% \iffalse %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% dljsLib.sty package, %% %% Copyright (C) 2001-2016 D. P. Story %% %% dpstory@uakron.edu %% %% %% %% This program can redistributed and/or modified under %% %% the terms of the LaTeX Projet Public License %% %% Distributed from CTAN archives in directory %% %% macros/latex/base/lppl.txt; either version 1 of the %% %% License, or (at your option) any later version. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{dljslib} % [2014/10/05 v2.0 Manage a Library of Document Level JavaScripts (dps)] %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,hyperindex=false]{hyperref} \pdfstringdefDisableCommands{\let\\\textbackslash}% %\OnlyDescription % comment out for implementation details \EnableCrossrefs \CodelineIndex \RecordChanges \InputIfFileExists{aebdocfmt.def}{\PackageInfo{dljslib}{Inputting aebdocfmt.def}} {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax \PackageInfo{dljslib}{aebdocfmt.def cannot be found}} \begin{document} \GetFileInfo{dljslib.sty} \title{The \texttt{dljsLib} Package} \author{D. P. Story\\ Email: \texttt{dpstory@uakron.edu}} \date{processed \today} \maketitle \tableofcontents \let\Email\texttt \DocInput{dljslib.dtx} \IfFileExists{\jobname.ind}{\newpage\setupFullwidth\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute \texttt{makeindex -s gind.ist -o dljslib.ind dljslib.idx} on the command line and recompile \texttt{dljslib.dtx}.} \IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute \texttt{makeindex -s gglo.ist -o dljslib.gls dljslib.glo} on the command line and recompile \texttt{dljslib.dtx}.} \end{document} % % \fi % % \InputIfFileExists{aebdonotindex.def}{\PackageInfo{dljslib}{Inputting aebdonotindex.def}} % {\PackageInfo{dljslib}{aebdonotindex.def cannot be found}} % % \changes{v1.3}{2005/08/27}{Added new user contributed routines for unordered, % interval, point and factored responses. Added a feature whereby you % can create a file called libcusopt.opt to declare your own options % for this package, but these should be a combination of existing % options.} % \changes{v2.0}{2014/10/05}{replaced app.alert with eqAppAlert} % %\section{Introduction} % This is a companion package to the \texttt{insdljs} package. \texttt{Insdljs} gives the % document author the ability to write document level JavaScripts to the PDF docuement, when % it is finally built. I personally will be writing a number of general routines to % handle situations that arise, and I would hope that other enthusiasts of \texttt{insdljs} will % do the same. Therefore, it is desirable to gather together some general purpose routines into % a single library, and have a way of selecting the desired function or functions to be used. % % This package is meant for document authors, not for package developers. This package can only be used % once per document, perhaps called from the preamble of a document. % %\section{The Library Procedures} % \begin{macrocode} %<*package> % \end{macrocode} % Define some convenience commands, \cs{dljsRegister} and \cs{DeclareAndRegister}, see comments that follow. % \begin{macrocode} \newcommand\dljsRegister[2][n] {\expandafter\let\csname checkout@#2\endcsname=#1} \def\@ifcheckedout#1{\expandafter\if\csname checkout@#1\endcsname y} \newcommand\DeclareAndRegister[1] {\DeclareOption{#1}{\dljsRegister[y]{#1}}\dljsRegister{#1}} % \end{macrocode} % Here we ``register'' the functions contained in the library. \cs{dljsRegister} defines a % control sequence that records the name of the function (actually, the option name). This % control is set to `n'. When a package user chooses a particular function for inclusion, the % control is set to `y'. % \begin{macrocode} \dljsRegister[y]{dljslib} % \end{macrocode} % \subsection{Library Card Catalog} % \IndexOpt{equations} % \IndexOpt{vectors} % \IndexOpt{indefIntegral} % \IndexOpt{ImplMulti} % \IndexOpt{nodec} % The arguments of the \cs{DeclareAndRegister} command are the options of this package, and % their names represent JavaScript functions in the library. % \begin{macrocode} \DeclareAndRegister{equations} \DeclareAndRegister{vectors} \DeclareAndRegister{indefIntegral} \DeclareAndRegister{ImplMulti} \DeclareAndRegister{nodec} % \end{macrocode} % \IndexOpt{noBinFac} % \IndexOpt{limitArith} % \IndexOpt{combinatorics} % \IndexOpt{setSupport} % More options. % \begin{macrocode} \DeclareAndRegister{noBinFac} \DeclareAndRegister{limitArith} \DeclareAndRegister{combinatorics} \DeclareAndRegister{setSupport} % \end{macrocode} % \IndexOpt{unordered} % \IndexOpt{complex} % \IndexOpt{satisfyEq} % \IndexOpt{useGermanNums} % \IndexOpt{factors} % More options still. % \begin{macrocode} \DeclareOption{unordered}{\PackageWarning{dljslib} {The `unordered' option is now combined with the\MessageBreak `setSupport' option, will use the `setSupport' option\MessageBreak instead}\ExecuteOptions{setSupport}} %\DeclareAndRegister{unordered} \DeclareAndRegister{complex} \DeclareAndRegister{satisfyEq} \DeclareAndRegister{useGermanNums} \DeclareAndRegister{factors} % \end{macrocode} % \IndexOpt{point} % \IndexOpt{intervals} % The final set of options. % \begin{macrocode} \DeclareAndRegister{point} \DeclareAndRegister{intervals} \def\includeOptions#1{\@for\@option:=#1\do{\dljsRegister[y]{\@option}}} \InputIfFileExists{libcusopt.opt}{}{} % \end{macrocode} % \begin{macrocode} \ProcessOptions % \end{macrocode} % \subsection{Requirements for a Library Card} % % In order to check a function out of this library, you must have % the \texttt{insdljs} Package. The \texttt{insdljs} package itself % has software requirements: (1) the \texttt{verbatim} and % \texttt{hyperref} packages; (2) One of the following, % \textsf{Distiller~5.0} or greater, \textsf{pdftex}, or % \textsf{dvipdfm}. % % \begin{macrocode} \RequirePackage{insdljs} % \end{macrocode} % After inputting \textsf{insdljs}, we define |\setdecimalpoint|, which populates % the text command |\aebdecimalpoint|. The text command |\aebdecimalpoint| is used in the \texttt{nodec} % option. % \begin{macrocode} \def\setdecimalpoint#1{\def\aebdecimalpoint{\eqbs#1}} \setdecimalpoint{.} % \end{macrocode} % % \subsection{Checkout Procedure} % % Functions can be checkout of the library by using the \texttt{dljslib} package % in the usual way. For example: %\begin{verbatim} %\documentclass{article} %\usepackage{amsmath} %\usepackage[pdftex,designi]{web} %\usepackage{exerquiz} %\usepackage[indefIntegral]{dljslib} % <- check out `indefIntegral' %\end{verbatim} % Here, we first use \texttt{exerquiz}, which has \texttt{insdljs} as a required package. % The use of this package is not limited to users of \texttt{exerquiz}, for example, we can % say %\begin{verbatim} %\documentclass{article} %\def\mydriver{dvipdfm} %\usepackage[\mydriver]{color} %\usepackage[\mydriver,colorlinks,pdfpagemode=None]{hyperref} %\usepackage[\mydriver]{insdljs} %\usepackage[indefIntegral]{dljslib} % <- check out `indefIntegral' %\end{verbatim} % However, at the time of the release of v1.0 of this package, the only functions in this % library are ones used by \texttt{exerquiz}. % % \subsection{Exiting the Library with your Checkouts} % % This package has an output stream, \cs{dljslib@verbatim@out}, % that is used to write all the functions that are to be included. % We use a control sequence \cs{js@verbatim@out} defined in % \texttt{insdljs}. We also use a verbatim write from % \texttt{insdljs} as well, the \cs{js@verbatimwrite} environment. % \cs{js@verbatimwrite} writes to the output stream pointed to % \cs{js@verbatim@out}. % \begin{macrocode} \newwrite\dljslib@verbatim@out % \end{macrocode} % This package generates only one auxiliary file, % \texttt{dljslib.ljs}, which can be deleted after the document is % latexed. The file \texttt{dljslib.ljs} (\texttt{ljs} means % ``library javascripts'') and contains the functions that are % specified in the package options. At the end of this package, % the file \texttt{dljslib.ljs} is input back into the calling % document where the package \texttt{insdljs} takes over. % \begin{macrocode} \immediate\openout\dljslib@verbatim@out=dljslib.ljs % \end{macrocode} % \subsection{The Catalog and Checkout Mechanism} % \begin{macro}{library@holding} % This is a simple environment, it reads its parameter, and if that option was specified by the % user, it writes the function verbatim to the \texttt{dljslib.ljs}, otherwise, it comments out % that function using the \texttt{comment} environment from the \texttt{verbatim} package. % This environment uses, \texttt{js@verbatimwrite}, an environment % defined in the \texttt{insdljs} package. % \begin{macrocode} \newenvironment{library@holding}[1] {% \expandafter\ifx\csname checkout@#1\endcsname y% \let\js@verbatim@out\dljslib@verbatim@out \let\dljs@verbatim\js@verbatimwrite \let\enddljs@verbatim\endjs@verbatimwrite\else \let\dljs@verbatim\comment \let\enddljs@verbatim\endcomment\fi\dljs@verbatim }{\enddljs@verbatim} % \end{macrocode} % \end{macro} %\section{The DLJS Library} % We finally reach the ``stacks'', the location of the actual library holdings. % % \medskip\noindent This item must always accompany the collection of functions that are to be % checked out. This is the beginning of the \texttt{insDLJS} environment. To continue this library analogy, % this of this as the ``front wrapper'' or ``front cover'' of your library selections. It contains the % ``name'' of the library from which you checked out your selections. % \begin{macrocode} \begin{library@holding}{dljslib} \begin{insDLJS*}[dljslib]{dljslib} \begin{newsegment}{dljslib: AcroTeX DLJS Library} /* The Document Level JavaScript Library D. P. Story copyright 2001-\the\year */ var dljslib = true; \end{newsegment} \end{library@holding} % \end{macrocode} %\subsection{The Stacks} % Now we reach of the beginning of the stacks. There are several sections of the library, currently, % \nameref{s:respfunctions} and \nameref{s:compfunctions}. % % \subsection{Response Functions}\label{s:respfunctions} % % \textbf{Used by Exerquiz.} In this section we catalog response functions. A response function is the one that % \cs{RespBoxMath} calls to process the user's response to a math fill-in question. See the sample file % \texttt{jqzspec.tex} for a detailed explanation of this type of function. % % \subsubsection{\texttt{equations}}\label{equations} % \IndexOpt{equations} % These routines process questions for which an equation is the expected answer. % \begin{macrocode} \@ifcheckedout{equations} \newcommand\equationsAlertMsg{"An equation is expected"} \fi \begin{library@holding}{equations} \begin{newsegment}{dljslib: Equation Handling} function ProcRespEq(flag,CorrAns,n,epsilon,domain,indepVar,oComp) { if (!ProcessIt) return null; ok2Continue = true; var success; var fieldname = event.target.name; var UserAns = event.value; % \end{macrocode} % \begin{macrocode} var CorrExpressions = CorrAns.split("="); var zCorrAns = "("+CorrExpressions[0]+")-("+CorrExpressions[1] +")"; UserAns = stripWhiteSpace (UserAns); if(!ok2Continue ) return null; if (!/[=]/.test(UserAns)) { eqAppAlert(\equationsAlertMsg, 3); return null; } % \end{macrocode} % Check for commas, not permitted here. (2012/05/25) % \begin{macrocode} var reComma=/,/; if ( reComma.test(UserAns) ) { eqAppAlert(\eqSyntaxErrorComma,3); return null; } % \end{macrocode} % \begin{macrocode} var UserExpressions = UserAns.split("="); var zUserAns = "("+UserExpressions[0]+")-("+UserExpressions[1] +")"; % \end{macrocode} % If \texttt{oComp} is an object, then see if it has a \texttt{comp} property % \begin{macrocode} var comp = ( typeof oComp == "object" ) ? (typeof oComp.comp == "undefined" ) ? diffCompare : oComp.comp : oComp; % \end{macrocode} % The \texttt{comp} parameter, which has been changed to \texttt{oComp} can now be % an object. One property of this object is \texttt{comp}, handled above. Another % property is \texttt{priorParse}, this is a function that returns \texttt{null} % or \texttt{true}. This \texttt{priorParse} function allows for additional % filtering of the \texttt{zUserAns} before parsing. If it returns \texttt{true}, % we are ok to continue, if \texttt{null}, we don't like something the user has entered, % and ask him/her to change it. % \begin{macrocode} if ( typeof oComp == "object" && typeof oComp.priorParse != "undefined" ) { % \end{macrocode} % Let's go ahead and allow \texttt{oComp.priorParse} be an array of functions. % \begin{macrocode} if ( typeof oComp.priorParse == "object" ) { for ( var i=0; i < oComp.priorParse.length; i++) { var retn = oComp.priorParse[i](zUserAns); if ( retn == null ) return null; } } else { var retn = oComp.priorParse(zUserAns); if ( retn == null ) return null; } } zCorrAns = ParseInput(zCorrAns); if (!ok2Continue) { eqAppAlert("Syntax error in author's answer! Check console.", 3); console.println("Syntax Error: " + CorrAns); return null; } zUserAns = ParseInput(zUserAns); if (!ok2Continue) return null; % convert vars to new format, if needed indepVar = TypeParameters(indepVar); var lambda = getNonZeroRatio (domain, indepVar, zCorrAns, zUserAns); if ( lambda == null ) { eqAppAlert(\eqSyntaxErrorUndefVar,3); return null; }; if ( !ok2Continue ) return notifyField(false, flag, fieldname); zCorrAns = lambda + "*(" + zCorrAns + ")"; success=randomPointCompare (n,domain,indepVar,epsilon, zCorrAns,zUserAns,comp) if ( success == null ) { eqAppAlert(\eqSyntaxErrorUndefVar,3); return null; } return notifyField(success, flag, fieldname); } function getNonZeroRatio (_a, _v, _F, _G) { var _i, _j; var aXY = new Array(); _a = _a.replace(/[\[\]\s]/g, ""); var _V = _v.split(","); // e.g. _V[0] = "i:x" var _n = _V.length; var aIntervals = _a.split("&"); var aInterval = aIntervals[0].split("x"); var endpoints = aInterval[0].split(","); for (_j=0; _j < 4; _j++) { for (_i = 0; _i < _n; _i++) { var endpoints = aInterval[_i].split(","); aXY[_i] = endpoints[0]-0 +(endpoints[1]-endpoints[0])*Math.random(); \db console.println("aXY["+_i+"] = " + aXY[_i]);\db% } for (var _i = 0; _i< _n; _i++) { if (_V[_i].charAt(0) == "r" ) eval ( "var "+ _V[_i].charAt(2) + " = " + aXY[_i] + ";"); else // assume type "i" eval ( "var "+ _V[_i].charAt(2) + " = " + Math.ceil(aXY[_i]) + ";"); } _F = eval(_F); if ( app.viewerVersion >= 5) { var rtnCode = 0; eval("try { if(isNaN(_G = eval(_G))) rtnCode=-1; }" +"catch (e) { rtnCode=1; }"); switch(rtnCode) { case 0: break; case 1: return null; case -1: ok2Continue=false; return -1; } } else if(isNaN(_G=eval(_G))) {ok2Continue=false;return -1;} if ( _F != 0 && _G != 0 ) return _G/_F; } console.println( "Can't find a non zero scalar"); return null; } \end{newsegment} \end{library@holding} % \end{macrocode} % % \subsubsection{\texttt{vectors}}\label{vectors} % % \IndexOpt{vectors} % This function attempts to process questions that have vectors % as answers. Note the name of the function is \texttt{ProcVec}, this is the name used to call it. %\begin{verbatim} %$\vec a + \vec b = \RespBoxMath{<4, 4, 4>}{1}{.0001}{[2,4]}*{ProcVec}$ %\end{verbatim} %See also the file \texttt{jqzspec.tex} for more details. % \begin{macrocode} \@ifcheckedout{vectors} \newcommand\vectorsErrorMsgi{"I'm looking for a vector. You need to use proper vector notation, try using angle brackets <....>."} \newcommand\vectorsErrorMsgii{"Angle brackets are not balanced. Check the expression you typed in."} \newcommand\vectorsErrorMsgiii{"Incorrect number of components. The answer requires " + aCorrAns.length+" components."} \def\vectorEmptyCompMsgiv(#1){"You entered nothing for the component " +(#1+1) +" of your answer. Please enter a component for the vector."} \fi \begin{library@holding}{vectors} \begin{newsegment}{dljslib: Vector Handling} function ProcVec (flag,CorrAns,n,epsilon,domain,indepVar,oComp) { % \end{macrocode} % This function attempts to process questions that have vectors % as answers. % \begin{macrocode} if (!ProcessIt) return null; ok2Continue = true; var i, success, truthCnt=1; var aScalar, scalar = 1; var fieldname = event.target.name; var UserAns = event.value; UserAns = stripWhiteSpace(UserAns); // sets ok2Continue CorrAns = stripWhiteSpace(CorrAns); if ( !ok2Continue ) return null; var isSpecResp=false; for ( var i=0; i]/.test(UserAns)) { eqAppAlert(\vectorsErrorMsgi, 3); return null; } if (!CkBalP(UserAns,"<",">")) { eqAppAlert(\vectorsErrorMsgii, 3); return null; } // see if there is a scalar multiple to the left of '<' aScalar = UserAns.match(/(.*)(\*)(\s*<)/); if (aScalar != null) { scalar = aScalar[1]; UserAns = UserAns.slice(aScalar.index + aScalar[0].length-1) } % \end{macrocode} % If \texttt{oComp} is an object, then see if it has a \texttt{comp} property % \begin{macrocode} var comp = ( typeof oComp == "object" ) ? (typeof oComp.comp == "undefined" ) ? diffCompare : oComp.comp : oComp; % \end{macrocode} % \begin{macrocode} CorrAns = CorrAns.replace(/[<>]/g, ""); // strip of < and > UserAns = UserAns.replace(/[<>]/g, ""); % \end{macrocode} % The \texttt{comp} parameter, which has been changed to \texttt{oComp} can now be % an object. One property of this object is \texttt{comp}, handled above. Another % property is \texttt{priorParse}, this is a function that returns \texttt{null} % or \texttt{true}. This \texttt{priorParse} function allows for additional % filtering of the \texttt{UserAns} before parsing. If it returns \texttt{true}, % we are ok to continue, if \texttt{null}, we don't like something the user has entered, % and ask him/her to change it. % \begin{macrocode} if ( typeof oComp == "object" && % typeof oComp.priorParse != "undefined" ) { var retn=processSpecialParse(oComp.priorParse,UserAns); if (retn==null) return null; } % \end{macrocode} % Not convert each to an array % \begin{macrocode} aUserAns = UserAns.split(","); aCorrAns = CorrAns.split(","); if (scalar != 1) for (i=0; i)."} \fi \begin{library@holding}{setSupport} \begin{newsegment}{dljslib: Support for Sets} % \end{macrocode} % This function can handle (math fill-in) questions whose answers are a set of numbers or a % comma delimited list of numbers. %\begin{flushleft} % Sample usage: %\begin{verbatim} % $(x+1)(2x-1)(x-2)^3 = 0$, $x = \RespBoxMath[\rectW{.75in}\textSize{0}] % {-1, 1/2, 2, 2, 2}{1}{.0001}{[0,1]}*{ProcRespSetNum}$ %\end{verbatim} %\end{flushleft} % \begin{macrocode} function ProcRespSetNum(flag,CorrAns,n,epsilon,domain,indepVar,oComp) { ok2Continue = true; if (!ProcessIt) return null; var fieldname = event.target.name; var UserAns = event.value; UserAns = stripWhiteSpace(UserAns); CorrAns = stripWhiteSpace(CorrAns); if (!ok2Continue) return null; var isSpecResp=false; for ( var i=0; i$/.test(UserAns) ) { ok2format=false; return eqAppAlert(\noBracketsInAnsMsg,3), null; } else return true; } function formatAsVector() { if (ok2format&&event.value.replace(/\\s/g,"") != "") { event.value = "< " + event.value + " >"; } } % \end{macrocode} % Input an order pair of numbers, determine if it satisfies an equation. This problem % type is new as there are ``infinitely many answers.'' If we pose the question % ``Enter a point that lies on the line $2x+3y=6$.'' The user enters an ordered pair % of numbers. The CorrAns that is passed is $2x+3y-6$, and we test the user's input % to see if the expression evaluates to zero. % % \begin{macrocode} % \end{macrocode} % This function can handle simple symbolic answers. The variable list, \texttt{inderVar}, should % be the ``universal set'' of the problem. % \begin{flushleft} % Sample usage: %\begin{verbatim} % \def\U{a,b,c,d,e,f,g} % define a universal set % $A \cap B = \RespBoxMath[\AddAAFormat{\formatAsSet} % \rectW{.75in}\textSize{0} % ]{c,d}(\U){1}{.0001}{[0,1]}*{ProcRespSetSym}$ %\end{verbatim} % \end{flushleft} % \begin{macrocode} function ProcRespSetSym(flag,CorrAns,n,epsilon,domain,indepVar,oComp) { ok2Continue = true; if (!ProcessIt) return null; var fieldname = event.target.name; var UserAns = event.value; UserAns = stripWhiteSpace(UserAns); CorrAns = stripWhiteSpace(CorrAns); if (!ok2Continue) return null; var isSpecResp=false; for ( var i=0; i)} and % replace with \texttt{cis(,i)}. I hope this works. % \begin{macrocode} UserAns=changeArgs4Cis(UserAns); % \end{macrocode} % ...and do the same thing for the correct answer. % \begin{macrocode} CorrAns=changeArgs4Cis(CorrAns); % \end{macrocode} % The complex option is not meant to be an option to do complex arithmetic, but only % to accept a complex number as an answer. So, we do not accept an answer with two % or more i's in it. % \begin{macrocode} var aMatch = UserAns.match(/(\b|[^a-zA-Z])i/g); if ( aMatch != null && aMatch.length > 1) { eqAppAlert(\alertNotComplexMsg, 3); return null; } var comp = ( typeof oComp == "object" ) ? (typeof oComp.comp == "undefined" ) ? diffCompare : oComp.comp : oComp; if ( typeof oComp == "object" && typeof oComp.priorParse != "undefined" ) { if ( typeof oComp.priorParse == "object" ) { for ( var i=0; i < oComp.priorParse.length; i++) { var retn = oComp.priorParse[i](UserAns); if ( retn == null ) return null; } } else { var retn = oComp.priorParse(UserAns); if ( retn == null ) return null; } } % \begin{macrocode} UserAns = ParseInput(UserAns); CorrAns = ParseInput(CorrAns); indepVar = TypeParameters(indepVar); if (!ok2Continue) return null; success=randomPointCompare( n,domain,indepVar,epsilon,CorrAns,UserAns,comp); if ( success == null ) { eqAppAlert(% \eqSyntaxErrorUndefVar,3); return null; } return notifyField(success, flag, fieldname); } % \end{macrocode} % \texttt{ProcRespListComplex}, contributed by Bruce Wagner, extends % \texttt{ProcRespComplex} to lists; an ordered listing of complex responses. % Sample syntax: %\begin{verbatim} %If $z=4(\cos x+i\sin x)$, compute $z^2$ and $z^3$, in that order. %\RespBoxMath{16*cis(2x),64*cis(3x)}{4}{0.0001}{[0,1]}*{ProcRespListComplex} %\end{verbatim} % \begin{macrocode} function ProcRespListComplex(flag,CorrAns,n,epsilon,% domain,indepVar,oComp) { ok2Continue = true; if (!ProcessIt) return null; var fieldname = event.target.name; var UserAns = event.value; UserAns = stripWhiteSpace(UserAns); CorrAns = stripWhiteSpace(CorrAns); // sets ok2Continue if ( !ok2Continue ) return null; var isSpecResp=false; for ( var i=0; i aUserAns.length ) return eqAppAlert(\eqTooFewEntries,3), null; var _v = TypeParameters(indepVar); var _V = _v.split(","); // e.g. _V[0] = "i:x" % \end{macrocode} % \texttt{\_n} is the number of variables % \begin{macrocode} var _n = _V.length; % \end{macrocode} % \texttt{testFunc} is a random linear function of the form % \texttt{ax+by+...}, where \texttt{a} and \texttt{b} are selected at random. % \begin{macrocode} var testFunc=""; for (var _i=0; _i < _n; _i++) testFunc += ("+"+(Math.random()*9)+"*"+_V[_i].charAt(2)); % \end{macrocode} %\changes{v1.9d}{2012/05/13}{Introduced \texttt{iCorrect} variable} % Introduced \texttt{iCorrect} variable to correct check each of the % user's pairs of responses. % \begin{macrocode} var isCorrect=1; for (var pair=0; pair< l; pair++) { % \end{macrocode} % We require each ordered pair to be enclosed in parentheses % \begin{macrocode} if ( (aUserAns[pair].charAt(0) != "\(") || % (aUserAns[pair].charAt(aUserAns[pair].length-1) != "\)")) return eqAppAlert(\eqSyntaxErrorNoParens,3), null; % \end{macrocode} % Strip away the parentheses, so for example, \texttt{UserAnsPair="3,5"} % \begin{macrocode} UserAnsPair=aUserAns[pair].substring(1,aUserAns[pair].length-1); % \end{macrocode} % \texttt{aUserAnsPair} an the array that contains the components of % \texttt{aUserAns[pair]} % \begin{macrocode} var aUserAnsPair = UserAnsPair.split(","); % \end{macrocode} % See if each component is a number % \begin{macrocode} for ( var i=0; i < aUserAnsPair.length; i++) { try { if (isNaN(eval(aUserAnsPair[i]))) % return syntaxError(), null; % \end{macrocode} %\changes{v1.9d}{2012/05/13}{Corrected reference, changed %\texttt{aUserAns} to \texttt{aUserAnsPair}} % \texttt{(2012/05/13)} Corrected reference, changed \texttt{aUserAns} to \texttt{aUserAnsPair} % \begin{macrocode} if (!allowzero && (eval(aUserAnsPair[i])==0)) return eqAppAlert(\eqNonzeroEntries,3), null; } catch(e) { return syntaxError(), null; } } % \end{macrocode} % If the number of components does not match the number of variables, this is an % error. Give the user a chance to correct it. % \begin{macrocode} if ( aUserAnsPair.length != _n) { if (bNotifyWrngNumEntries) return eqAppAlert(\wrongNumEntriesMsg,3), null; else return notifyField(false, flag, fieldname); } % \end{macrocode} % Evaluate each component of the user's answer. % \begin{macrocode} for (var _i=0; _i < _n; _i++) { if (_V[_i].charAt(0) == "r" ) eval ("var "+_V[_i].charAt(2)+"="+aUserAnsPair[_i]+";"); else // assume type "i" eval ("var "+_V[_i].charAt(2)+"="% +Math.ceil(aUserAnsPair[_i])+";"); } % \end{macrocode} % \texttt{UserInput} is misnamed, this is the answer the author provides, % for example, \texttt{2x+3y-6}. We parse it, then evaluate it (using the values % of the variables computed above. % \begin{macrocode} var UserInput=ParseInput(aCorrAns[1]); var UserAns=eval(UserInput); % \end{macrocode} % We also evaluate the test function \texttt{testFunc} for the values of the % variables computed above. We store the result in \texttt{aUsersArray}. % \begin{macrocode} aUsersArray[pair]=eval(testFunc); % \end{macrocode} % If less than \texttt{epsilon}, we set \texttt{success} to \texttt{true}, % or we return \texttt{false} % \begin{macrocode} success=(Math.abs(UserAns) < epsilon)?true:false; % \end{macrocode} % If \texttt{success} is true, we multiply by 1, else we multiply by 0 % \begin{macrocode} isCorrect *=Number(success); } % \end{macrocode} % If \texttt{isCorrect} is \texttt{1}, all comparisons were successful. % \begin{macrocode} success=(isCorrect==1); % \end{macrocode} % Sort \texttt{aUsersArray} from least to greatest % \begin{macrocode} var aOrderArray = aUsersArray.sort(function(a,b){return a-b}); var m = aUsersArray.length - 1; % \end{macrocode} % See if any two consecutive entries differ by a little, if not, we'll % say the two answers are the same and ask the user for distinct entries. % \begin{macrocode} for (i=0; i= 5) { var rtnCode = 0; eval("try {if (isNaN(eqC = eval(_F)-eval(_G))) rtnCode=-1;}" +" catch (e) { rtnCode=1; }"); switch(rtnCode) { case 0: break; case 1: return null; case -1: return -1; } } else if (isNaN(eqC = eval(_F)-eval(_G))) return -1; for (var _i=0; _i< _n; _i++) { if (_V[_i].charAt(0) == "r" ) eval ( "var "+ _V[_i].charAt(2) + " = " + aXY[_i] + ";"); else // assume type "i" eval ( "var "+ _V[_i].charAt(2) + " = " + Math.ceil(aXY[_i]) + ";"); } _F = eval(_F); if ( app.viewerVersion >= 5) { var rtnCode = 0; eval("try { if(isNaN(_G = eval(_G))) rtnCode=-1; }" +" catch (e) { rtnCode=1; }"); switch(rtnCode) { case 0: break; case 1: return null; case -1: return -1; } } else if(isNaN(_G = eval(_G))) return -1; return Math.abs( _F - _G - eqC ); } \end{newsegment} \end{library@holding} % \end{macrocode} % % \subsection{Filter User's Responses} % The following two function were contributed by Ross Moore and Frances % Griffin, and were taken from their % \href{http://rutherglen.ics.mq.edu.au/~macqtex/}{MacQ\TeX} online testing % system. See the sample file \texttt{integer\_tst.tex} for sample usage. % These two functions take \texttt{UserAns} as a parameter and return % \texttt{null} or \texttt{true} to signal the user expression is not an % acceptable response, or that it's ok for processing, respectively. % \begin{macrocode} \@ifcheckedout{nodec} \newcommand\nodecAlertMsg{% "A decimal answer is not acceptable here. Please express your answer using fractions, square roots, e, log, etc."} \fi \begin{library@holding}{nodec} % \end{macrocode} % \subsubsection{\texttt{nodec}} % \IndexOpt{nodec}Do not allow the use of decimal numbers. (Just searches of ``.''.) % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - No Decimals} function nodec(UserAns) { var dot = /[\.\aebdecimalpoint]/; if (dot.test(UserAns)) { eqAppAlert(\nodecAlertMsg,3); return null; } else return true; } \end{newsegment} % \end{macrocode} % \begin{macrocode} \end{library@holding} \@ifcheckedout{noBinFac} \newcommand\noBinFactBinCoeffAlertMsg{% "You may not use this notation here. Please evaluate the binomial coefficient. You may present your answer as a product rather than calculating a very large number."} \newcommand\noBinFactPermAlertMsg{% "You may not use this notation here. Please evaluate the permutation. You may present your answer as a product rather than calculating a very large number."} \newcommand\noBinFactFactAlertMsg{% "You may not use this notation here. Please evaluate the factorial. You may present your answer as a product rather than calculating a very large number."} \fi \begin{library@holding}{noBinFac} % \end{macrocode} % \subsubsection{\texttt{noBinFac}} % \IndexOpt{noBinFac}Disallow binomial coefficients and factorials in math fill-ins. % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - No Binomial Coefficients Allowed} aReFact = new Array( /(?=\()?(\d+)(?=\))?!/, /(?=\[)?(\d+)(?=\])?!/, /(?=\{)?(\d+)(?=\})?!/ ); function noBinFac(UserAns) { var bad = /(C\()/; if (bad.test(UserAns)) { eqAppAlert(\noBinFactBinCoeffAlertMsg,3); return null; } bad = /(P\()/; if (bad.test(UserAns)) { eqAppAlert(\noBinFactPermAlertMsg,3); return null; } for ( var i=0; i= 10 ) { if (bAllowWrngNormSciNotn) return true; else return eqAppAlert(\sciNotNormalForm,3), null; } else { bItsNormSciNot=true; return true } } else return eqAppAlert(\sciNotSyntaxError,3), null; } function sciNotResp(UserAns) {return SciNotResp(UserAns);} function postSciNotResp(UserAns) { bAllowWrngNormSciNotn=false; return bItsNormSciNot; } % \end{macrocode} %\changes{v1.9a}{2011/07/15}{Added \texttt{noNegExp}} % \texttt{noNegExp} does not allow negative exponents in the answer % \begin{macrocode} function NoNegExp (UserAns) { var re=/(\^|\^\()+-/g; UserAns=ChngAllGrpsToParens(UserAns); if (re.test(UserAns)) return eqAppAlert(\NoNegExpMsg,3), null; return true; } function noNegExp(UserAns){return NoNegExp(UserAns)} \end{newsegment} \end{library@holding} % \end{macrocode} % \subsection{Additional mathematical functions} % The following are contributions by Ross Moore and Frances Griffin, from their work % on \href{http://rutherglen.ics.mq.edu.au/~macqtex/}{MacQ\TeX}. % These define function of an integer variable: combinations, permutations and factorials. % These can be used for math fill-ins. % \begin{macrocode} \begin{library@holding}{combinatorics} % \end{macrocode} % \subsubsection{\texttt{combinatorics}} % Combinatorial function\IndexOpt{combinatorics} % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - Combinatorial Functions} function ch(n,r) { if ((n==r)||(r==0)) return(1); if ((n==(r+1))||(r==1)) return(n); if (r > (n-r)) var coeff = factorialCancel( expandFactorial(r+1,n),expandFactorial(1,n-r)); else var coeff = factorialCancel( expandFactorial(n-r+1,n),expandFactorial(1,r)); return (eval(coeff)); } function perm(n,r) { if (r==0) return(1); else var coeff = factorialCancel( expandFactorial(n-r+1,n),expandFactorial(1,n-r)); return (eval(coeff)); } % \end{macrocode} % \texttt{factorialCancel} and \texttt{expandFactorial} are needed by \texttt{binomialCoeff} % \begin{macrocode} function expandFactorial(lo,hi) { var f = lo; for (var i=lo+1;i<=hi;i++) f = i+"*"+f; return f; } % \end{macrocode} % \texttt{factorialCancel} cancels common factors in \texttt{num} and \texttt{denom} using strings produced % by \texttt{expandFactorial}. It expects tails of factorials to have already been cancelled. % \begin{macrocode} function factorialCancel(top,bot) { var num = top.split("*"); var denom = bot.split("*"); var len = denom.length; var temp = 0; var i, j; for (i=0;i<=len-1;i++) { for (j=0;j<=len-1;j++) { temp = num[i]/denom[j]; if ((temp - Math.round(temp)) == 0) { num[i] = temp; denom[j] = 1; } } } var t = denom.join(""); var reg = /[^1]/; if (reg.test(t)) { temp = factorialCancel(denom.join("*"),num.join("*")); } else { temp = num.join("*"); } return (temp); } function fact(num) { var tot = 1; for (var r=1; r <= num; r++) tot *= r; return(tot); } \end{newsegment} \end{library@holding} % \end{macrocode} % \subsection{\texttt{ParseInput} Extensions}\label{s:parseinput} % The default behavior for processing a math fill-in question is to % require the student to insert `\texttt*' for multiplication and to % enclose any function being raised to a power in parentheses, e.g. % \verb+x*(sin(x))^2+. This becomes quite tiresome if the expression to be entered % is complicated. The following two functions enable the student to use % `implied multiplication' and simplified exponentiation. % % \IndexOpt{ImplMulti} % The \texttt{ImplMulti} option loads two JavaScript functions, \texttt{Ck4Products()} % and \texttt{Ck4Exponents()}. The latter implements the notation, \verb+sin^2(x)+ % for $\sin^2(x)$, equivalent to $(\sin(x))^2$. The exponent can be complex and enclosed % in parentheses, for example \verb-ln^(x+1)(x)-. The former function, \texttt{Ck4Products()}, % inserts the multiplication symbol, `\texttt{*}', wherever implied. For example, % \verb+xysin(xy)+ becomes \verb+x*y*sin(x*y)+. % \begin{flushleft} % \textcolor{red}{Important:} If loaded, \texttt{Exerquiz} will automatically use these two functions. % \end{flushleft} % \begin{macrocode} \begin{library@holding}{ImplMulti} % \end{macrocode} % \subsubsection{\texttt{ImplMulti}} % \begin{macrocode} \begin{newsegment}{dljslib: Implied Multiplication} % \end{macrocode} % The JavaScript function \texttt{Ck4Products()} takes the user input and tries to % insert the multiplication symbol, `\texttt*', wherever implied. % \begin{macrocode} function Ck4Products(UserInput) { var re, aR; % \end{macrocode} % Search through for matches with known functions % \begin{macrocode} for (var i=0; i % \end{macrocode} \endinput