% \iffalse %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% dljsLib.sty package, 2002-2-9 %% %% Copyright (C) 2001-2002 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} % [2007/02/05 v1.6 Manage a Library of Document Level JavaScripts (dps)] %<*driver> \documentclass{ltxdoc} \usepackage[dviwindo,colorlinks,hyperindex]{hyperref} \pdfstringdefDisableCommands{\let\\\textbackslash}% \EnableCrossrefs \CodelineIndex \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} \PrintIndex \end{document} % % \fi % \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.} % %\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} \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} % 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} \DeclareAndRegister{noBinFac} \DeclareAndRegister{limitArith} \DeclareAndRegister{combinatorics} \DeclareAndRegister{setSupport} \DeclareAndRegister{unordered} \DeclareAndRegister{factors} \DeclareAndRegister{point} \DeclareAndRegister{intervals} \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 fillowing, % \textsf{Distiller~5.0} or greater, \textsf{pdftex}, or % \textsf{dvipdfm}. % % \begin{macrocode} \RequirePackage{insdljs} % \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 finaly 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} % \begin{macro}{equations} % These routines process questions for which an equation is the expected answer. % \begin{macrocode} \begin{library@holding}{equations} \begin{newsegment}{dljslib: Equation Handling} function ProcRespEq(flag,CorrAns,n,epsilon,a,indepVar,oComp) { if (!ProcessIt) return null; ok2Continue = true; var success; var fieldname = event.target.name; var UserAns = event.value; % \end{macrocode} % Implement an "undefined" answer. Due to Ross-Griffin % \begin{macrocode} % if (UserAns == "undefined") { % success = (CorrAns == UserAns); % return notifyField(success, flag, fieldname); % } %- var Expressions = CorrAns.split("="); %- var zCorrAns = "("+Expressions[0]+")-("+Expressions[1] +")"; %- Expressions = UserAns.split("="); %- if (Expressions.length != 2) %- { var CorrExpressions = CorrAns.split("="); var zCorrAns = "("+CorrExpressions[0]+")-("+CorrExpressions[1] +")"; UserAns = stripWhiteSpace (UserAns); if(!ok2Continue ) return null; if (!/[=]/.test(UserAns)) { app.alert("An equation is expected", 3); return null; } %- var zUserAns = "("+Expressions[0]+")-("+Expressions[1] +")"; 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) { app.alert("Syntax error in author's answer! Check console.", 3); console.println("Syntax Error: " + CorrAns); return null; } zUserAns = ParseInput(zUserAns); if (!ok2Continue) return null; indepVar = TypeParameters(indepVar); // convert vars to new format, if needed var lambda = getNonZeroRatio (a, indepVar, zCorrAns, zUserAns); if ( lambda == null ) { app.alert(\eqSyntaxErrorUndefVar,3); return null; }; if ( !ok2Continue ) return notifyField(false, flag, fieldname); zCorrAns = lambda + "*(" + zCorrAns + ")"; \db console.println("zCorrAns = " + zCorrAns);\db% success=randomPointCompare (n,a,indepVar,epsilon,zCorrAns,zUserAns,comp) \db console.println("success = " + success );\db% if ( success == null ) { app.alert(\eqSyntaxErrorUndefVar,3); return null; } return notifyField(success, flag, fieldname); } function getNonZeroRatio (_a, _v, _F, _G) { var _i, _j; var aXY = new Array(); % var nV = _v.length; _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(","); % with (Math) % { 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])*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) + " = " + ceil(aXY[_i]) + ";"); % eval ( "var "+_v[_i] + " = " + 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} % \end{macro} % \subsubsection{\texttt{vectors}}\label{vectors} % \begin{macro}{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} \begin{library@holding}{vectors} \begin{newsegment}{dljslib: Vector Handling} function ProcVec (flag,CorrAns,n,epsilon,a,indepVar,oComp) { % This function attempts to process questions that have vectors % as answers. if (!ProcessIt) return null; ok2Continue = true; %- var i, success, truthCnt=0; var i, success, truthCnt=1; var aScalar, scalar = 1; var fieldname = event.target.name; var UserAns = event.value; % \end{macrocode} % Implement an "undefined" answer. Due to Ross-Griffin % \begin{macrocode} if (UserAns == "undefined") { success = (CorrAns == UserAns); return notifyField(success, flag, fieldname); } CorrAns = stripWhiteSpace (CorrAns); UserAns = stripWhiteSpace (UserAns); // sets ok2Continue if ( !ok2Continue ) return null; if (!/[<>]/.test(UserAns)) { app.alert("I'm looking for a vector. You need to use proper vector notation.", 3); return null; } if (!CkBalP(UserAns,"<",">")) { app.alert("Angle brackets are not balanced.", 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" ) { % \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](UserAns); if ( retn == null ) return null; } } else { var retn = 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= 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) + " = " + ceil(aXY[_i]) + ";"); } % eval ( "var "+_v[i] + " = " + 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 ); % } dps/change 02/23/07 } \end{newsegment} \end{library@holding} % \end{macrocode} % \end{macro} % \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} \begin{library@holding}{nodec} % \end{macrocode} % \subsubsection{\texttt{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 = /\./; if (dot.test(UserAns)) { app.alert("A decimal answer is not acceptable here." + " Please express your answer using fractions, square roots, " + "e, log, etc."); return null; } else return true; } \end{newsegment} \end{library@holding} \begin{library@holding}{noBinFac} % \end{macrocode} % \subsubsection{\texttt{noBinFac}} % Disallow binomial coefficients and factorials in math fill-ins. % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - No Binomial Coefficients Allowed} function noBinFac(UserAns) { var bad = /(C\()/; if (bad.test(UserAns)) { app.alert("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.",3); return null; } var bad = /(P\()/; if (bad.test(UserAns)) { app.alert("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.",3); return null; } bad = /(fact)/; if (bad.test(UserAns)) { app.alert("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.",3); return null; } return true } \end{newsegment} \end{library@holding} % \end{macrocode} % \begin{macrocode} \begin{library@holding}{limitArith} % \end{macrocode} % \subsubsection{\texttt{Limit Arithmetic Operations \& Built-in Functions}} % A collection of functions to limit the use of the arithmetic operations and to limit % the use of the trig functions. These functions are called through an optional parameter % of \cs{RespBoxMath}, as illustrated below and in the demo document \texttt{limarith.tex}. % \begin{macrocode} \begin{newsegment}{dljslib: Limit Arithmetic and Built in Functions} % \end{macrocode} % The \texttt{DecimalsOnly} is a function that takes only numbers, either integer or decimal. % Usage %\begin{verbatim} % $ 2.3 + 4.5 = \RespBoxMath[\rectW{.75in}\textSize{0}]{6.8}{1}{.0001}{[0,1]} % [{priorParse: DecimalsOnly }]\CorrAnsButton{6.8}$ %\end{verbatim} % \begin{macrocode} function DecimalsOnly(UserAns) { var errorStr = "Enter only an integer, e.g., 17, or a decimal number, e.g. 12.4. " + "Using arithmetic operations or built in function is not acceptable for this problem." UserAns = stripWhiteSpace(UserAns); if ( !ok2Continue ) return null; if( !isFinite( UserAns ) ) { app.alert(errorStr); return null; } return true; } % \end{macrocode} % The function \texttt{NoProducts} requires that \texttt{ImplMulti} be taken. % An example of usage is %\begin{verbatim} %$ 3/4 = \RespBoxMath[\rectW{.75in}\textSize{0}]{.75}{1}{.0001}{[0,1]} % [{priorParse: new Array(NoDivision, NoProducts) }]\CorrAnsButton{.75}$ %\end{verbatim} % In the above example, we first call \texttt{NoDivision} then \texttt{NoProducts}. This is % the way you can chain these filtering functions together. % \begin{macrocode} function NoProducts (UserAns) { // Requires the ImplMulti option of dljslib UserAns = stripWhiteSpace(UserAns); if ( !ok2Continue ) return null; UserAns = Ck4Products(UserAns); if ( /\*/.test( UserAns ) ) { app.alert( "Multiplication is not allowed for this problem."); return null; } return true; } function NoDivision (UserAns) { if ( /\//.test( UserAns) ) { app.alert( "Division is not allowed for this problem."); return null; } return true; } % \end{macrocode} % This function, as the name implies, denies the use of both addition and subtraction. % The algorithm I use here is that if a plus or minus follows anything but a left parenthesis, % we assume it is a binary operation of addition or subtraction, respectively. %\begin{verbatim} %$ 5.1 - 3.2 = \RespBoxMath[\rectW{.75in}\textSize{0}]{1.9}{1}{.0001}{[0,1]} % [{priorParse: NoAddOrSub }]\CorrAnsButton{1.9}$ %\end{verbatim} % \begin{macrocode} function NoAddOrSub (UserAns) { UserAns = stripWhiteSpace(UserAns); if ( !ok2Continue ) return null; UserAns = UserAns.replace(/\[|\{/g, "\("); UserAns = UserAns.replace(/\]|\}/g, "\)"); var result; var re = /.[+-]/g; re.lastIndex = 0; while ( (result = re.exec( UserAns )) != null ) { if ( result[0].charAt(0) != "\(" ) { app.alert( "Neither addition nor subtraction is not allowed for this problem."); return null; } } return true; } % \end{macrocode} % Deny user the use of all arithmetic functions, including exponents. % \begin{macrocode} function NoArithAllowed (UserAns) { var aNoArithmetic = new Array ( NoAddOrSub, NoProducts, NoDivision, NoExpAllowed ); for ( var i = 0; i < aNoArithmetic.length; i++ ) if ( (retn = aNoArithmetic[i](UserAns)) == null ) return null; return true; } % \end{macrocode} % Deny user the use of exponents. % \begin{macrocode} function NoExpAllowed (UserAns) { // Requires the ImplMulti option of dljslib UserAns = stripWhiteSpace(UserAns); if ( !ok2Continue ) return null; if ( /\^/.test( UserAns ) || /pow/.test( UserAns ) ) { app.alert( "The use of exponents is not allowed for this problem."); return null; } return true; } % \end{macrocode} % Deny user the use all trig functions, as well as the constants \texttt{PI} and \texttt{pi}, % which are aliases for $\pi$. Example: %\begin{verbatim} %$ \sin(\pi/4) = \RespBoxMath[\rectW{.75in}\textSize{0}]{sqrt(2)/2}{1}{.0001}{[0,1]} % [{priorParse: NoTrigAllowed }]\CorrAnsButton{sqrt(2)/2}$ %\end{verbatim} %You can obviously build similar function to deny the use of logs or square roots, for example. %\changes{v1.5}{2007/02/05} %{ % Removed \texttt{"pi"} and \texttt{"PI}" from the \texttt{aTrigFuncs array}, and added % \texttt{"arcsin"}, \texttt{"arccos"}, "\texttt{arctan"}. %} % \begin{macrocode} function NoTrigAllowed (UserAns) { UserAns = stripWhiteSpace(UserAns); if ( !ok2Continue ) return null; var aTrigfuncs = new Array ( "acos","asin","atan","cos", "sin", "tan","sec","csc","cot", "arcsin", "arccos", "arctan" ); var re, regexp; re = /[a-zA-Z]{2,}/g; aF = UserAns.match(re); if ( aF != null ) { for (var i=0; i < aF.length; i++) { for(var j=0; j < aTrigfuncs.length; j++) { if ( aF[i].indexOf(aTrigfuncs[j]) != -1 ) { app.alert("The use of trig functions in this problem is not allowed."); return null } } } } return true; } function NoTrigLogAllowed (UserAns) { UserAns = stripWhiteSpace(UserAns); if ( !ok2Continue ) return null; var aTrigfuncs = new Array ( "acos","asin","atan","cos", "sin", "tan","sec","csc","cot", "arcsin", "arccos", "arctan", "logc","log", "ln" ); var re, regexp; re = /[a-zA-Z]{2,}/g; aF = UserAns.match(re); if ( aF != null ) { for (var i=0; i < aF.length; i++) { for(var j=0; j < aTrigfuncs.length; j++) { if ( aF[i].indexOf(aTrigfuncs[j]) != -1 ) { app.alert("The use of trig and log functions is not allowed in this problem."); return null } } } } return true; } \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. % \begin{macro}{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{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; % var aRegExp = new Array(/([\d\)])([A-Za-z\(\\])/g, /(\))(\d)/g, /([A-Za-z])([\d\(\\])/g, /(@)([A-Za-z\d])/g ); % \end{macrocode} % Search through for matches with known functions % \begin{macrocode} for (var i=0; i (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)); } %%% factorialCancel and expandFactorial are needed by binomialCoeff function expandFactorial(lo,hi) { var f = lo; for (var i=lo+1;i<=hi;i++) f = i+"*"+f; return f; } % factorialCancel cancels common factors in num and denom using strings produced % by expandFactorial. It expects tails of factorials to have already been cancelled. 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} % The following functions, which are \texttt{ProcResp}-types, were written for an online % grading system being developed by Drs.\ Bruce Wagner and David Arnold, and Mr. % Jacob Miles-Prystowsky. The descriptions given below were provided by the authors. % \begin{macrocode} \begin{library@holding}{unordered} % \end{macrocode} % \subsubsection{\texttt{unordered}} % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - Processing Unordered Responses} % \end{macrocode} % The JS function \texttt{ProcRespSetFormula} will grade an % unordered list of formulas, such as % \texttt{x}, \verb!x^2!, \verb!x^3!. The code is a modification of % \texttt{ProcRespListFormula}. The idea is to split the user and correct % answers and then compare the first correct answer with each of the % user answers in turn. If there is a match, swap that user answer % with the first user answer. Then compare the second correct answer % with the rest of the user answers, and continue in that way. %\begin{flushleft} % Usage: %\begin{verbatim} %\def\formulabox#1#2#3{\RespBoxMath{#1}(#2){4}{1.0E-15}{#3}} %Some question requiring an unordered list of responses. %\formulasetbox{x,x^2,x^3}{x}{[1,2]} %\end{verbatim} %\end{flushleft} % \begin{macrocode} function ProcRespSetFormula(flag,CorrAns,n,epsilon,a,indepVar,oComp) { ok2Continue = true; if (!ProcessIt) return null; var fieldname = event.target.name; var UserAns = event.value; UserAns = stripWhiteSpace(UserAns); if (!ok2Continue) return null; var aUserAns = UserAns.split(","); var aCorrAns = CorrAns.split(","); var numCorrect = 0; var match = 0; if ( aUserAns.length != aCorrAns.length ) return notifyField(false, flag, fieldname); for ( var i=0; i< aCorrAns.length; i++) { match = 0; for ( var j=i; j< aUserAns.length; j++) { var retn = _ProcResp(flag,aCorrAns[i],aUserAns[j],n,epsilon,a,indepVar,oComp); if ( retn == null ) return syntaxError(), null; if (retn==1) { var temp=aUserAns[j]; aUserAns[j]=aUserAns[i]; aUserAns[i]=temp; match = match + 1; } } numCorrect += (match) ? 1 : 0; } var success = (numCorrect == aCorrAns.length) ? true : false; if ( success == null ) return syntaxError(), null; return notifyField(success, flag, fieldname); } \end{newsegment} \end{library@holding} % \end{macrocode} % \begin{macrocode} \begin{library@holding}{factors} % \end{macrocode} % \subsubsection{\texttt{factors}} % \texttt{ProcRespFactors} is for grading polynomial factoring % questions. For example, if a polynomial factors as % \verb!-5x^2(x-4)(x+2)!, then the answer is only unique up to the order of % factors and a change of sign on an even number of factors. For % example, it could also be written as \verb!-5x^2(x+2)(x-4)! or % \verb!5x^2(-x+4)(x+2)! or \verb!-5(x-4)(x+2)x^2!, etc. This script % should grade all of these correctly. (However, it will not allow % something like \verb!-(x-4)(x+2)5x^2!. The leading coefficient, if % there is one, must be placed at the beginning, which conforms to % our usual conventions.) %\begin{flushleft} % Usage: %\begin{verbatim} %\def\factorsbox#1#2#3{\RespBoxMath{#1}(#2){4}{1.0E-15}{#3}*{ProcRespFactors}} %Some question requiring a factored response %\factorsbox{3x(x^2+1)(2x-1)^3}{x}{[0,1]} %\end{verbatim} %\end{flushleft} % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - Processing Factors as Responses} function ProcRespFactors(flag,CorrAns,n,epsilon,a,indepVar,oComp) { ok2Continue = true; if (!ProcessIt) return null; var fieldname = event.target.name; var UserAns = event.value; UserAns = stripWhiteSpace(UserAns); if (!ok2Continue) return null; var retn = _ProcResp(flag,CorrAns,UserAns,n,epsilon,a,indepVar,oComp); if ( retn == null ) return syntaxError(), null; if ( retn == 0 ) { var initialsuccess = false; return notifyField(initialsuccess, flag, fieldname); } UserAns = UserAns.replace(/\*/g, ""); UserAns = UserAns.replace(/([A-Za-z]\^\d+)\(/g, "($1)("); UserAns = UserAns.replace(/\)([A-Za-z]\^\d+)/g, ")($1)"); UserAns = UserAns.replace(/([A-Za-z])\(/g, "($1)("); UserAns = UserAns.replace(/\)([A-Za-z])/g, ")($1)"); UserAns = UserAns.replace(/\)\(/g, "),("); UserAns = UserAns.replace(/(\w)\(/g, "$1,("); UserAns = UserAns.replace(/\)(\w)/g, "),$1"); CorrAns = CorrAns.replace(/\*/g, ""); CorrAns = CorrAns.replace(/([A-Za-z]\^\d+)\(/g, "($1)("); CorrAns = CorrAns.replace(/\)([A-Za-z]\^\d+)/g, ")($1)"); CorrAns = CorrAns.replace(/([A-Za-z])\(/g, "($1)("); CorrAns = CorrAns.replace(/\)([A-Za-z])/g, ")($1)"); CorrAns = CorrAns.replace(/\)\(/g, "),("); CorrAns = CorrAns.replace(/(\w)\(/g, "$1,("); CorrAns = CorrAns.replace(/\)(\w)/g, "),$1"); var NegCorrAns = CorrAns; var aUserAns = UserAns.split(","); var aCorrAns = CorrAns.split(","); var aNegCorrAns = NegCorrAns.split(","); for ( var i=0; i< aNegCorrAns.length; i++) {aNegCorrAns[i] = "-" + "(" + aNegCorrAns[i] + ")"} var numCorrect = 0; var match = 0; var signflag=0; if ( aUserAns.length != aCorrAns.length ) return notifyField(false, flag, fieldname); for ( var i=0; i< aCorrAns.length; i++) { match = 0; for ( var j=i; j< aUserAns.length; j++) { var retn = _ProcResp(flag,aCorrAns[i],aUserAns[j],n,epsilon,a,indepVar,oComp); if ( retn == null ) return syntaxError(), null; if (retn==1) { var temp=aUserAns[j]; aUserAns[j]=aUserAns[i]; aUserAns[i]=temp; match = match + 1; } else { var retn = _ProcResp(flag,aNegCorrAns[i],aUserAns[j],n,epsilon,a,indepVar,oComp); if ( retn == null ) return syntaxError(), null; if (retn==1) { var temp=aUserAns[j]; aUserAns[j]=aUserAns[i]; aUserAns[i]=temp; match = match + 1; signflag = signflag + 1; } } } numCorrect += (match) ? 1 : 0; } var success = ((numCorrect == aCorrAns.length) && (signflag\%2 == 0)) ? true : false; if ( success == null ) return syntaxError(), null; return notifyField(success, flag, fieldname); } \end{newsegment} \end{library@holding} % \end{macrocode} % \begin{macrocode} \begin{library@holding}{point} % \end{macrocode} % \subsubsection{\texttt{point}} % The JS function \texttt{ProcPoint} is an almost exact copy of your % \texttt{ProcVec}, but uses parentheses instead of angle brackets as % delimiters. This is for questions that have a point $(x,y)$ as the % answer. %\begin{flushleft} % Usage: %\begin{verbatim} %\def\formulapointbox#1#2#3{\RespBoxMath{#1}(#2){4}{1.0E-15}{#3}*{ProcPoint}} %Some question requiring a point (ordered pair) response %\formulapointbox{(e^t,te^t)}{t}{[0,1]} %\end{verbatim} %\end{flushleft} % \begin{macrocode} \begin{newsegment}{dljslib: Contrib - Processing a Point Response} function ProcPoint(flag,CorrAns,n,epsilon,a,indepVar,oComp) { if (!ProcessIt) return null; ok2Continue = true; % var i, success, truthCnt=0; var i, success, truthCnt=1; var aScalar, scalar = 1; var fieldname = event.target.name; var UserAns = event.value; % Implement an "undefined" answer. Due to Ross-Griffin if (UserAns == "undefined") { success = (CorrAns == UserAns); return notifyField(success, flag, fieldname); } CorrAns = stripWhiteSpace (CorrAns); UserAns = stripWhiteSpace (UserAns); // sets ok2Continue if ( !ok2Continue ) return null; if (!/[()]/.test(UserAns)) { app.alert("I'm looking for a point. You need to use proper point notation.", 3); return null; } if (!CkBalP(UserAns,"(",")")) { app.alert("Parentheses are not balanced.", 3); return null; } % \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; CorrAns = CorrAns.replace(/[()]/g, ""); // strip off ( 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" ) { % \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](UserAns); if ( retn == null ) return null; } } else { var retn = oComp.priorParse(UserAns); if ( retn == null ) return null; } } % Not convert each to an array aUserAns = UserAns.split(","); aCorrAns = CorrAns.split(","); if (scalar != 1) for (i=0; i % \end{macrocode} \endinput