% \iffalse
%<*copyright>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% eq-save package,                                     %%
%% Copyright (C) 2017-2021                              %%
%%   dpstory@uakron.edu                                 %%
%%                                                      %%
%% This program can redistributed and/or modified under %%
%% the terms of the LaTeX Project Public License        %%
%% Distributed from CTAN archives in directory          %%
%% macros/latex/base/lppl.txt; either version 1.2 of    %%
%% the License, or (at your option) any later version.  %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%</copyright>
%<package>\NeedsTeXFormat{LaTeX2e}[1997/12/01]
%<package>\ProvidesPackage{eq-save}
%<package> [2021/04/27 v1.2.5 eq-save: save exerquiz quizzes and resume (dps)]
%<*driver>
\documentclass{ltxdoc}
\usepackage[colorlinks,hyperindex=false]{hyperref}
\usepackage{calc}
\let\uif\textsf\let\app\textsf
\let\pkg\textsf\let\env\texttt
\let\opt\texttt
\def\ameta#1{$\langle\textit{\texttt{#1}}\rangle$}
\def\psf#1{\textsf{\textbf{#1}}}
%\pdfstringdefDisableCommands{\let\\\textbackslash}
\OnlyDescription  % comment out for implementation details
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\InputIfFileExists{aebdocfmt.def}{\PackageInfo{eq-save}{Inputting aebdocfmt.def}}
    {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax
     \PackageInfo{eq-save}{aebdocfmt.def cannot be found}}
\begin{document}
\def\CMD#1{\textbackslash#1}
  \GetFileInfo{eq-save.sty}
  \title{\textsf{eq-save}: Saving \pkg{exerquiz} quizzes and resuming}
  \author{D. P. Story\\
    Email: \texttt{dpstory@acrotex.net}}
  \date{processed \today}
  \maketitle
  \tableofcontents
  \let\Email\texttt
  \renewenvironment{theglossary}{%
    \let\efill\relax
    \begin{itemize}}{\end{itemize}}
   \value{GlossaryColumns}=1
  \DocInput{eq-save.dtx}
\IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute
    \texttt{makeindex -s gind.ist -o eq-save.ind eq-save.idx} on the command line and recompile
    \texttt{eq-save.dtx}.}
\IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute
    \texttt{makeindex -s gglo.ist -o eq-save.gls eq-save.glo} on the command line and recompile
    \texttt{eq-save.dtx}.}
