% \iffalse
%<*copyright>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% dljsLib.sty package,             2002-2-9            %%
%% Copyright (C) 2001-2009  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.      %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%</copyright>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{dljslib}
%<package> [2012/11/17 v1.9f Manage a Library of Document Level JavaScripts (dps)]
%<*driver>
\documentclass{ltxdoc}
\usepackage[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}
%</driver>
% \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{complex}
\DeclareAndRegister{satisfyEq}
\DeclareAndRegister{unordered}
\DeclareAndRegister{factors}
\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 fillowing,
% \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 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}
\newcommand\equationsAlertMsg{"An equation is expected"}
\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}
%    \begin{macrocode}
    var CorrExpressions = CorrAns.split("=");
    var zCorrAns = "("+CorrExpressions[0]+")-("+CorrExpressions[1] +")";
    UserAns = stripWhiteSpace (UserAns);
    if(!ok2Continue ) return null;
    if (!/[=]/.test(UserAns)) {
            app.alert(\equationsAlertMsg, 3);
            return null;
    }
%    \end{macrocode}
% Check for commas, not permitted here. (2012/05/25)
%    \begin{macrocode}
    var reComma=/,/;
    if ( reComma.test(UserAns) ) {
        app.alert(\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) {
        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;
%   convert vars to  new format, if needed
    indepVar = TypeParameters(indepVar);
    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 + ")";
    success=randomPointCompare (n,a,indepVar,epsilon,
        zCorrAns,zUserAns,comp)
    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();
    _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}
%    \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}
\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."
}
\begin{library@holding}{vectors}
\begin{newsegment}{dljslib: Vector Handling}
function ProcVec (flag,CorrAns,n,epsilon,a,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;
%    \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(\vectorsErrorMsgi, 3);
        return null;
    }
    if (!CkBalP(UserAns,"<",">")) {
        app.alert(\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" ) {
%    \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<aUserAns.length; i++)
            aUserAns[i]=""+scalar+"*"+aUserAns[i];
    if (aCorrAns.length != aUserAns.length) {
        app.alert(\vectorsErrorMsgiii,3);
        return null;
    }
    // convert to new format, if needed
    indepVar = TypeParameters(indepVar);
    for (i=0; i<aCorrAns.length; i++) {
        aCorrAns[i] = ParseInput(aCorrAns[i]);
        if (!ok2Continue) {
            app.alert("Author Syntax error!", 3);
            return null;
        }
        aUserAns[i] = ParseInput(aUserAns[i]);
        if (aUserAns[i]==null) {
            app.alert(\vectorEmptyCompMsgiv(i), 3);
            return null;
        }
        if (!ok2Continue) return null;
        success=randomPointCompare (n,a,indepVar,epsilon,
            aCorrAns[i],aUserAns[i],comp)
        if ( success == null ) {
            app.alert(\eqSyntaxErrorUndefVar,3); return null; }
        truthCnt *= (success) ? 1 : 0;
    }
    return notifyField(!!truthCnt, flag, fieldname);
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
%    \end{macro}
% \subsubsection{\texttt{setSupport}}
%    \begin{macro}{setSupport}
% We introduce two JavaScript functions \texttt{ProcRespSetNum} and
% \texttt{ProcRespSetSym}, for handling a set of answers or a comma
% delimited list of answers. The first function is for
% numerical answers, the second for simple symbolic answers.  The
% demo file for these two response functions is
% \texttt{set\_test.tex}; the examples below were taken from that file.
%    \end{macro}
%    \begin{macrocode}
\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,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(",");
%    \end{macrocode}
% Make sure all of UserAns are numbers
%    \begin{macrocode}
    for ( var i=0; i < aUserAns.length; i++) {
        try {
            if (isNaN(eval(aUserAns[i]))) return syntaxError(), null;
        } catch(e) { return syntaxError(), null; }
    }
    var aUserAns = aUserAns.sort(
        function(a,b) { return eval(a) - eval(b);} );
    var aCorrAns = CorrAns.split(",").sort(
        function(a,b) { return  eval(a) - eval(b);} );
    var numCorrect = 0;
    if ( aUserAns.length != aCorrAns.length )
        return notifyField(false, flag, fieldname);
    for ( var i=0; i< aCorrAns.length; i++) {
        var retn = _ProcResp(
        flag,aCorrAns[i],aUserAns[i],n,epsilon,a,indepVar,oComp);
        if ( retn == null ) return syntaxError(), null;
        numCorrect += (retn) ? 1 : 0;
    }
%    var success = (numCorrect == aCorrAns.length) ? true : false;
    var success = (numCorrect == aCorrAns.length);
%    if ( success == null ) return syntaxError(), null;
    return notifyField(success, flag, fieldname);
}
function formatAsSet() {
    if (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[\AA{\AAKeystroke{
%        \AAKqRespBoxMath}\AAFormat{\setAsFormat}}
%           \rectW{.75in}\textSize{0}
%       ]{c,d}(\U){1}{.0001}{[0,1]}*{ProcRespSetSym}$
%\end{verbatim}
% \end{flushleft}
%    \begin{macrocode}
function ProcRespSetSym(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 _V = indepVar.split(",");
    for ( var _i=0; _i < _V.length; _i++) {
         eval ( "var "+ _V[_i] + " = \"" + _i + "\";");
    }
%    \end{macrocode}
% Make sure all of UserAns are numbers
%    \begin{macrocode}
    for ( var _i=0; _i < aUserAns.length; _i++) {
        try {
            if (isNaN(eval(aUserAns[_i]))) return syntaxError(), null;
            aUserAns[_i] = eval(aUserAns[_i]);
        } catch(e) { return syntaxError(), null; }
    }
    var aCorrAns = CorrAns.split(",");
    for ( var _i=0; _i < aCorrAns.length; _i++) {
        try {
            if (isNaN(eval(aCorrAns[_i])))
                return app.alert(
                    "Author error, recheck your code",3), null;
            aCorrAns[_i] = eval(aCorrAns[_i]);
        } catch(e) { return app.alert(
            "Author error, recheck your code",3), null; }
    }
    var aUserAns = aUserAns.sort(
        function(a,b) { return eval(a) - eval(b);} );
    var aCorrAns = aCorrAns.sort(
        function(a,b) { return  eval(a) - eval(b);} );
    var numCorrect = 0;
    if ( aUserAns.length != aCorrAns.length )
        return notifyField(false, flag, fieldname);
    for ( var _i=0; _i< aCorrAns.length; _i++) {
        var retn = _ProcResp(
        flag,aCorrAns[_i],aUserAns[_i],n,epsilon,"[0,1]","i:_x",oComp);
        if ( retn == null ) return syntaxError(), null;
        numCorrect += (retn) ? 1 : 0;
    }
%    console.println( aUserAns.toSource() );
    var success = (numCorrect == aCorrAns.length);
%    var success = (numCorrect == aCorrAns.length) ? true : false;
%    if ( success == null ) return syntaxError(), null;
    return notifyField(success, flag, fieldname);
}
%    \end{macrocode}
% The function \texttt{ProcRespListFormula} can be used to process a comma-delimited
% \emph{ordered} list of expressions.
%    \begin{macrocode}
function ProcRespListFormula(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);
     UserAns = UserAns.replace(/,+/g, ",");
     UserAns = UserAns.replace(/,$/, "");
     UserAns = UserAns.replace(/^,/, "");
     event.value = UserAns;
     CorrAns = stripWhiteSpace(CorrAns);
     if (!ok2Continue) return null;
     % Implement a "none" answer.
     if (UserAns == "none") {
         success = (CorrAns == UserAns);
         return notifyField(success, flag, fieldname);
     }
     var aUserAns = UserAns.split(",");
     var aCorrAns = CorrAns.split(",");
     var numCorrect = 0;
     if ( aUserAns.length != aCorrAns.length )
        return notifyField(false, flag, fieldname);
     for ( var i=0; i< aCorrAns.length; i++) {
         var retn =_ProcResp(
            flag,aCorrAns[i],aUserAns[i],n,epsilon,a,indepVar,oComp);
         if ( retn == null ) return syntaxError(), null;
         numCorrect += (retn) ? 1 : 0;
     }
     var success = (numCorrect == aCorrAns.length);
%     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}
% \subsubsection{\texttt{complex}}
% The function \texttt{ProcRespComplex} supplies support for answers that are
% complex numbers. The function test whether there is exactly one \texttt{i}
% in the expression, if not, a message appears reminding the user that the form
% of a complex number is \texttt{a + bi}. The function adds \texttt{i} as one of the
% variables, and appends \texttt{x[0,1]} to the domain specification. This might be a
% problem if the document author uses the old style of specifying the domain; use
% \texttt{[a,b]} to specify the domain, we change this to \texttt{[a,b]x[0,1]}.
%
% The rest of the function is like a multivariable problem. Seems to work ok.
% Here is a sample syntax:
%\begin{verbatim}
% $(3+3i)(4+5i) = \RespBoxMath{-3+27i}{3}{0.0001}{[0,1]}*{ProcRespComplex}$
%\end{verbatim}
%The correct answer must be supplied with the \cs{RespBoxMath}, and is used to compare
% with what the student enters.
% \changes{v1.7}{2007/10/12}
%{%
%   Added support for answer that are complex numbers.
%}
%    \begin{macrocode}
\newcommand{\complexPowerAlertMsg}{%
    "Powers of i (for example, i^2, i^3) are not supported,
    replace powers of i with their complex equivalents."
}
\newcommand{\complexCisAlertMsg}{%
    "The cis function does not support exponents. Write,
    for example, cis^3(x) as cis(3*x), instead."}
\newcommand{\alertNotComplexMsg}{%
    "The expression is not in the form of a complex
    number, a+bi"}
\def\emptyCompComplexMsg(#1){%
    "You entered nothing for the component "
     +(#1+1)+" of your answer. Please enter a complex number."
}
\begin{library@holding}{complex}
\begin{newsegment}{dljslib: Support for Complex Numbers}
%    \end{macrocode}
% Defined (11/11/08). The \texttt{cis} function is undefined unless the \texttt{complex} option is used.
%    \begin{macrocode}
function cis(x,i) { return Math.cos(x) + i*Math.sin(x); }
JSfCustom.push("cis");
JSf = JSf.concat(JSfBuiltIn, JSfCustom);
function ProcRespComplex(flag,CorrAns,n,epsilon,a,indepVar,oComp)
{
    if (!ProcessIt) return null;
    ok2Continue = true;
    var i, success;
    var fieldname = event.target.name;
    var UserAns = event.value;
    CorrAns = stripWhiteSpace (CorrAns);
    UserAns = stripWhiteSpace (UserAns); // sets ok2Continue
    if ( !ok2Continue ) return null;
    indepVar+="i";
    a+="x[0,1]";
%    \end{macrocode}
% We don't support powers of i
%    \begin{macrocode}
    if (/(\b|[^a-zA-Z])i\^/.test(UserAns)) {
        app.alert(\complexPowerAlertMsg,3);
        return null;
    }
%    \end{macrocode}
% Powers of \texttt{cis} function are not supported at this time.
%    \begin{macrocode}
%    var re=/cis\^/
    if ( /cis\^/.test(UserAns) ) {
        app.alert(\complexCisAlertMsg,3);
        return null;
    }
%    \end{macrocode}
%    \end{macrocode}
% (2012/05/25) Check for commas, not permitted here.
% \changes{v1.9f}{2012/11/17}{Moved this block higher, before testing for comma.}
%    \begin{macrocode}
    var reComma=/,/;
    if ( reComma.test(UserAns) ) {
        app.alert(\eqSyntaxErrorComma,3);
        return null;
    }
%    \end{macrocode}
% To make the \texttt{cis} function work, we've defined it to be a function of two variables,
% \texttt{cis(x,i)}, but the user does not need to know that. We search for \texttt{cis(<arg>)} and
% replace with \texttt{cis(<arg>,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) {
        app.alert(\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,a,indepVar,epsilon,CorrAns,UserAns,comp);
    if ( success == null ) { app.alert(%
\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,a,indepVar,oComp) {
     ok2Continue = true;
     if (!ProcessIt) return null;
     var fieldname = event.target.name;
     var UserAns = event.value;
     UserAns = stripWhiteSpace(UserAns);
     UserAns = UserAns.replace(/,+/g, ",");
     UserAns = UserAns.replace(/,$/, "");
     UserAns = UserAns.replace(/^,/, "");
     event.value = UserAns;
     CorrAns = stripWhiteSpace(CorrAns);
     if (!ok2Continue) return null;
     % Implement a "none" answer.
     if (UserAns == "none") {
         success = (CorrAns == UserAns);
         return notifyField(success, flag, fieldname);
     }
     var aUserAns = UserAns.split(",");
     var aCorrAns = CorrAns.split(",");
     if ( aUserAns.length != aCorrAns.length )
        return notifyField(false, flag, fieldname);
     var numCorrect = 0;
     var match = 0;
     for ( var i=0; i< aCorrAns.length; i++) {
         match = 0;
         event.value = aUserAns[i];
         var retn = ProcRespComplex(
            flag,aCorrAns[i],n,epsilon,a,indepVar,oComp);
         event.value = UserAns;
         if ( retn == null ) return null;
         numCorrect += (retn) ? 1 : 0;
     }
     var success = (numCorrect == aCorrAns.length);
%     var success = (numCorrect == aCorrAns.length) ? true : false;
     return notifyField(success, flag, fieldname);
}
%    \end{macrocode}
% \texttt{ProcRespSetComplex}, contributed by Bruce Wagner, extends
% \texttt{ProcRespComplex} to sets; an un-ordered listing of complex responses.
%\begin{verbatim}
% Find all real and complex solutions of the equation $x^2=-9$. \\
% Express your answer(s) in rectangular form $a+bi$.
% \RespBoxMath{3i,-3i}{4}{0.0001}{[0,1]}*{ProcRespSetComplex}
%\end{verbatim}
%    \begin{macrocode}
function ProcRespSetComplex(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);
     UserAns = UserAns.replace(/,+/g, ",");
     UserAns = UserAns.replace(/,$/, "");
     UserAns = UserAns.replace(/^,/, "");
     event.value = UserAns;
     CorrAns = stripWhiteSpace(CorrAns);
     if (!ok2Continue) return null;
     % Implement a "none" answer.
     if (UserAns == "none") {
         success = (CorrAns == UserAns);
         return notifyField(success, flag, fieldname);
     }
     var aUserAns = UserAns.split(",");
     var aCorrAns = CorrAns.split(",");
     if ( aUserAns.length != aCorrAns.length )
        return notifyField(false, flag, fieldname);
     var numCorrect = 0;
     var match = 0;
     for ( var i=0; i< aCorrAns.length; i++) {
         match = 0;
         for ( var j=i; j< aUserAns.length; j++) {
            event.value = aUserAns[j];
            var retn = ProcRespComplex(
                flag,aCorrAns[i],n,epsilon,a,indepVar,oComp);
            event.value = UserAns;
            if ( retn == null ) return 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);
     return notifyField(success, flag, fieldname);
}
function changeArgs4Cis(str) {
    var re =/cis\(/g;
    while ( (aP=re.exec(str) ) != null ) {
        var LeftP=re.lastIndex;
        var RightP=FindBalP(str,re.lastIndex,1);
        str = str.substring(0,RightP)
            +",i"+str.substring(RightP);
    }
    return str;
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
% \subsubsection{\texttt{satisfyEq}}
%
% These functions are used for questions where the student is asked to enter one or more
% points that satisfy a given equation $ F = G $. For these types of problems, there
% are infinity many correct answers.
%
%    \begin{macrocode}
\newcommand{\eqSyntaxErrorNoParens}{"Syntax Error: Enter the point
    using parentheses, for example (1,2) or (1,2,3), as applicable."}
\newcommand{\eqNonzeroEntries}{"Syntax Error: All entries are required
    to be nonzero, try again."}
\newcommand{\eqTooManyEntries}{"You've entered more points than
    requested, enter only "+l+" points."}
\newcommand{\eqTooFewEntries}{"You've entered fewer points than
    requested, enter only "+l+" points."}
\newcommand{\eqDuplEntries}{"One or more points are the same,
    provide "+l+" distinct points."}
\begin{library@holding}{satisfyEq}
\begin{newsegment}
    {dljslib: Support for n-tuple input to Satisfy an Equation}
%    \end{macrocode}
%\DescribeMacro{ProcRespEvalEq}is not based on random point generation, as
%all the other \textsf{exerquiz} functions are. Here, the user enters
%numerical data, the function then verifies the data entered satisfies the
%given equation. The role of \texttt{CorrAns} has changed. If the equation
%is $ F = G $, then $ F - G $ should be passed as the
%\texttt{CorrAns} variable. This function obeys the value of
%\texttt{epsilon} but ignores the number of iterations (\verb!{1}! below),
%and the domain of the variables (\cs{ixdna} below) \cs{ixdna} is a special
%command that can be used for this parameter, in this context only.  The \texttt{oComp}
%parameter is also ignored.
%\medskip\noindent\textbf{Sample Use.}
%\begin{verbatim}
%\item Enter a point that lies on the line $2x+3y=6$,\\[3pt]
%    $\text{A point is }\RespBoxMath[\rectW{.75in}
%    \textSize{0}]{2x+3y-6}(xy){1}{.0001}{[0,1]x[0,1]}*{ProcRespEvalEq}
%    \CorrAnsButton{various, such as (0,2)}$
%\end{verbatim}
% The demo document is \texttt{satisfy\_eq.tex}.
%\changes{v1.9}{2011/06/24}{Added \texttt{ProcRespEvalEq} in response to
% a problem posed by David Arnold.}
%    \begin{macrocode}
function ProcRespEvalEq(flag,CorrAns,n,epsilon,a,indepVar,oComp){
    var retn=_ProcRespEvalEq(true,flag,CorrAns,n,epsilon,indepVar);
    return retn;
}
%    \end{macrocode}
% \DescribeMacro{ProcRespEvalEqNonZero} is the same as \texttt{ProcRespEvalEq}, but requires
% all entries to be nonzero.
%    \begin{macrocode}
function ProcRespEvalEqNonZero(flag,CorrAns,n,epsilon,a,indepVar,oComp){
    var retn=_ProcRespEvalEq(false,flag,CorrAns,n,epsilon,indepVar);
    return retn;
}
%    \end{macrocode}
%    \begin{macrocode}
function _ProcRespEvalEq(allowzero,flag,CorrAns,n,epsilon,indepVar)
{
    ok2Continue = true;
    if (!ProcessIt) return null;
    var fieldname = event.target.name;
    var UserAns = event.value;
    UserAns = stripWhiteSpace(UserAns);
    if (!ok2Continue) return null;
    if ( (UserAns.charAt(0) != "\(") || %
(UserAns.charAt(UserAns.length-1) != "\)"))
        return app.alert(\eqSyntaxErrorNoParens,3), null;
    UserAns=UserAns.substring(1,UserAns.length-1);
    var aUserAns = UserAns.split(",");
%    \end{macrocode}
% Make sure all of UserAns are numbers
%    \begin{macrocode}
    for ( var i=0; i < aUserAns.length; i++) {
        try {
            if (isNaN(eval(aUserAns[i]))) return syntaxError(), null;
            if (!allowzero && (eval(aUserAns[i])==0))
                return app.alert(\eqNonzeroEntries,3), null;
        } catch(e) { return syntaxError(), null; }
    }
    var _v = TypeParameters(indepVar);
    var _V = _v.split(",");  // e.g. _V[0] = "i:x"
    var _n = _V.length;
    if ( aUserAns.length != _n)
        return notifyField(false, flag, fieldname);
%    \end{macrocode}
% The following code is taken from \texttt{diffCompare}, it uses a "safe" technique
% for evaluating an expression.
%    \begin{macrocode}
    for (var _i=0; _i < _n; _i++) {
        if (_V[_i].charAt(0) == "r" )
          eval("var "+_V[_i].charAt(2)+"="+aUserAns[_i]+";");
        else // assume type "i"
          eval("var "+_V[_i].charAt(2)+"="+Math.ceil(aUserAns[_i])+";");
    }
    var UserInput=ParseInput(CorrAns);
    var UserAns=eval(UserInput);
    success=(Math.abs(UserAns) < epsilon)?true:false;
    return notifyField(success, flag, fieldname);
}
%    \end{macrocode}
% This function takes a semi-colon delimited list of ordered n-tuples.
% The \texttt{CorrAns} parameter is of the form \texttt{n\_pairs; F-G}
%    \begin{macrocode}
function ProcRespEvalEqList(flag,CorrAns,n,epsilon,a,indepVar,oComp){
    var retn=_ProcRespEvalEqList(true,flag,CorrAns,n,epsilon,indepVar);
    return retn;
}
function ProcRespEvalEqListNonZero(flag,CorrAns,n,epsilon,a,%
indepVar,oComp){
    var retn=_ProcRespEvalEqList(false,flag,CorrAns,n,epsilon,indepVar);
    return retn;
}
function _ProcRespEvalEqList(allowzero,flag,CorrAns,n,epsilon,indepVar)
{
    ok2Continue = true;
    if (!ProcessIt) return null;
    var fieldname = event.target.name;
    var UserAns = event.value;
    UserAns = stripWhiteSpace(UserAns);
    if (!ok2Continue) return null;
    var success;
%    \end{macrocode}
% Remove any semicolons at end of line, then remove any duplicated semicolons.
% This is done to prevent simple errors by user input.
%    \begin{macrocode}
    UserAns=UserAns.replace(/;+$/,"");
    UserAns=UserAns.replace(/;+/g,";");
    var aUsersArray = new Array();
%    \end{macrocode}
% Split the user's answer up by the delimiting semi-colon.
%    \begin{macrocode}
    var aUserAns = UserAns.split(";");
%    \end{macrocode}
% First component is the number of points expected, second component is \texttt{F(x)-G(x)}
%    \begin{macrocode}
    var aCorrAns = CorrAns.split(";");
    var l = aCorrAns[0];
%    \end{macrocode}
% If the user gave too many answers, broadcast alert.
%    \begin{macrocode}
    if (l < aUserAns.length )
        return app.alert(\eqTooManyEntries,3), null;
%    \end{macrocode}
% If the user gave too few answers, broadcast alert.
%    \begin{macrocode}
    if (l > aUserAns.length )
        return app.alert(\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 app.alert(\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 app.alert(\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)
            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<m; i++)
        if (Math.abs(aUsersArray[i]-aUsersArray[i+1])<.0001)
            return app.alert(\eqDuplEntries,3), null;
%    \end{macrocode}
% If we have not exited earlier, we exit now with \texttt{success} as \texttt{true} or \texttt{false}.
%    \begin{macrocode}
    return notifyField(success, flag, fieldname);
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
%
% \subsection{Compare Functions}\label{s:compfunctions}
%
% \textbf{Used by Exerquiz.}   A compare function is a JavaScript that compares the author's answer
% with the user's answer. There may be a need for compare functions other than the default one provided
% by \texttt{exerquiz}.
%
% \subsubsection{\texttt{indefIntegral}}\label{indefIntegral}
%    \begin{macro}{indefIntegral}
% The answer to an indefinite integral is non-unique; however all answers differ by a constant.
% This compare function is used with indefinite integrals. See \texttt{jqzspec.tex} for an
% example of the use of this function. Note the name of the function is \texttt{indefCompare}, this
% is the name you use to call the function. An example of usage of this function can be found in
% the sample file \texttt{jslib\_ex.tex} that comes with the Acro\TeX{} Bundle; from that file we
% have:
%\begin{verbatim}
%$\displaystyle\int\sin(x)\,dx =
%    \RespBoxMath{-cos(x)}[intSin]{4}{.0001}{[0,1]}[indefCompare]$
%\end{verbatim}
% See also the file \texttt{jqzspec.tex} for more details.
%    \begin{macrocode}
\begin{library@holding}{indefIntegral}
\begin{newsegment}{dljslib: Indefinite Integral Handling}
function indefCompare(_a,_c,_v,_F,_G) {
    var eqC;
    var aAB = _a.split(",");
    var aXY = _c.split(",");
    var _V = _v.split(",");  // e.g. _V[0] = "i:x"
    var _n = aXY.length
        for (var _i=0; _i< _n; _i++) {
            if (_V[_i].charAt(0) == "r" )
                eval ( "var "+ _V[_i].charAt(2)
                    + " = " + aAB[2*_i] + ";");
            else // assume type "i"
                eval ( "var "+ _V[_i].charAt(2)
                    + " = " + Math.ceil(aAB[2*_i]) + ";");
        }
% var C = 0 is used to designate an arbitrary constant
        var C = 0;
        if ( app.viewerVersion >= 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}
%    \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}
\newcommand\nodecAlertMsg{%
    "A decimal answer is not acceptable here.
     Please express your answer using fractions, square roots,
     e, log, etc."%
}
\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}
%var nodecAlertMsg=\nodecAlertMsg;
function nodec(UserAns)
{
    var dot = /[\.\aebdecimalpoint]/;
    if (dot.test(UserAns)) {
        app.alert(\nodecAlertMsg,3);
        return null;
    } else return true;
}
\end{newsegment}
%    \end{macrocode}
%    \begin{macrocode}
\end{library@holding}
\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."}
\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}
aReFact = new Array(
    /(?=\()?(\d+)(?=\))?!/,
    /(?=\[)?(\d+)(?=\])?!/,
    /(?=\{)?(\d+)(?=\})?!/
);
function noBinFac(UserAns)
{
    var bad = /(C\()/;
    if (bad.test(UserAns)) {
        app.alert(\noBinFactBinCoeffAlertMsg,3);
        return null;
    }
    bad = /(P\()/;
    if (bad.test(UserAns)) {
        app.alert(\noBinFactPermAlertMsg,3);
        return null;
    }
    for ( var i=0; i<aReFact.length; i++) {
        if (aReFact[i].test(UserAns)) {
            app.alert(\noBinFactFactAlertMsg,3);
            return null;
        }
    }
    bad = /(fact)/;
    if (bad.test(UserAns)) {
        app.alert(\noBinFactFactAlertMsg,3);
        return null;
    }
    return true
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
%    \begin{macrocode}
\newcommand{\DecimalsOnlyErrorMsg}{%
    "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."}
\newcommand{\NoProductsErrorMsg}{%
    "Multiplication is not allowed for this problem."}
\newcommand{\NoDivisionErrorMsg}{%
    "Division is not allowed for this problem."}
\newcommand{\NoAddOrSubErrorMsg}{%
    "Neither addition nor subtraction is allowed for this problem."}
\newcommand{\NoExpAllowedErrorMsg}{%
    "The use of exponents is not allowed for this problem."}
\newcommand{\NoTrigAllowedErrorMsg}{%
    "The use of trig functions in this problem is not allowed."}
\newcommand{\NoTrigLogAllowedErrorMsg}{%
    "The use of trig and log functions is not allowed
        in this problem."}
\newcommand{\sciNotSyntaxError}{"Enter the answer in
    scientific notation."}
\newcommand{\sciNotNormalForm}{"The scientific notation entered
    is not in normalized form."}
\newcommand{\NoNegExpMsg}{"No negative exponents permitted,
    keep working!"}
\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)
{
    UserAns  = stripWhiteSpace(UserAns);
    if ( !ok2Continue ) return null;
    if( !isFinite( UserAns ) ) {
        app.alert(\DecimalsOnlyErrorMsg,3);
        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(\NoProductsErrorMsg,3);
        return null;
    }
    return true;
}
function NoDivision (UserAns)
{
    if ( /\//.test( UserAns) ) {
        app.alert(\NoDivisionErrorMsg,3);
        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(\NoAddOrSubErrorMsg,3);
            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(\NoExpAllowedErrorMsg,3);
        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(\NoTrigAllowedErrorMsg,3);
                    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(\NoTrigLogAllowedErrorMsg,3);
                    return null
                }
            }
        }
    }
    return true;
}
%    \end{macrocode}
%\changes{v1.9a}{2011/07/15}{Added \texttt{sciNotResp}}
% This filter function checks to see if the user's input is in the form of (normalized)
% scientific notation: \verb![+-]*d[.d*]*[ ]*E[+-]*d+!, written in pseudo-reg expr.
%    \begin{macrocode}
function sciNotResp(UserAns)
{
    var _sciNotation, _a;
    _sciNotation = /^[+-]*(\d)(\.\d*)* *E[+-]*\d+$/;
    UserAns=stripWhiteSpace(UserAns);
    if ( (_a=_sciNotation.exec(UserAns)) !=null) {
        if (Number(_a[1]) == 0 ) {
            app.alert(\sciNotNormalForm,3);
            return null;
        } else return true
    } else {
        app.alert(\sciNotSyntaxError,3);
        return null;
    }
}
%    \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)) {
        app.alert(\NoNegExpMsg,3);
        return null;
    } else 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;
%    \end{macrocode}
% Search through for matches with known functions
%    \begin{macrocode}
    for (var i=0; i<JSf.length; i++)
    {
%    \end{macrocode}
% Here we mark the beginning of the left parenthesis for a
% that follows one of the  known functions. This way we can
% distinguish between the built in JavaScript functions and
% other sequences of letters that may represent products.
% \begin{flushleft}
% \textbf{Note:} In the regular
% expression below, and elsewhere, when our search includes unbalanced parentheses
% we need to triple escape them, i.e., instead of `\verb+\\(+' we write
% `\verb+\\\(+'. See comments in \texttt{insdlis.dtx}.
% \end{flushleft}
%    \begin{macrocode}
        re = new RegExp("("+JSf[i]+")(\\\()","g");
        UserInput = UserInput.replace(re, "\\$1@$2");
%    \end{macrocode}
% If a known function has a letter or a right parenthesis to the left of it,
% the user must want multiplication, make it so!
%    \begin{macrocode}
        re = new RegExp("([\\w\\\)])(\\"+JSf[i]+")(@\\\()","g");
        UserInput = UserInput.replace(re, "$1*$2$3");
    }
%    \end{macrocode}
% Now do the same type thing for known constants.
%    \begin{macrocode}
    for (var i=0; i<JSc.length; i++)
    {
%    \end{macrocode}
% We mark the beginning and end of a known predefined constant
% \changes{v1.6}{2007/02/23}
%{
%    If we match up with "E", we do nothing. This is support of
%    using "E" for scientific notation.
%}
%    \begin{macrocode}
        re = new RegExp("("+JSc[i]+")","g");
        if ( JSc[i] != "E" ) {
            UserInput = UserInput.replace(re, "\\$1@");
%    \end{macrocode}
% If a known constant has a letter or an right parenthesis to the left of it,
% the user must want multiplication, make it so!
%    \begin{macrocode}
            re = new RegExp("([\\w\\\)])(\\"+JSc[i]+")(@)","g");
        }
    }
%    \end{macrocode}
% Search for a number or right paren followed by a letter or right paren
% and insert *.
%\changes{v1.6}{2007/02/23}
%{
%    dps/change 02/23/07. In the search below, we exclude the search
%   for the letter "E", because it is used for scientific notation (called exponential)
%}
% notation in JavaScript).
%    \begin{macrocode}
    UserInput = UserInput.replace(
        /([\d\)])([A-DF-Za-z\(\\])/g, "$1*$2");
%    \end{macrocode}
% Search for a right paren followed by a number.
%    \begin{macrocode}
    UserInput = UserInput.replace(/(\))(\d)/g, "$1*$2");
%    \end{macrocode}
% Search for a letter followed by a number of right paren, and insert *
%    \begin{macrocode}
    UserInput = UserInput.replace(/([A-Za-z])([\d\(\\])/g, "$1*$2");
%    \end{macrocode}
% If a predefined constant, such as \texttt{PI}, is multiplied on the
% right by a factor, there will be a \texttt{@} followed by a letter or decimal.
%    \begin{macrocode}
%    re = /(@)([A-Za-z\d])/g;
    UserInput = UserInput.replace(/(@)([A-Za-z\d])/g, "$1*$2");
%    \end{macrocode}
% Now strip off the markers
%    \begin{macrocode}
    UserInput = UserInput.replace(/(\\)([A-Za-z]{1,})(@)/g, "$2");
%    \end{macrocode}
%  Search through list of known functions for a match.
%    \begin{macrocode}
% MacQTeX change   dps/change 02/23/07
    re = /[A-Za-z]{1,}/g;
    while ( (aR = re.exec(UserInput)) != null)
    {
        for (var i=0; i<JSf.length; i++) if ( aR[0] == JSf[i]) break;
        if ( i < JSf.length ) continue;
        for (var i=0; i<JSc.length; i++) if ( aR[0] == JSc[i]) break;
        if ( i < JSc.length ) continue;
%    \end{macrocode}
% If there is no match with known functions or constants, then we need to assume
% this word is a series of products, and separate them on their non-word
% boundaries by a multiplication operator *. We will not be able to identify
% mistyped functions, for example, if the user enters \texttt{cis(x)} instead of
% \texttt{cos(x)}, this will end up as \texttt{c*i*s*(x)}. Ultimately,
% the user will get a message that there is an error in the expression, but not
% hints as to what the error is will not be given.
%    \begin{macrocode}
        aR[0] = aR[0].replace(/([A-Za-z])\B/g,"$1*");
        UserInput = UserInput.substring(0,aR.index)
            +aR[0]+UserInput.substring(re.lastIndex);
    }
    return UserInput;
}
%    \end{macrocode}
% The function \texttt{Ck4Exponents()} attempts to convert the notation \verb+sin^2(x)+
% into standard JavaScript format of \texttt{pow(sin(x),2)}.
%    \begin{macrocode}
function Ck4Exponents(UserInput)
{
    var re, regexp, aP, RightP;
    for (var i=0; (i<JSf.length) && (ok2Continue); i++)
    {
        re = new RegExp(JSf[i]+"\\^");
        while ( re.test(UserInput) && (ok2Continue) )
        {
%    \end{macrocode}
% Here we seek to match an expression of the form: \verb+cos^(exp)(arg)+
%    \begin{macrocode}
            regexp = new RegExp(JSf[i]+"\\^\\\(", "g");
            if ( (aP = regexp.exec(UserInput)) != null ) {
                // forward search
                RightP=FindBalP(UserInput,regexp.lastIndex-1,1);
                var offsetExp = RightP-regexp.lastIndex;
                regexp = new RegExp(
                    JSf[i]+"\\^\\(.{"+offsetExp+"}\\)\\\(", "g");
                regexp.lastIndex=0;
                if ( (aP = regexp.exec(UserInput)) != null ) {
                    // forward search
                    RightP=FindBalP(UserInput,regexp.lastIndex-1,1);
                    var offsetArg = RightP - regexp.lastIndex;
                    regexp = new RegExp("("+JSf[i]
                        +")\\^\\((.{"+offsetExp+"})\\)\\((.{"
                        +offsetArg+"})\\)");
                    regexp.lastIndex=0;
                    if (regexp.test(UserInput))
                        UserInput=UserInput.replace(
                            regexp,"(pow($1($3),$2))");
                    else ok2Continue=false;
                    continue;
                }
            }
%    \end{macrocode}
% Here we seek to match an expression of the form: \verb+cos^\pmNum.Num(arg)+
%    \begin{macrocode}
            regexp = new RegExp(JSf[i]
                +"\\^([a-zA-Z]|[+-]?\\d+\\.?\\d*|[+-]?\\d*\\.?\\d+)"
                +"\\\(","g");
            if ( (aP = regexp.exec(UserInput)) != null ) {
                // forward search
                RightP=FindBalP(UserInput,regexp.lastIndex-1,1);
                regexp = new RegExp("("
                    +JSf[i]+")\\^([a-zA-Z]|[+-]?\\d+"
                    +"\\.?\\d*|[+-]?\\d*\\.?\\d+)\\((.{"
                    +eval(RightP-regexp.lastIndex)+"})\\)");
                regexp.lastIndex=0;
                if (regexp.test(UserInput))
                    UserInput=UserInput.replace(
                        regexp,"(pow($1($3),$2))");
                else ok2Continue=false;
            }
            else ok2Continue=false;
        }
    }
%    \end{macrocode}
% Now we do the same thing for declared constants.
%    \begin{macrocode}
    for (var i=0; (i < JSc.length) && (ok2Continue); i++)
    {
        re = new RegExp(JSc[i]+"\\^", "g");
        while ( re.test(UserInput) && (ok2Continue) )
        {
            re.lastIndex = 0;
            aR = re.exec(UserInput);
            if (UserInput.charAt(re.lastIndex)=='\(') {
                // forward search
                RightP=FindBalP(UserInput,re.lastIndex,1);
                var offsetExp = RightP - re.lastIndex - 1;
                re.lastIndex=0;
                regexp = new RegExp("("+JSc[i]
                    +")\\^\\((.{"+offsetExp+"})\\)");
                if ( regexp.test(UserInput) )
                    UserInput = UserInput.replace(
                        regexp, "(pow($1,$2))");
                else ok2Continue = false;
            }
            else
            {
                re.lastIndex=0;
                regexp = new RegExp("("+JSc[i]
                +")\\^([a-zA-Z]|[+-]?\\d+\\.?\\d*|[+-]?\\d*\\.?\\d+)");
                if (regexp.test(UserInput))
                    UserInput = UserInput.replace(
                        regexp, "(pow($1,$2))");
                else ok2Continue = false;
            }
        }
    }
    return UserInput;
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
%    \end{macro}
% \subsection{User Contributions}
% 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}}
%    \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}
% 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\formulasetbox#1#2#3{\RespBoxMath{#1}(#2)[\thequestionno]{10}
%    {1.0E-15}{#3}*{ProcRespSetFormula}}
%\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);
     UserAns = UserAns.replace(/,+/g, ",");
     UserAns = UserAns.replace(/,$/, "");
     UserAns = UserAns.replace(/^,/, "");
     event.value = UserAns;
     CorrAns = stripWhiteSpace(CorrAns);
     if (!ok2Continue) return null;
     % Implement a "none" answer.
     if (UserAns == "none") {
         success = (CorrAns == UserAns);
         return notifyField(success, flag, fieldname);
     }
     var aUserAns = UserAns.split(",");
     var aCorrAns = CorrAns.split(",");
     var numCorrect = 0, 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);
%     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;
    var success = ((numCorrect==aCorrAns.length)&&(signflag\%2==0));
    if ( success == null ) return syntaxError(), null;
    return notifyField(success, flag, fieldname);
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
%    \begin{macrocode}
\newcommand{\pointErrorMsgi}{%
    "I'm looking for a point. You need to use proper point notation."}
\newcommand{\pointErrorMsgii}{"Parentheses are not balanced."}
\newcommand{\pointErrorMsgiii}{"Incorrect number of components.
    The answer requires "+ aCorrAns.length+" components."}
\def\pointEmptyCompMsgiv(#1){
    "You entered nothing for the component " +(#1+1)
        +" of your answer. Please enter a component for the point."
}
\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=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(\pointErrorMsgi, 3);
        return null;
    }
    if (!CkBalP(UserAns,"(",")")) {
        app.alert(\pointErrorMsgii, 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<aUserAns.length; i++)
            aUserAns[i]=""+scalar+"*"+aUserAns[i];
    if (aCorrAns.length != aUserAns.length) {
        app.alert(\pointErrorMsgiii,3);
        return null;
    }
    indepVar = TypeParameters(indepVar);
    for (i=0; i<aCorrAns.length; i++) {
        aCorrAns[i] = ParseInput(aCorrAns[i]);
        if (!ok2Continue) {
            app.alert("Author Syntax error!", 3);
            return null;
        }
        aUserAns[i] = ParseInput(aUserAns[i]);
        if (aUserAns[i]==null) {
            app.alert(\pointEmptyCompMsgiv(i), 3);
            return null;
        }
        if (!ok2Continue) return null;
        success=randomPointCompare (
            n,a,indepVar,epsilon,aCorrAns[i],aUserAns[i],comp)
        if ( success == null ) {
            app.alert(\eqSyntaxErrorUndefVar,3); return null; }
        truthCnt *= (success) ? 1 : 0;
%-        if (success) truthCnt +=1;
    }
%    return notifyField((truthCnt == 3), flag, fieldname);
    return notifyField(!!truthCnt, flag, fieldname);
}
\end{newsegment}
\end{library@holding}
%    \end{macrocode}
%    \begin{macrocode}
\begin{library@holding}{intervals}
%    \end{macrocode}
% \subsubsection{\texttt{intervals}}
%  \texttt{ProcRespIntervals} is for grading questions that have an
%  interval or union of intervals as the answer. Example answers
%  include:
%\begin{verbatim}
%(2,3)
%[2,3]
%(-inf,4)
%(-inf,4]
%(6,inf)
%[6,inf)
%(2,3)U[8,9)
%(-inf,6)U(9,inf)
%(-inf,6]U[7,8)U(9,inf)
%\end{verbatim}
%  Here I've used "inf" for infinity and the capital letter "U" for
%  the union symbol. Note also that intervals in a union can appear
%  in any order.
%\begin{flushleft}
%The \texttt{ProcRespIntervals} function has been modified by Robert Marik
%to allow intervals with end points \texttt{ln(2)}, \texttt{exp(4)} or \texttt{sqrt(3)}.
%Thus, intervals of the form
%\verb!(ln(2),ln(3)]U(exp(10),inf)! are recognized by this procedure.
%\medskip\noindent
% Usage:
%\begin{verbatim}
%\def\intervalbox#1{\RespBoxMath{#1}(infU){10}
%    {1.0E-4}{[0,1]x[0,1]x[0,1]x[0,1]}*{ProcRespIntervals}}
%Some question requiring an interval or union of intervals
%\intervalbox{(-inf,4]U[5,inf)}
%\end{verbatim}
% To avoid problems with unbalanced parentheses, as in this example,
%\verb!\intervalbox{(-inf,4)U[5,inf)}!.
% Here there is only one right parenthesis and two left parentheses. As a
% workaround, escape the odd
% parenthesis, like so
%\verb!\intervalbox{(-inf,4)U[5,inf\eqbs)}!,
% where \cs{eqbs} is defined in the \textsf{insdljs} package.
%\end{flushleft}
%    \begin{macrocode}
\begin{newsegment}{dljslib: Contrib - Processing Interval Responses}
function ProcRespIntervals(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);
     CorrAns = stripWhiteSpace(CorrAns);
     if (!ok2Continue) return null;
     UserAns = UserAns.replace(/inf/g, "x");
     CorrAns = CorrAns.replace(/inf/g, "x");
     indepVar = "x";
     a="[0,1]";
     var aUserAns = UserAns.split("U");
     var aCorrAns = CorrAns.split("U");
     var numCorrect = 0;
     var match = 0;
     var matchparts = 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++) {
             CorrInt=aCorrAns[i];
             UserInt=aUserAns[j];
             var levaUser = UserInt.charAt(0);
             var pravaUser = UserInt.charAt(UserInt.length-1);
             var stredUser = UserInt.substring(1,UserInt.length-1);
             UserInt = levaUser+","+stredUser+","+pravaUser;
             var levaCorr = CorrInt.charAt(0);
             var pravaCorr = CorrInt.charAt(CorrInt.length-1);
             var stredCorr = CorrInt.substring(1,CorrInt.length-1);
             CorrInt = levaCorr+","+stredCorr+","+pravaCorr;
             var aCorrInt = CorrInt.split(",");
             var aUserInt = UserInt.split(",");
             if ( aUserInt.length != 4 )
                return notifyField(false, flag, fieldname);
             matchparts = 0;
             if (aCorrInt[0] == aUserInt[0]) matchparts+=1;
             if (aCorrInt[3] == aUserInt[3]) matchparts+=1;
             var retn1 = _ProcResp(
               flag,aCorrInt[1],aUserInt[1],n,epsilon,a,indepVar,oComp);
             if (retn1 == null) return syntaxError(), null;
             if (retn1 == 1) matchparts+=1;
             var retn2 = _ProcResp(
               flag,aCorrInt[2],aUserInt[2],n,epsilon,a,indepVar,oComp);
             if (retn2 == null) return syntaxError(), null;
             if (retn2 == 1) matchparts+=1;
             if (matchparts == 4) {
                 var temp=aUserAns[j];
                 aUserAns[j]=aUserAns[i];
                 aUserAns[i]=temp;
                 match = match + 1;
             }
         }
         numCorrect += (match) ? 1 : 0;
     }
     var success = (numCorrect == aCorrAns.length);
%     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}
% Finally, we have the ``back wrapper'' or ``back cover'' of the selected materials. We close the
% \texttt{insDLJS} environment
%    \begin{macrocode}
\begin{library@holding}{dljslib}
\end{insDLJS*}
\end{library@holding}
%    \end{macrocode}
% \section{Out the Door and Close it behind you}, and free up this write register.
%    \begin{macrocode}
\immediate\closeout\dljslib@verbatim@out
\advance\count17 by -1
%    \end{macrocode}
% \section{Back Home with your Selections}
%    \begin{macrocode}
\input{dljslib.ljs}
%</package>
%    \end{macrocode}
\endinput