\end{document}
%</driver>
% \fi
% \MakeShortVerb{|}
% \InputIfFileExists{aebdonotindex.def}{\PackageInfo{web}{Inputting aebdonotindex.def}}
%    {\PackageInfo{web}{cannot find aebdonotindex.def}}
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%    The option \IndexOpt{devmode}\opt{devmode} does not require the user to enter his or  her name
%    in the name field, if the \cs{nameField} and \cs{BeginNoPeeking} commands are present; otherwise it has no effect.
%    The \IndexOpt{!devmode}\opt{!devmode} is the logical negation of \opt{devmode}, its the same as no option
%    passed.
%    \begin{macrocode}
\DeclareOption{devmode}{\def\devMode{true}}
\DeclareOption{!devmode}{\def\devMode{false}}
\def\devMode{false}
\ProcessOptions
\RequirePackage{exerquiz}[2017/07/30]
\RequirePackage{atbegshi}
\edef\ap@restoreCats{%
  \catcode`\noexpand\"=\the\catcode`\"\relax
  \catcode`\noexpand\,=\the\catcode`\,\relax
  \catcode`\noexpand\(=\the\catcode`\(\relax
  \catcode`\noexpand\!=\the\catcode`\!\relax
}
\@makeother\"\@makeother\,\@makeother\(\@makeother\!
%    \end{macrocode}
%   \changes{v1.0}{2017/08/12}{Wrote initial documentation, set version as v1.0}
%   \section{Introduction}
%   Work, on what ultimately became this package, was initiated by a user Manfred~S. He and his team were writing
%   practice documents for their students that included \env{oQuestion}, \env{shortquiz}, and \env{quiz} environments from the
%   \pkg{exerquiz} package. It was desired for the student to enter his/her name first, then begin the practice document.
%   After a while, the student may become tired or disinterested, so he/she save the document.
%   He wanted to take advantage of the ability of Adobe Acrobat Reader 11 or greater (DC and beyond) to save the form data,
%   something it couldn't do prior. Later the student becomes motivated and returns to the document to continue working through
%   the questions.
%
%   Sounds good, but wait! \env{oQuestion}, \env{shortquiz}, and \env{quiz} environments were not designed
%   for this. There are a lot of JavaScript variables, arrays, objects containing information about the quizzes as they are
%   attempted. This data is normally disposed of when the reader takes another quiz. Certainly, as the user saves and closes
%   the document all variables, arrays, objects are lost. This package attempts to save all essential information when
%   the user saves the document, the information is saved in a hidden text field. Upon opening the document again,
%   the essential data is restored.
%
%   A professor might want this feature for a tutorial. The tutorial (rather long) can have questions from
%   \env{oQuestion}, \env{shortquiz}, and \env{quiz} environments. The student can save, and return to the
%   reading of the tutorial and the answering of the questions. A self-paced tutorial does not need a name field
%   to act as a `gatekeeper' to the document, as is the need of Manfred~S.
%
%
%   \section{Commands of this package}
%   The \DescribeMacro{\nameField}\cs{nameField} command inserts a text field into which the student enters
%   his name; otherwise, he cannot continue to the next page. Changing your name after you've begun to work
%   on the questions clears the answer to all quizzes; this is an annoyance factor, a feeble attempt to reduce
%   cheating. When \cs{nameField} is used, the top of the next page should be \cs{BeginNoPeeking}.
%    \begin{macrocode}
\newcommand\nameField[4][]{\textField[#1
  \AAkeystroke{chk4PassToQuestions(event);}
  \AAformat{if(typeof oRecordOfQuizData=="undefined") \r\t
    var oRecordOfQuizData=new Object();\r
    try{IhrNameFormat(event);}catch(e){}
  }]{#2}{#3}{#4}}
%    \end{macrocode}
%    \DescribeMacro{\hiddenScoreData}is a text field that has zero dimensions, it takes up no (horizontal) {\TeX} space, and is hidden.
%    This field, when the document is saved, receive all essential quiz data. It is read again when the document
%    is opened to restore the quiz data. We give this field an initial value, for otherwise, the PDF viewer will
%    not scan this field on opening.
%    \begin{macrocode}
\newcommand{\hiddenScoreData}{\makebox[0pt][l]{%
\textField[\F\FHidden\V{({})}\DV{({})}\AAformat{%
  if(typeof oRecordOfQuizData=="undefined")\r\t
  oRecordOfQuizData={};}\BG{}\BC{}]{holdScoreData}{0bp}{0bp}}}
\AtBeginShipoutFirst{\hiddenScoreData}
%    \end{macrocode}
%    We place this field on the first page, upper left corner. It will be scanned by the PDF viewer (Reader)
%    and it will define the object \texttt{oRecordOfQuizData} that will hold essential quiz data.
%
%    \paragraph*{Displaying and clearing results} As the user/student progresses through the document, he
%    can see his success rate by viewing the text fields below.
%
%    The \DescribeMacro{\sooField}\cs{sooField} (soo=score out of) displays the combined score: `12 out of 16', for example.
%    The phase may be redefined for language purposes by redeclaring the command \DescribeMacro{\declareScorePhrase}\cs{declareScorePhrase}, the English
%    declaration is \verb~\declareScorePhrase{#1+"\space\eqOutOf\space"+#2}~, see the documentation above for this command.
%
%    The \DescribeMacro{\sField}\cs{sField} is one the field that holds only the score, while
%    \DescribeMacro{\ooField}\cs{ooField} holds the `out of' value.
%    \begin{macrocode}
\newcommand{\sField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
  {\eqsroot.Score}{#2}{#3}}
\newcommand{\ooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
  {\eqsroot.OutOf}{#2}{#3}}
\newcommand{\sooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
   {\eqsroot.ScoreComb}{#2}{#3}}
%    \end{macrocode}
%    Now we do the same thing for the points score. \DescribeMacro{\psField}\cs{psField} holds the total
%    number of points awarded; \DescribeMacro{\pooField}\cs{pooField} is the total number of points;
%    \DescribeMacro{\psooField}\cs{psooField} is the `points out of' field.
%    \begin{macrocode}
\newcommand{\psField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
  {\eqsroot.ptScore}{#2}{#3}}
\newcommand{\pooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
  {\eqsroot.ptOutOf}{#2}{#3}}
\newcommand{\psooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
   {\eqsroot.ptScoreComb}{#2}{#3}}
%    \end{macrocode}
%    We supply a global clearing button. This button clear all results in the document, questions posed
%    by \env{oQuestions}, \env{shortquiz}, and \env{quiz} environments.
%    \begin{macrocode}
\newcommand{\clearAllField}[3][]{\pushButton[\CA{Clear All}#1
  \AAmouseup{clearAllSQElements();}]{globalClearAll}{#2}{#3}}
%    \end{macrocode}
%
%   \paragraph*{Set action keys} We modify certain action keys to save the information we'll need later when the document is saved.
%   The \cs{setActionKeys} is a new feature of \pkg{exerquiz} (2017/07/29) and is used to add JavaScript
%   actions to certain key elements of the quiz environments. This is how we are able to preserve and later
%   restore the quiz data. The command \DescribeMacro{\eqsSetActionKeys}\cs{eqsSetActionKeys} is expanded
%   when \cs{DeclareReportRootName} is expanded. If the author declares a new root, the \cs{setActionKeys},
%   which depend on \cs{eqsroot}, must be re-emitted.
%    \begin{macrocode}
\newcommand{\eqsSetActionKeys}{%
  \setActionKeys{%
%    \end{macrocode}
%    (2018/04/07) Removing \cs{AddAAFormat}, there is no test for null later in the code.
%    \changes{v1.1}{2018/04/07}{No need for the change to \string\cs{AddAAFormat}}
%    \begin{macrocode}
%    \AddAAFormat{\if\eqQuizType\isSQZ
%      if (typeof event.target.isCorrect=="undefined")\r\t
%      event.target.isCorrect=null;\fi}
    \AddAAKeystroke{\if\eqQuizType\isSQZ
      event.target.isCorrect=(retn)?1:0;\r\t
      oRecordOfQuizData[event.target.name]=event.target.isCorrect;\r\t
      cntCorrectResponses();\fi}
    \AddAAMouseUpMC{\if\eqQuizType\isSQZ
      event.target.isCorrect=\Ans@choice;\r
      oRecordOfQuizData[event.target.name]=event.target.isCorrect;\r
      cntCorrectResponses();\fi}
    \AddAAMouseUpMS{\if\eqQuizType\isSQZ
      event.target.isCorrect=\Ans@choice;\r
      oRecordOfQuizData[event.target.name]=event.target.isCorrect;\r
      cntCorrectResponses();\fi}
  }%
}
%    \end{macrocode}
% \paragraph*{Modify actions of Begin Quiz and End Quiz} These actions may be modified using the
% two commands \cs{postInitQuiz} and \cs{postSubmitQuiz}. They are used to insert the \texttt{cntCorrectResponses()} call
% into the action performed by the `Begin Quiz' and `End Quiz' buttons. \emph{It is assumed the document
% author is not otherwise using these two commands.}
%    \begin{macrocode}
\def\postInitQuiz{%
  var f=this.getField("ScoreData.\oField");\r
  f.value="0;0;0;0";\r
  cntCorrectResponses();}
\def\postSubmitQuiz{%
  oRecordOfQuizData["ScoreData.\oField"]=%
    [1*Score,1*NQuestions,1*ptScore,1*NPointTotal];\r\t\t
  cntCorrectResponses();\r
}
%    \end{macrocode}
%   \paragraph*{Open Page Action} We add a page open event to restore the data as needed. We only do this once
%   per document session. The script used in contained in the command \DescribeMacro\restoreQD\cs{restoreQD}.
%   \changes{v1.2.3}{2019/27/07}{Made the open doc script into a macro \string\cs{resoreQD}}
%   \changes{v1.2.4}{2019/08/01}{Changed to page open}
%   \changes{v1.2.5}{2019/08/07}{added dirty=false to \string\cs{restoreQD}}
%    \begin{macrocode}
\def\restoreQD{if(!restoreQuizData.hasRestoredData)\r\t
  var rqdTO=(app.setTimeOut("try{restoreQuizData()}catch(e){};%
  app.clearTimeOut(rqdTO);%
  restoreQuizData.hasRestoredData=true;dirty=false;",1000));}
%\addToDocOpen{\JS{\restoreQD}}
\thisPageAction{\JS{\restoreQD}}{}
%\thisPageAction{\JS{if(!restoreQuizData.hasRestoredData)\r\t
%  var rqdTO=(app.setTimeOut("restoreQuizData();%
%  app.clearTimeOut(rqdTO);%
%  restoreQuizData.hasRestoredData=true",1000));}}{}
%    \end{macrocode}
%   \paragraph*{Action prior to saving} It is important to save the quiz data, we can only do that if we save
%   it to a field, the value of the field will be saved. We save the data to a hidden text field
%   \texttt{"holdScoreData"}, this field is required.
%    \begin{macrocode}
\begin{willSave}
isAQuizUnfinishedAtSave();
if (typeof oRecordOfQuizData !="undefined") collectQuizData();
\end{willSave}
%    \end{macrocode}
% \paragraph*{No peeking} If the \cs{nameField} command is used,
% use \DescribeMacro{\BeginNoPeeking}\cs{BeginNoPeeking} command can optionally appear on the
% first page that contain content the author does not want the user to peek at. The
% JavaScript string \DescribeMacro{\EnterNameFirstMsg}\cs{EnterNameFirstMsg} appears in the alert
% box if the user goes to a forbidden page without first enther his name into the \cs{nameField}.
% May be redefined for local languages.
%    \begin{macrocode}
\flJSStr[noquotes,noparens]{\EnterNameFirstMsg}{You must enter
  your name first!}
\def\declareScorePhrase#1{\def\dclScorePhse(##1)(##2){#1}}
\declareScorePhrase{#1+"\space\eqOutOf\space"+#2}
\def\BeginNoPeeking{\def\IhrNamePO{\thisPageAction{%
  \JS{if(!_docDevMode&&!_passToQuestions){\r\t
    this.pageNum=0;\r\t
    NoNameMsg=app.setTimeOut("app.alert('\EnterNameFirstMsg');%
    app.clearTimeOut(NoNameMsg);",25);}}}{}}%
%    \end{macrocode}
% Page option for this page
%    \begin{macrocode}
  \IhrNamePO
%    \end{macrocode}
% Page open for all other pages
%    \begin{macrocode}
  \AtBeginShipout{\IhrNamePO}%
}
%    \end{macrocode}
%     The command \DescribeMacro{\DeclareReportRootName}\cs{DeclareReportRootName} may never need to be used, but just
%     in case, it can only be used once in the preamble. It names the parent (or root) name of the text fields that
%     will contain the running summary of the user's efforts in the document. The default root name is \texttt{SUMRY}.
%    \begin{macrocode}
\newcommand{\DeclareReportRootName}[1]{\def\eqsroot{#1}%
  \eqsSetActionKeys}
\DeclareReportRootName{SUMRY}
\@onlypreamble{\DeclareReportRootName}
%    \end{macrocode}
%   One of the problems is the quizzes and shortquizzes are not known when the document is first
%   opened. Normally this is not a problem, but in this application we need to know them. This problem
%   is solved by two events: at the end of the document the list of quizzes is known, it is save to
%   the auxiliary file \texttt{qzlist-\string\jobname.cut}, then this file is input back into the preamble, parsed,
%   and entered into the document level JavaScript through the command \cs{jsCodeForQzs}. The contents
%   of the aux file may look like: \texttt{\string\jsForQzs\space qz1;qz2;oQ1;sQ1;\string\@nil}. The internal command
%   \DescribeMacro{\jsCodeForQzs}\cs{jsCodeForQzs} parses this line at the semicolons; as a result, \cs{jsCodeForQzs}
%   expands to
%\begin{verbatim}
%var qz1=new Object();
%var qz2=new Object();
%var oQ1=new Object();
%var sQ1=new Object();
%\end{verbatim}
%    \begin{macrocode}
\let\jsCodeForQzs\@empty\def\semiColon{;}\let\itsNonEmpty=0
\def\jsForQzs#1\@nil{\jsForQzsi#1;;\@nil}
\def\jsForQzsi#1;#2\@nil{\def\argii{#2}\ifx\argii\semiColon
  \let\eqs@next\relax\else
  \let\itsNonEmpty=1%
  \g@addto@macro\jsCodeForQzs{var #1=new Object();^^J}%
  \def\eqs@next{\jsForQzsi#2\@nil}\fi\eqs@next}
%    \end{macrocode}
%    We input the file that is created at the end of the document. We do a \cs{AtEndOfPackage} because
%    the command \cs{jsCodeForQzs} must be well defined by the time the document JavaScript are inserted.
%    \begin{macrocode}
\AtEndOfPackage{\InputIfFileExists{qzlist-\jobname.cut}{}{}}
%    \end{macrocode}
%   At the end of the document after all quizzes and shortquizzes are known, we save them to
%   the file \texttt{qzlist-\string\jobname.cut}, they are then input in the preamble.
%   The \DescribeMacro{\saveListofQzs}\cs{saveListofQzs} writes the name of each quiz to an
%   semi-colon delimited list.
%    \begin{macrocode}
\let\jsForQzsHold\@empty
\let\cListOfQuizNames\@empty
\let\cListOfSQuizNames\@empty
\let\eqsHandleOpen=0
\def\saveListofQzs{%
  \ifx\ListOfQuizNames\@empty\else
    \let\jsForQzsHold\@empty
    \let\cListOfQuizNames\@empty
    \edef\ListOfQuizNames{\expandafter\@gobble\ListOfQuizNames}
    \immediate\openout\CommentStream=qzlist-\jobname.cut
    \let\eqsHandleOpen=1
      \expandafter\@for\expandafter
        \@qz\expandafter:\expandafter=\ListOfQuizNames\do{%
        \edef\@tmpExp{\noexpand
          \g@addto@macro\noexpand\jsForQzsHold{\@qz;}}\@tmpExp
        \edef\@tmpExp{\noexpand
          \g@addto@macro\noexpand\cListOfQuizNames{,"\@qz"}}\@tmpExp
      }%
  \fi
  \ifx\ListOfSQuizNames\@empty\else
    \if\eqsHandleOpen0
      \let\jsForQzsHold\@empty
      \immediate\openout\CommentStream=qzlist-\jobname.cut
      \let\eqsHandleOpen=1\fi
    \let\cListOfSQuizNames\@empty
    \edef\ListOfSQuizNames{\expandafter\@gobble\ListOfSQuizNames}
    \expandafter\@for\expandafter\@qz
      \expandafter:\expandafter=\ListOfSQuizNames\do{%
      \edef\@tmpExp{\noexpand\g@addto@macro\noexpand
        \jsForQzsHold{\@qz;}}\@tmpExp
        \edef\@tmpExp{\noexpand
          \g@addto@macro\noexpand\cListOfSQuizNames{,"\@qz"}}\@tmpExp
    }%
    \immediate\write\CommentStream{%
      \string\jsForQzs\space\jsForQzsHold\string\@nil}
  \fi
  \if\eqsHandleOpen1
    \ifx\ListOfQuizNames\@empty\else
      \immediate\write\CommentStream{%
        \string\def\string\cListOfQuizNames{\expandafter
          \@gobble\cListOfQuizNames}}
    \fi
    \ifx\ListOfSQuizNames\@empty\else
      \immediate\write\CommentStream{%
        \string\def\string\cListOfSQuizNames{\expandafter
          \@gobble\cListOfSQuizNames}}
    \fi
  \fi
}
%    \end{macrocode}
%   Expand \cs{saveListofQzs} at the end of the document.
%    \begin{macrocode}
\AtEndDocument{\saveListofQzs}
%    \end{macrocode}
%   \section{Document JavaScript}
%    \begin{macrocode}
\dlJSStr{\eqerrUnfinishQuizAtSave}
  {One of your quizzes is not finished, you will lose those responses.}
\begin{insDLJS}{gcnt}{eq-save: Save and Resume JS support}
var _passToQuestions=false;
var oRecordOfQuizData;
var _docDevMode=\devMode;
var aQzList=new Array(\cListOfQuizNames);
var aSqList=new Array(\cListOfSQuizNames);
\jsCodeForQzs%
cntCorrectResponses.nCorrectInDoc=0;
cntCorrectResponses.nOutOfInDoc=0;
cntCorrectResponses.nPtsCorrectInDoc=0;
cntCorrectResponses.nPtsOutOfInDoc=0;
%    \end{macrocode}
%\leavevmode\IndexJS{cntCorrectResponses()}is the workhorse of \pkg{eq-save}. It keeps tabs on the
%total number of correct answers and the total number of questions. All \env{shortquiz}es are known immediately,
%but results from \env{quiz} environments are not known until the student presses the `End Quiz' button.
%    \begin{macrocode}
function cntCorrectResponses() {
  var f=this.getField("\eqsroot");
  if (f==null) return;
  var g=f.getArray();
%    \end{macrocode}
%  \textbf{Naming convention:}\\\null\qquad\texttt{\string\eqsroot.ScoreComb},
%  \texttt{\string\eqsroot.Score}, \texttt{\string\eqsroot.OutOf}\\[3pt]
%  It is expected that the length \texttt{g.length=1\string|2\string|3}\\\null\quad
%  if \texttt{g.length=1}, we expect the field to be \texttt{\string\eqsroot.ScoreComb},\\\null\quad
%  if \texttt{g.length=2}, we expect \texttt{\string\eqsroot.Score}
%    and \texttt{\string\eqsroot.OutOf}, and\\\null\quad
%  if \texttt{g.length=3}, report all three
%    \begin{macrocode}
  var fld1="\eqsroot.Score";
  var fld2="\eqsroot.OutOf";
  var fld3="\eqsroot.ScoreComb";
  var fld4="\eqsroot.ptScore";
  var fld5="\eqsroot.ptOutOf";
  var fld6="\eqsroot.ptScoreComb";
  cntCorrectResponses.nCorrectInDoc=0;
  cntCorrectResponses.nOutOfInDoc=0;
  cntCorrectResponses.nPtsCorrectInDoc=0;
  cntCorrectResponses.nPtsOutOfInDoc=0;
  var pos,baseName;
  for (var i=0; i<this.numFields; i++) {
    fname=this.getNthFieldName(i);
    baseName=fname+"..";
    pos=baseName.indexOf(".");
    baseName=baseName.substring(pos+1);
    pos=baseName.indexOf(".");
    baseName=baseName.substring(0,pos);
    if (aQzList.indexOf(baseName)!=-1) {
      continue;
    }
    pos=fname.indexOf(".");
    var root=fname.substring(0,pos);
    if (root=="obj"|root=="grpobj") {
      var f=this.getField(fname);
%    \end{macrocode}
%    Removing test for isCorrect, it can lead to some field not being
%    included when they should.
%    \changes{v1.1}{2018/04/07}{Removed test for isCorrect}
%    \begin{macrocode}
%      if (typeof f.isCorrect=="undefined") continue;
      cntCorrectResponses.nOutOfInDoc+=1;
      if (f.isCorrect==1) {
          cntCorrectResponses.nCorrectInDoc+=1;
      }
    } else if (root=="mcq"||root=="mck"){
        continue;
      } else if (fname.substring(0,2)=="mc") {
%    \end{macrocode}
%      For MC within a quiz, there are two fields, name as indicated above.
%      if the second field exists, we ignore this field and continue.
%    \begin{macrocode}
      var tst4qz="mcq"+fname.substring(2);
      var otst4qz=this.getField(tst4qz);
      if (otst4qz!=null)continue;
%    \end{macrocode}
%     Distinguish between multiple choice and multiple selection
%    \begin{macrocode}
      var f=this.getField(fname);
      var aResults=fname.match(/\./g);
      if (aResults.length>2) {
        // multiple selection
        if (f.exportValues[0][0]==1) {
          cntCorrectResponses.nOutOfInDoc+=1;
          if (f.isBoxChecked(0)) {
            cntCorrectResponses.nCorrectInDoc+=1;
          }
        }
      } else {
        // multiple choice
        cntCorrectResponses.nOutOfInDoc+=1;
        if (f.value[0]==1) {
            cntCorrectResponses.nCorrectInDoc+=1;
        }
      }
    }
  }
  addInQuizResults();
%    \end{macrocode}
%    We now display the totals results.
%    \begin{macrocode}
  f=this.getField(fld1);
  if(f!=null)f.value=cntCorrectResponses.nCorrectInDoc;
  f=this.getField(fld2);
  if(f!=null)f.value=cntCorrectResponses.nOutOfInDoc
  var f=this.getField(fld3);
  if (f!=null)f.value=(\dclScorePhse(cntCorrectResponses.nCorrectInDoc)%
(cntCorrectResponses.nOutOfInDoc));
  f=this.getField(fld4);
  if(f!=null)f.value=cntCorrectResponses.nPtsCorrectInDoc;
  f=this.getField(fld5);
  if(f!=null)f.value=cntCorrectResponses.nPtsOutOfInDoc
  var f=this.getField(fld6);
  if (f!=null)
    f.value=(\dclScorePhse(cntCorrectResponses.nPtsCorrectInDoc)%
(cntCorrectResponses.nPtsOutOfInDoc));
}
%    \end{macrocode}
%   \leavevmode\IndexJS{addInQuizResults()} is called by \texttt{cntCorrectResponses()} to add in the results
%   from the quizzes, if known. Because `Begin Quiz' and `End Quiz' can be links (not recommended) we save
%   the results of the quiz as the value of the field \texttt{ScoreData.\ameta{quizName}}. \pkg{exerquiz}
%   package save the quiz data in the form \texttt{"Score;\penalty0NQuestions;\penalty0ptScore;\penalty0NPointTotal"}.
%   This string can be split and the individual
%   values may be retrieved.
%    \begin{macrocode}
function addInQuizResults() {
  var results,value,score,outof;
%    \end{macrocode}
% Coming into this function, the calculations so far are for \env{oQuestion} and \env{shortquiz} environments, these normally
% don't have points assigned, and we do not support them if they do. Instead, we'll assign them to the points
%    \begin{macrocode}
  cntCorrectResponses.nPtsCorrectInDoc=%
cntCorrectResponses.nCorrectInDoc;
  cntCorrectResponses.nPtsOutOfInDoc=cntCorrectResponses.nOutOfInDoc;
  for (var i=0; i<aQzList.length; i++) {
    var f=this.getField("ScoreData."+aQzList[i]);
    if (f!=null) {
      if (f.value!="") {
        aTmp=f.value.split(";");
        cntCorrectResponses.nCorrectInDoc+=(1*aTmp[0]);
        cntCorrectResponses.nOutOfInDoc+=(1*aTmp[1]);
        cntCorrectResponses.nPtsCorrectInDoc+=(1*aTmp[2]);
        cntCorrectResponses.nPtsOutOfInDoc+=(1*aTmp[3]);
      }
    }
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{clearAllSQElements()} clears all the quiz fields (all types). Much of the code
%   here is copied from \pkg{exerquiz}.
%    \begin{macrocode}
function clearAllSQElements() {
  var fname;
  // clear any short quizzes and any supportive elements
  for (var i=0; i<aSqList.length; i++) {
    ProcessIt = false;
    if ( typeof eval(aSqList[i])== "undefined" )
      eval(aSqList[i])= new Object();
    if (typeof appAlerts[aSqList[i]] == "undefined")
      appAlerts[aSqList[i]] = new Object();
    this.resetForm(new Array("mc."+aSqList[i],"obj."+aSqList[i],%
"tally."+aSqList[i],"grpobj."+aSqList[i]));
    var f = this.getField("obj."+aSqList[i]);
    if ( f != null ) f.strokeColor=\ifx\defaultColorJSLoc\@empty%
\defaultColorJS\else\defaultColorJSLoc\fi;
    f = this.getField("grpobj."+aSqList[i]);
    if ( f != null ) f.strokeColor=\ifx\defaultColorJSLoc\@empty%
\defaultColorJS\else\defaultColorJSLoc\fi;
    f = this.getField("rbmarkup."+aSqList[i]);
    if ( f != null ) f.display=display.hidden;
    eval(aSqList[i]).Grp = {};
    appAlerts[aSqList[i]].bAfterValue=false;
    ProcessIt=true;
  }
  isAQuizUnfinished.check=true;
  // clear any quizzes and any supportive elements
  for (var i=0; i<aQzList.length; i++) {
    InitializeQuiz(aQzList[i],1);
    aQuizControl[aQzList[i]] = 0;
  }
%    \end{macrocode}
%   Here's where we clear all the field with parent names of
%   \cs{eqsroot} (\texttt{SUMRY}), \texttt{holdScoreData}, and \texttt{ScoreData}.
%    \begin{macrocode}
  this.resetForm(["\eqsroot","holdScoreData","ScoreData"]);
  oRecordOfQuizData=new Object();
}
%    \end{macrocode}
%   \leavevmode\IndexJS{chk4PassToQuestions()} This function is used in the keystroke and format
%   phase of the \cs{nameField} command. If the student/user clears the field or changes the value
%   of the field once it has been committed, \texttt{chk4PassToQuestions()} then calls \texttt{clearAllSQElements()}
%   to clear all fields.
%    \begin{macrocode}
chk4PassToQuestions.entered=false;
function chk4PassToQuestions(event) {
  if(event.willCommit) {
    if (chk4PassToQuestions.entered) {
      _passToQuestions=false;
      clearAllSQElements();
      this.dirty=false;
      return;
    }
    if(event.value!="") {
      var value=""+event.value;
      value = value.replace(/\s/g,"");
      if(value==null || value.length==0) {
        _passToQuestions=false;
        chk4PassToQuestions.entered=false;
      } else {
        _passToQuestions=true;
        chk4PassToQuestions.entered=true;
        clearAllSQElements();
        this.dirty=false;
      }
    }
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{collectQuizData()} is called by the \texttt{willSave} event. It save
%   the object \texttt{oRecordOfQuizData} to the field \texttt{holdScoreData} as a string.
%    \begin{macrocode}
function collectQuizData() {
  var f=this.getField("holdScoreData");
  f.value=(oRecordOfQuizData.toSource());
}
%    \end{macrocode}
%   \leavevmode\IndexJS{restoreQuizData()} is called when the document is opened and attempts to
%   transfer the value of \texttt{holdScoreData} back into \texttt{oRecordOfQuizData}.
%   \changes{v1.2}{2019/07/02}{Added ProbDist array}
%   \changes{v1.2.1}{2019/07/05}{Added RightWrong array}
%    \begin{macrocode}
restoreQuizData.hasRestoredData=false;
function restoreQuizData() {
  var f=this.getField("holdScoreData");
  try{oRecordOfQuizData=eval(f.value);}catch(e){return;}
  for (fname in oRecordOfQuizData) {
    f=this.getField(fname);
    if (typeof oRecordOfQuizData[fname]=="object") {
      // name of field is endQuiz.qzname
      var pos=fname.indexOf(".");
      var qzName=fname.substring(pos+1);
      var qzRoot=fname.substring(0,pos);
 %    \end{macrocode}
%    (2021/02/17) Conditional to handle \texttt{ScoreData} only, this enables other
%    data that are objects to be present in \texttt{oRecordOfQuizData}.
%   \changes{v1.2}{2021/02/17}{Added conditional to process \texttt{ScoreData} only}
%   \changes{v1.2.5}{2021/04/27}{Added a switch (JS) for more complex decision within
%   \string\texttt{restoreQuizData}}
%    \begin{macrocode}
     switch(qzRoot) {
        case "ScoreData":
          lstOfQuizzes[qzName]=eval(qzName);
          Score=1*oRecordOfQuizData[fname][0];
          NQuestions=1*oRecordOfQuizData[fname][1];
          ptScore=1*oRecordOfQuizData[fname][2];
          NPointTotal=1*oRecordOfQuizData[fname][3];
          var h=this.getField("ScoreData."+qzName);
          h.value=Score+";"+NQuestions+";"+ptScore+";"+NPointTotal;
          break;
        case "ProbDist":
          ProbDist=eval(oRecordOfQuizData[fname]);
          break;
        case "RightWrong":
          RightWrong=eval(oRecordOfQuizData[fname]);
          break;
        default:
          console.println("name not recognized:"+fname);
      }
    } else f.isCorrect=oRecordOfQuizData[fname];
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{IhrNameFormat()} is the format script for the \cs{nameField} command.
%    \begin{macrocode}
function IhrNameFormat(event){
  if(event.value!="") {
    var value=""+event.value;
    value = value.replace(/\s/g,"");
    if(value==null || value.length==0) {
      _passToQuestions=false;
      chk4PassToQuestions.entered=false;
    } else {
      _passToQuestions=true;
      chk4PassToQuestions.entered=true;
      this.dirty=false;
    }
  } else {
  	chk4PassToQuestions.entered=false;
  	_passToQuestions=false;
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{isAQuizUnfinishedAtSave()} is a variation on the JavaScript function
%   \texttt{isAQuizUnfinished} defined in \pkg{exerquiz}. When there is an unfinished quiz
%   and the user saves the document, this function (call by \texttt{willSave}) warns the user
%   that he will lose the answer entered into the quiz. It is too late to stop the save, there
%   is no JavaScript command for doing that.
%    \begin{macrocode}
function isAQuizUnfinishedAtSave()
{
    for ( var qtfield in aQuizControl )
        if ( aQuizControl[qtfield] == 1 )
        {
            eqAppAlert(\eqerrUnfinishQuizAtSave, 3);
            return false;
        }
    return true;
}
\end{insDLJS}
%    \end{macrocode}
%    \begin{macrocode}
\ap@restoreCats
%</package>
%    \end{macrocode}
\endinput