From 05d9e348e9ce7fb895782424da35d989a0396a44 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 3 Aug 2020 12:15:38 +0900 Subject: thorshammer (new) --- texmf-dist/doc/latex/thorshammer/README.md | 33 + .../doc/latex/thorshammer/action-sequences.zip | Bin 0 -> 8120 bytes texmf-dist/doc/latex/thorshammer/container.pdf | Bin 0 -> 49921 bytes texmf-dist/doc/latex/thorshammer/container.tex | 94 + .../latex/thorshammer/examples/cfgs/thexcfg1.tex | 152 ++ .../thorshammer/examples/cfgs/thexcfg2-star.tex | 168 ++ .../latex/thorshammer/examples/cfgs/thexcfg2.tex | 158 ++ .../thorshammer/examples/cfgs/thorsclass1.cfg | 43 + .../thorshammer/examples/cfgs/thorsclass2.cfg | 44 + .../thorshammer/examples/cfgs/thorsclass3-star.cfg | 9 + .../thorshammer/examples/cfgs/thorsclass3.cfg | 8 + .../thorshammer/examples/cfgs/thorsclassx.cfg | 6 + .../doc/latex/thorshammer/examples/misc/thexrt.tex | 319 +++ .../latex/thorshammer/examples/nosolns/thexb.tex | 147 ++ .../latex/thorshammer/examples/nosolns/thexbd.tex | 146 ++ .../latex/thorshammer/examples/nosolns/thexr.tex | 175 ++ .../latex/thorshammer/examples/nosolns/thexrt.tex | 222 ++ .../latex/thorshammer/examples/nosolns/thexub.tex | 147 ++ .../latex/thorshammer/examples/nosolns/thexuc.tex | 152 ++ .../examples/ordinary-option/get-hash-string.tex | 35 + .../ordinary-option/quiz-pwd-to-correct-AA.tex | 190 ++ .../ordinary-option/quiz-pwd-to-correct-AR.tex | 174 ++ .../doc/latex/thorshammer/folder-js/aeb-reader.js | 50 + .../doc/latex/thorshammer/folder-js/aeb_pro.js | 158 ++ .../doc/latex/thorshammer/install-action-seq.pdf | Bin 0 -> 345357 bytes .../system-scripts/standalone/altclasspaths.txt | 1 + .../system-scripts/standalone/cpquizzes.ps1 | 51 + .../system-scripts/standalone/mkcfg.ps1 | 71 + .../system-scripts/standalone/mkfolders.ps1 | 60 + .../system-scripts/standalone/rmquizzes.ps1 | 51 + .../system-scripts/standalone/runps1.bat | 2 + .../system-scripts/standalone/sample-list.csv | 3 + .../system-scripts/thors-structure/runps1.bat | 2 + .../system-scripts/thors-structure/sample-vars.txt | 8 + .../system-scripts/thors-structure/thmclass.ps1 | 713 ++++++ .../doc/latex/thorshammer/terminate-batch.pdf | Bin 0 -> 25334 bytes .../doc/latex/thorshammer/terminate-batch.tex | 24 + texmf-dist/doc/latex/thorshammer/thmclass.pdf | Bin 0 -> 207656 bytes texmf-dist/doc/latex/thorshammer/thmclass.tex | 970 ++++++++ texmf-dist/doc/latex/thorshammer/thors-the-man.pdf | Bin 0 -> 1388897 bytes texmf-dist/doc/latex/thorshammer/thors-the-man.tex | 2178 ++++++++++++++++++ texmf-dist/doc/latex/thorshammer/thorshammer.pdf | Bin 0 -> 6227257 bytes .../source/latex/thorshammer/thorshammer.dtx | 2398 ++++++++++++++++++++ .../source/latex/thorshammer/thorshammer.ins | 62 + texmf-dist/tex/latex/thorshammer/thorshammer.cfg | 52 + texmf-dist/tex/latex/thorshammer/thorshammer.sty | 1100 +++++++++ 46 files changed, 10376 insertions(+) create mode 100644 texmf-dist/doc/latex/thorshammer/README.md create mode 100644 texmf-dist/doc/latex/thorshammer/action-sequences.zip create mode 100644 texmf-dist/doc/latex/thorshammer/container.pdf create mode 100644 texmf-dist/doc/latex/thorshammer/container.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg1.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2-star.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass1.cfg create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass2.cfg create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3-star.cfg create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3.cfg create mode 100644 texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclassx.cfg create mode 100644 texmf-dist/doc/latex/thorshammer/examples/misc/thexrt.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/nosolns/thexb.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/nosolns/thexbd.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/nosolns/thexr.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/nosolns/thexrt.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/nosolns/thexub.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/nosolns/thexuc.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/ordinary-option/get-hash-string.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AA.tex create mode 100644 texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AR.tex create mode 100644 texmf-dist/doc/latex/thorshammer/folder-js/aeb-reader.js create mode 100644 texmf-dist/doc/latex/thorshammer/folder-js/aeb_pro.js create mode 100644 texmf-dist/doc/latex/thorshammer/install-action-seq.pdf create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/altclasspaths.txt create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/cpquizzes.ps1 create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkcfg.ps1 create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkfolders.ps1 create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/rmquizzes.ps1 create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/runps1.bat create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/standalone/sample-list.csv create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/runps1.bat create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/sample-vars.txt create mode 100644 texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/thmclass.ps1 create mode 100644 texmf-dist/doc/latex/thorshammer/terminate-batch.pdf create mode 100644 texmf-dist/doc/latex/thorshammer/terminate-batch.tex create mode 100644 texmf-dist/doc/latex/thorshammer/thmclass.pdf create mode 100644 texmf-dist/doc/latex/thorshammer/thmclass.tex create mode 100644 texmf-dist/doc/latex/thorshammer/thors-the-man.pdf create mode 100644 texmf-dist/doc/latex/thorshammer/thors-the-man.tex create mode 100644 texmf-dist/doc/latex/thorshammer/thorshammer.pdf create mode 100644 texmf-dist/source/latex/thorshammer/thorshammer.dtx create mode 100644 texmf-dist/source/latex/thorshammer/thorshammer.ins create mode 100644 texmf-dist/tex/latex/thorshammer/thorshammer.cfg create mode 100644 texmf-dist/tex/latex/thorshammer/thorshammer.sty (limited to 'texmf-dist') diff --git a/texmf-dist/doc/latex/thorshammer/README.md b/texmf-dist/doc/latex/thorshammer/README.md new file mode 100644 index 00000000..f4c622a1 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/README.md @@ -0,0 +1,33 @@ +The thorshammer Package +Author: D. P. Story +Dated: 2020-01-13 + +WARNING: Adobe Acrobat DC or Adobe Acrobat XI is required for +post PDF-creation. Any PDF-creator application is supported. + +This package implements an idea by Thorsten G. for assessment +using PDF quizzes produced by the exerquiz package. Thorsten not +only wanted to pose multiple choice, multiple selection, and +fill-in type questions, but also wanted to ask extended response +questions that would be manually evaluated. Once the quiz is +graded, the instructor may optionally pass the quizzes through +an Acrobat action sequence to extract the student's name and +grade from the quizzes. The extracted information is saved to a +tab-delimited TXT file. The instructor can later merge this file +into a larger spreadsheet. + +Note: Unzip action-sequences.zip to obtain the action-sequences folder. + +If intriguing, install thorshammer and try this workflow. + +Enjoy! + +Now, I must get back to my retirement. + + +D. P. Story +www.acrotex.net +dpstory@uakron.edu +dpstory@acrotex.net + + diff --git a/texmf-dist/doc/latex/thorshammer/action-sequences.zip b/texmf-dist/doc/latex/thorshammer/action-sequences.zip new file mode 100644 index 00000000..d22b7ad3 Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/action-sequences.zip differ diff --git a/texmf-dist/doc/latex/thorshammer/container.pdf b/texmf-dist/doc/latex/thorshammer/container.pdf new file mode 100644 index 00000000..5a128582 Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/container.pdf differ diff --git a/texmf-dist/doc/latex/thorshammer/container.tex b/texmf-dist/doc/latex/thorshammer/container.tex new file mode 100644 index 00000000..4bfb64d7 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/container.tex @@ -0,0 +1,94 @@ +%% +%% This is file `container.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% thorshammer.dtx (with options: `container') +%% +\documentclass{article} +\usepackage[designi]{web} +\usepackage{eforms} +\hypersetup{pdfpagemode=UseAttachments} +%% \previewOn\pmpvOn +\parindent0pt \parskip6pt +\begin{defineJS}{\pbContainer} +var f=this.getField("qzName"); +if(typeof global.RcrdData=="undefined") + global.RcrdData=1; +if(global.RcrdData) { + global.qzName=f.value; + if (global.qzName=="") { + f.value="qzData"; + global.qzName="qzData.txt"; + } else global.qzName=f.value+".txt"; + var d=this.dataObjects; + if (d!=null) { + for(var i=0; i< d.length; i++) + this.removeDataObject(d[i].name); + } + this.createDataObject({ + cName: global.qzName, + cValue: "First\\tSecond\\tPoints\\tTotal\\tGrade" + }); +} +var _path=this.path; +var pos=_path.lastIndexOf("/"); +global.containerPath=_path.substring(0,pos+1); +var f=this.getField("gradedPath"); +var v=f.value; +var pos=v.indexOf(":"); +if(pos!=-1||v[0]=="/") global.gradedPath=v; +else global.gradedPath=global.containerPath+v; +aebTrustedFunctions(this,aebSaveAs); +this.closeDoc(true); +\end{defineJS} +\begin{defineJS}{\clrContainer} +this.resetForm(["qzName","gradedPath"]); +try{ + if (typeof global.qzName!="undefined") + delete global.qzName; global.qzName=""; + if (typeof global.gradedPath!="undefined") + delete global.gradedPath; global.gradedPath=""; + if (typeof global.appndSolns!="undefined") + delete global.appndSolns; global.appndSolns=true; + if (typeof global.RcrdDat!="undefined") + delete global.RcrdDat; global.RcrdDat=true; +} catch(e){} +\end{defineJS} +\begin{document} +This file contains the quiz data as an attachment. Before you +start the batch action \textsf{Thor's way}, build and +\emph{place this file in the class folder of the instructor}. +\begin{center} +\begin{tabular}{rl} +\pushButton[\TU{Fill in the two fields then push this button +before starting the batch sequence}\CA{Push}\AAmouseup{\pbContainer} +]{pbContainer}{}{13bp}&% +\parbox[c]{1.5in}{\textField[\TU{Enter base name of the file that +stores quiz results}]{qzName}{1.5in}{13bp}\vcgBdry[3bp] +\textField[\TU{The path to the folder that will hold the graded +quizzes, it may be a relative or an absolute path} +]{gradedPath}{1.5in}{13bp}}\cgBdry[\columnsep]%\makebox[0pt][l] +{\pushButton[\CA{Clear} + \AAmouseup{\clrContainer}]{clear}{}{13bp}}\\[12pt] + \checkBox[\V{Yes}\DV{Yes}\AAmouseup{% + global.appndSolns=(event.target.isBoxChecked(0)); +}]{AppdSolns}{11bp}{11bp}{Yes}&% +\rlap{Append solutions, if they exist}\\[6pt] +\checkBox[\V{Yes}\DV{Yes}\AAmouseup{% + global.RcrdData=(event.target.isBoxChecked(0)); +}]{RecordData}{11bp}{11bp}{Yes}&% +\rlap{Record class data} +\end{tabular} +\end{center} +Fill in the base name of the file in the text field above. After +you push the button, the file is saved, then start +\textsf{Thor's way} action. After the batch sequence finishes, +this file is opened again. Open the attachments panel and save +the attached file. The file just saved is a tab delimited text +file that can be opened in Microsoft Excel. +\end{document} +\endinput +%% +%% End of file `container.tex'. diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg1.tex b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg1.tex new file mode 100644 index 00000000..613e8bdb --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg1.tex @@ -0,0 +1,152 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[usebatch]{thorshammer} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% Adjust \instrPath \classPath in CFG file as needed +\InputClassData{thorsclass1} + +% \autoCopyOff + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\DeclareQuiz{q1} + +\thQuizHeader + +\noindent\textbf{Instructions:} +\begin{itemize} +\item (For the student) Press `\textsf{Start}' to begin the + quiz, after you've completed the quiz, press + `\textsf{End}'. \emph{Save the document before closing + it}. +\item (For the instructor) Open the document the student has + saved, the `\textsf{Mark It}' and `\textsf{Freeze Quiz}' + are visible. Press the `\textsf{Mark It}' button and the + quiz will be marked. For the extended response questions, + enter the points assigned in the box in the left margin. + At your option, reset the quiz or save the quiz with the + markup. +\end{itemize} + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz the `Thorsten way.'.\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2-star.tex b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2-star.tex new file mode 100644 index 00000000..278c34f7 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2-star.tex @@ -0,0 +1,168 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% Adjust \instrPath \classPath in CFG file as needed +% Two methods illustrated here + +% When a class path uses the second star option, as thorsclass3-star.cfg does, +% additional parsing of each line is needed, in this example, a typical data line +% has the form: *{first}{last}{ID}*{path}. The use of * is optional +\makeatletter +\def\ParseClassLine{\@ifstar + {\def\ISStari{*}\ParseClassLine@i} + {\def\ISStari{}\ParseClassLine@i}} +\def\ParseClassLine@i#1#2#3{\@ifstar + {\def\ISStarii{*}\ParseClassLine@ii{#1}{#2}{#3}} + {\def\ISStarii{}\ParseClassLine@ii{#1}{#2}{#3}}} +\def\ParseClassLine@ii#1#2#3#4{\edef\x{\noexpand + \classMember\ISStari{#1}{#2}\ISStarii{#4}}\x} +\makeatother +\InputFormattedClass[\ParseClassLine]{thorsclass3-star} + +% \autoCopyOff + +%\distrToStudentsOff + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\thQuizHeader + +\noindent\textbf{Instructions:} +\begin{itemize} +\item (For the student) Press `\textsf{Start}' to begin the + quiz, after you've completed the quiz, press + `\textsf{End}'. \emph{Save the document before closing + it}. +\item (For the instructor) Open the document the student has + saved, the `\textsf{Mark It}' and `\textsf{Freeze Quiz}' + are visible. Press the `\textsf{Mark It}' button and the + quiz will be marked. For the extended response questions, + enter the points assigned in the box in the left margin. + At your option, reset the quiz or save the quiz with the + markup. +\end{itemize} + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz the `Thorsten way.'.\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer +\end{document} \ No newline at end of file diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2.tex b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2.tex new file mode 100644 index 00000000..b2ade145 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thexcfg2.tex @@ -0,0 +1,158 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} +\useMCCircles + +% Neither of the two CFG files here uses the second star option, see theexcfg2-star.tex +% Adjust \instrPath \classPath in CFG file as needed +% Two methods illustrated here +%\InputFormattedClass{thorsclass2} + +\newcommand\ParseClassLine[4]{\classMember{#1}{#2}{#4}} +\InputFormattedClass[\ParseClassLine]{thorsclass3} + +% \autoCopyOff + +%\distrToStudentsOff + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + + +\thQuizHeader + +\noindent\textbf{Instructions:} +\begin{itemize} +\item (For the student) Press `\textsf{Start}' to begin the + quiz, after you've completed the quiz, press + `\textsf{End}'. \emph{Save the document before closing + it}. +\item (For the instructor) Open the document the student has + saved, the `\textsf{Mark It}' and `\textsf{Freeze Quiz}' + are visible. Press the `\textsf{Mark It}' button and the + quiz will be marked. For the extended response questions, + enter the points assigned in the box in the left margin. + At your option, reset the quiz or save the quiz with the + markup. +\end{itemize} + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz the `Thorsten way.'.\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer +\end{document} \ No newline at end of file diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass1.cfg b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass1.cfg new file mode 100644 index 00000000..82deb66f --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass1.cfg @@ -0,0 +1,43 @@ +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/c/Users/dpstory/Desktop/Test Folder/target/myClass} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} +\endinput % testing large class +\classMember{Peter}{Pan1}{A/_Thor} +\classMember{J\oct374rgen1}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer1}{C/_Thor} +\classMember{Peter}{Pan2}{A/_Thor} +\classMember{J\oct374rgen2}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer2}{C/_Thor} +\classMember{Peter}{Pan3}{A/_Thor} +\classMember{J\oct374rgen3}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer3}{C/_Thor} +\classMember{Peter}{Pan4}{A/_Thor} +\classMember{J\oct374rgen4}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer4}{C/_Thor} +\classMember{Peter}{Pan5}{A/_Thor} +\classMember{J\oct374rgen5}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer5}{C/_Thor} +\classMember{Peter}{Pan6}{A/_Thor} +\classMember{J\oct374rgen6}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer6}{C/_Thor} +\classMember{Peter}{Pan7}{A/_Thor} +\classMember{J\oct374rgen7}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer7}{C/_Thor} +\classMember{Peter}{Pan8}{A/_Thor} +\classMember{J\oct374rgen8}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer8}{C/_Thor} +\classMember{Peter}{Pan9}{A/_Thor} +\classMember{J\oct374rgen9}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer9}{C/_Thor} +\classMember{Peter}{Pan10}{A/_Thor} +\classMember{J\oct374rgen10}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer10}{C/_Thor} +\classMember{Peter}{Pan11}{A/_Thor} +\classMember{J\oct374rgen11}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer11}{C/_Thor} +\classMember{Peter}{Pan12}{A/_Thor} +\classMember{J\oct374rgen12}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer12}{C/_Thor} + diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass2.cfg b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass2.cfg new file mode 100644 index 00000000..0ce74346 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass2.cfg @@ -0,0 +1,44 @@ +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/c/Users/dpstory/Desktop/Test Folder/target/myClass} +\bClassData +{Peter}{Pan}{A/_Thor} +*{J\"{u}rgen}{Gilg}{B/_Thor} +{Thors}{Hammer}{C/_Thor} +\endinput % test large class +{Peter}{Pan1}{A/_Thor} +{J\oct374rgen1}{Gilg}{B/_Thor} +{Thors}{Hammer1}{C/_Thor} +{Peter}{Pan2}{A/_Thor} +{J\oct374rgen2}{Gilg}{B/_Thor} +{Thors}{Hammer2}{C/_Thor} +{Peter}{Pan3}{A/_Thor} +{J\oct374rgen3}{Gilg}{B/_Thor} +{Thors}{Hammer3}{C/_Thor} +{Peter}{Pan4}{A/_Thor} +{J\oct374rgen4}{Gilg}{B/_Thor} +{Thors}{Hammer4}{C/_Thor} +{Peter}{Pan5}{A/_Thor} +{J\oct374rgen5}{Gilg}{B/_Thor} +{Thors}{Hammer5}{C/_Thor} +{Peter}{Pan6}{A/_Thor} +{J\oct374rgen6}{Gilg}{B/_Thor} +{Thors}{Hammer6}{C/_Thor} +{Peter}{Pan7}{A/_Thor} +{J\oct374rgen7}{Gilg}{B/_Thor} +{Thors}{Hammer7}{C/_Thor} +{Peter}{Pan8}{A/_Thor} +{J\oct374rgen8}{Gilg}{B/_Thor} +{Thors}{Hammer8}{C/_Thor} +{Peter}{Pan9}{A/_Thor} +{J\oct374rgen9}{Gilg}{B/_Thor} +{Thors}{Hammer9}{C/_Thor} +{Peter}{Pan10}{A/_Thor} +{J\oct374rgen10}{Gilg}{B/_Thor} +{Thors}{Hammer10}{C/_Thor} +{Peter}{Pan11}{A/_Thor} +{J\oct374rgen11}{Gilg}{B/_Thor} +{Thors}{Hammer11}{C/_Thor} +{Peter}{Pan12}{A/_Thor} +{J\oct374rgen12}{Gilg}{B/_Thor} +{Thors}{Hammer12}{C/_Thor} + diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3-star.cfg b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3-star.cfg new file mode 100644 index 00000000..af16fef3 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3-star.cfg @@ -0,0 +1,9 @@ +\instrPath {/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath {/c/Users/dpstory/Desktop/Test Folder/target/myClass} +\def\altCPath{/C/Users/dpstory/Desktop/Test Folder/target/myOtherClass} +\bClassData +{Peter}{Pan}{453453}{A/_Thor} +{J\oct374rgen}{Gilg}{5565}*{\altCPath/B/_Thor} +{Thors}{Hammer}{534534}{C/_Thor} +\endinput + diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3.cfg b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3.cfg new file mode 100644 index 00000000..fa534153 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclass3.cfg @@ -0,0 +1,8 @@ +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\bClassData +{Peter}{Pan}{453453}{A/_Thor} +{J\oct374rgen}{Gilg}{5565}{B/_Thor} +{Thors}{Hammer}{534534}{C/_Thor} +\endinput + diff --git a/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclassx.cfg b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclassx.cfg new file mode 100644 index 00000000..ad1151ea --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/cfgs/thorsclassx.cfg @@ -0,0 +1,6 @@ +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/c/Users/dpstory/Desktop/Test Folder/target/myClass} +\bClassData +{Peter}{Pan}{453453}{A/_Thor} +{J\oct374rgen}{Gilg}{5565}{B/_Thor} +{Thors}{Hammer}{534534}{C/_Thor} diff --git a/texmf-dist/doc/latex/thorshammer/examples/misc/thexrt.tex b/texmf-dist/doc/latex/thorshammer/examples/misc/thexrt.tex new file mode 100644 index 00000000..b9e4d2d3 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/misc/thexrt.tex @@ -0,0 +1,319 @@ +% spdef is part of aeb-mobile package +% I'm using it as a convenience, so I can have a dual +% setup between the web package and not loading the +% web package +\RequirePackage[use=forweb]{spdef} % try !use=forweb +\documentclass{article} +\usepackage{amstext} +\ifforweb\usepackage[forcolorpaper]{web}\fi +\expexe{\usepackage[usesumrytbls,allowrandomize\ifforweb\else,forcolorpaper\fi]{exerquiz}} +\usepackage{ran_toks} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q1} +\thQzName{Grammatik 1} + +\title{Pr\"{u}fung: \thqzname} +\author{Odon, Thor, Loki} +\ifforweb + \subject{Testing Thor's way} + \keywords{LaTeX, acrotex, thorshammer} + \university{Thor University} + \email{thor@valhalla.gov} + \version{1700 Today} + \versionLabel{Due by} + \copyrightyears{1999-\the\year} + \nocopyright + \revisionLabel{} +\fi +% It is important to freeze the seed to that (1) you can reproduce the exact +% same quiz at a later time; (2) allow content written to the AUX file to +% come up to date. This is important when using summary tables. +\useThisSeed{1344524586} + +\renewcommand\sqslsectitle{L\"{o}sungen: \thqzname\space(Ver~\QzVer)} + +%\thQzHeaderL{Thor's Class} +\thQzHeaderCQ{Prüfung: \thqzname\space(Ver~\QzVer)} +\thQzHeaderCS{L\"{o}sungen: \thqzname\space(Ver~\QzVer)} + +\ifforweb + \thQzHeaderR{Seite \thepage} +\else + \thQzHeaderR{Herr Thor} +\fi + +\thQzName{Grammatik 1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% An example of how to re-format how the +% \Fullname field appears. +\thfullnameFmt{#2+", "+#1} + + +\makeatletter +% An example of redefining \thQuizHeaderLayout, here +% we make \Firstname and \Lastname field hidden and taking +% up no space +\renewcommand\thQuizHeaderLayout{\noindent + \smash{\rlap{\FirstName[\F\FHidden]{0bp}{0bp}}\rlap{\LastName[\F\FHidden]{0bp}{0bp}}}% + \begin{minipage}[t]{1.2in}\kern0pt + \makebox[0pt][r]{\raggedleft\markQz{}{11bp}% + \hspace{\marginparsep}}% + \th@QHPoints\studentReport{\widthof{000/000}}{11bp}\vcgBdry[6pt] + \makebox[0pt][r]{\raggedleft\freezeOrSave{}{11bp}% + \hspace{\marginparsep}}% + \th@QHGrade\studentGrade{14bp}{14bp}\vcgBdry[6pt] + \end{minipage}\hfill + \begin{minipage}[t]{\linewidth-1em-1.2in}\kern0pt + \begin{sumryTblAux}{\currQuiz} + \displaySumryTbl[ntables=1,showmarkup]{\currQuiz} + \end{sumryTblAux} + \end{minipage}} +\makeatother + +% reset the paths for \instrPath and \classPath for your system +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} + +\autoCopyOn + +%\distrToInstrOff +%\distrToStudentsOff + +\DeclareCoverPage{0} + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\ifforweb + \makeinlinetitle +\else + \maketitle +\fi + +\thispagestyle{empty} +%\thQzHeaderR{Herr Thor} + +\noindent +Student Name: \FullName{1.5in}{11bp} + +\section*{Instructions} + +Solve each problem to the best of your ability. Do not look a +little to the left or a little to the right -- Thor is watching +!! You have a time limit of 2 minutes to complete the quiz. + +\paragraph*{The Procedure} +\begin{enumerate} + \item The quiz begins on the next page + \item Go to the next page \verb!:-{)! + \item To begin the quiz, press the `\textsf{Begin}' button + \item Answer each of the questions + \item To end the quiz, press the `\textsf{End}' button. You + will be asked whether you really want to end the quiz. Press the + `\textsf{Yes}' button, or the `\textsf{No}' button to continue with the quiz + \item After ending the quiz, press the `\textsf{Save}' button; save the file + back to the original folder + \item Close \textsf{Adobe Reader}, and go have lunch. +\end{enumerate} +Good luck, no, I wish you \emph{good knowledge} ! + +\newpage + +\declareQuizBody{qzbody1} +\declareQuizBody{qzbody2} + +% The qzbody env encloses the entire body of the quiz +\begin{qzbody1} +\bRTVToks{\currQuiz} + +\thQuizHeader + +\noindent\textbf{Instructions:} (For the student) Press +`\textsf{Begin}' to begin the quiz; after completing the quiz, +press `\textsf{End}'. Use the `\textsf{Save}' button to save the +document. + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + +\begin{rtVW} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} +\end{rtVW} + +\begin{rtVW} + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} +\end{rtVW} + +\begin{rtVW} + \item\PTs{2} $9+8=\RespBoxMath{17}*{1}{.0001}{[0,1]}$ +\begin{solution} +Everyone knows that $ 9 + 8 = 17$, why don't you ? +\end{solution} +\end{rtVW} + +\begin{rtVW} +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay*{\linewidth}{1in} +\begin{solution} +Acro\negthinspace\TeX{} was created by D. P. Story and supported +for many years by J\"{u}gen Gilg. Special inspiration was +provided by K. F. Story, who suggested the name +Acro\negthinspace\TeX. +\end{solution} +\end{rtVW} + +\begin{rtVW} +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices[random=true] + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} +\end{rtVW} + + +\begin{rtVW} +\multipartquestion + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices[random=true] + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1} Andrew Jackson\eAns + \Ans[3]{1} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[nCols=2,random=true] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices[random=true] + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} +\end{rtVW} + +\eRTVToks + +% Ok, now display this questions in a random order. +\displayListRandomly{\thisQuiz} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{qzbody1} + +\begin{qzbody2} + +\thQuizHeader + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + +\essayitem{3} Comment on the experience of taking a quiz the `Thorsten way.'.\par +\RespBoxEssay*{\linewidth}{1in} + +\begin{solution} +This was a very wonderful experience, I'm privileged to have been in this class with such a wonderful +German teacher. As you can read, I am fluent in German now. Thank you Thor, wherever you are. + +A second paragraph should convince of my sincerity, remember me when you mark this quiz. +\end{solution} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{qzbody2} + +% Now we input the qzbody back in two times, though it can be more than that. The quiz name +% modified in each instance. +% +% Each instance of the quiz has a randomized order +% +\InputQuizBody{qzbody1} + +\InputQuizBody{qzbody2} + +\InputQuizBody{qzbody1} + + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexb.tex b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexb.tex new file mode 100644 index 00000000..04d5a659 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexb.tex @@ -0,0 +1,147 @@ +\RequirePackage[use=withdesign]{spdef} % try !use=withdesign (spdef is distributed with aeb-mobile) +\documentclass{article} +\usepackage{amstext} +\expexe{\usepackage[\ifwithdesign{designi}\else{forcolorpaper}\fi]{web}} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[!testmode]{thorshammer} + +\ifwithdesign +% Some crazy calculations to get the left margin looking good +\fontsize{9bp}{0}\selectfont + \addtoWebWidth{\widthof{Freeze Quiz}} + \resetmargins{\incby+\widthof{Freeze Quiz}}{}{}{} +\normalsize +\fi + +\DeclareQuiz{q1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\enumQuizzes{3} + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +%\makePDasXOn +%\makeXasPDOn + +\begin{docassembly} +\sadQuizzes +\end{docassembly} + +\begin{document} + +\thQuizHeader + +\noindent\textbf{Instructions:} Enter your first and last names +in the fields provided. Press `\textsf{Begin}' to begin the +quiz; after completing the quiz, press `\textsf{End}'. Use the +`\textsf{Save}' button to save the document. + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive $-1$ points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexbd.tex b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexbd.tex new file mode 100644 index 00000000..7b9ed8f1 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexbd.tex @@ -0,0 +1,146 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[batchdistr]{thorshammer} + +\DeclareQuiz{q1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% reset the paths for \instrPath and \classPath for your system +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\thQuizHeader + +\noindent\textbf{Instructions:} (For the student) Press +`\textsf{Begin}' to begin the quiz; after completing the quiz, +press `\textsf{End}'. Use the `\textsf{Save}' button to save the +document. + + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz the `Thorsten way.'.\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{document} + diff --git a/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexr.tex b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexr.tex new file mode 100644 index 00000000..80412858 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexr.tex @@ -0,0 +1,175 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls,allowrandomize]{exerquiz} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q1} + +% It is important to freeze the seed so that (1) you can reproduce the exact +% same quiz at a later time; (2) allow content written to the AUX file to +% come up to date. This is important when using summary tables. +\useRandomSeed{380105620} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} %,pdfencoding=auto +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% reset the paths for \instrPath and \classPath for your system +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} + +\autoCopyOn +\DeclareCoverPage{0} + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\thispagestyle{empty} + +\noindent In this file, we attempt to duplicate and extend the +work of \texttt{theexuc.tex} by developing a scheme to randomize +the questions. We begin with the simple case, of creating two +versions of the same quiz. We modify the preamble to include the +option \texttt{allowrandomize} of \textsf{exerquiz}. This file +randomizes the multiple choice and multiple selection question +that are marked up using \verb~\bChoices/\eChoices~. The `quiz +body' concept is used to introduced multiple equivalent quizzes. + +\newpage + +\declareQuizBody{qzbody} + +\begin{qzbody} + +\thQuizHeader + +\noindent\textbf{Instructions:} (For the student) Press +`\textsf{Begin}' to begin the quiz; after completing the quiz, +press `\textsf{End}'. Use the `\textsf{Save}' button to save the +document. + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices[random=true] + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices[random=true] + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1} Andrew Jackson\eAns + \Ans[3]{1} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[nCols=2,random=true] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices[random=true] + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz the `Thorsten way.'\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer +\end{qzbody} + +\typeout{!! inputting qzbody first time} +\InputQuizBody{qzbody} + +\typeout{!! inputting qzbody second time} +\InputQuizBody{qzbody} + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexrt.tex b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexrt.tex new file mode 100644 index 00000000..7852cdc1 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexrt.tex @@ -0,0 +1,222 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls,allowrandomize]{exerquiz} +\usepackage{ran_toks} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q1} + +% It is important to freeze the seed so that (1) you can reproduce the exact +% same quiz at a later time; (2) allow content written to the AUX file to +% come up to date. This is important when using summary tables. +\useRandomSeed{1344524586} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +% \previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% reset the paths for \instrPath and \classPath for your system +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} + +\autoCopyOn + +%\distrToInstrOff +%\distrToStudentsOff + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\noindent In this file, we attempt to \emph{duplicate} and +\emph{extend} the work of \texttt{theexuc.tex} by developing a +scheme to randomize choices and randomize the questions. To +randomize the choices, we modify the preamble to include the +option \texttt{allowrandomize} of \textsf{exerquiz}, to +randomize the order of the questions, we include the +\textsf{ran\_toks} package. The `quiz body' concept is used +to introduced multiple equivalent quizzes. + + +\newpage + + +\declareQuizBody{qzbody1} +\declareQuizBody{qzbody2} + +% The qzbody env encloses the entire body of the quiz +\begin{qzbody1} + +\bRTVToks{\currQuiz} + +\thQuizHeader + +\noindent\textbf{Instructions:} (For the student) Press +`\textsf{Begin}' to begin the quiz; after completing the quiz, +press `\textsf{End}'. Use the `\textsf{Save}' button to save the +document. + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + +\begin{rtVW} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} +\end{rtVW} + +\begin{rtVW} + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} +\end{rtVW} + +\begin{rtVW} + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ +\end{rtVW} + +\begin{rtVW} +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} +\end{rtVW} + +\begin{rtVW} +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices[random=true] + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} +\end{rtVW} + + +\begin{rtVW} +\multipartquestion + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices[random=true] + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1} Andrew Jackson\eAns + \Ans[3]{1} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[nCols=2,random=true] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices[random=true] + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} +\end{rtVW} + +\eRTVToks + +% Ok, now display this questions in a random order. +\displayListRandomly{\thisQuiz} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{qzbody1} + +\begin{qzbody2} + +\thQuizHeader + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + +\essayQ{10} % num points assigned +\item\PTs{10} Comment on the experience of taking a quiz the `Thorsten way.'\par +\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{qzbody2} + +% Now we input the qzbody back in two times, though it can be more than that. The quiz name +% modified in each instance. +% +% Each instance of the quiz has a randomized order +% +\InputQuizBody{qzbody1} + +\InputQuizBody{qzbody1} + +\InputQuizBody{qzbody2} + + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexub.tex b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexub.tex new file mode 100644 index 00000000..4b3286f0 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexub.tex @@ -0,0 +1,147 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% reset the paths for \instrPath and \classPath for your system +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} + +%\autoCopyOn % or \autoCopyOff + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\thQuizHeader + +\noindent\textbf{Instructions:} (For the student) Press +`\textsf{Begin}' to begin the quiz; after completing the quiz, +press `\textsf{End}'. Use the `\textsf{Save}' button to save the +document. + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}*{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}*{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz the `Thorsten way.'.\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer + +\end{document} + diff --git a/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexuc.tex b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexuc.tex new file mode 100644 index 00000000..e514552a --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/nosolns/thexuc.tex @@ -0,0 +1,152 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls]{exerquiz} +\usepackage[useclass]{thorshammer} + +\DeclareQuiz{q1} + +\setInitMag{fitwidth} +\hypersetup{pdfpagemode=UseNone} % don't need to see bookmarks +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar + +\showCreditMarkup + +%\previewOn\pmpvOn + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +\PTsHook{($\eqPTs^{\text{pts}}$)} + +\useMCCircles + +% reset the paths for \instrPath and \classPath for your system +\instrPath{/C/Users/dpstory/Desktop/Test Folder/target/_Thor} +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +%\classMember{Peter}{Pan}{} % with third arg empty, these files will be dropped +%\classMember{J\oct374rgen}{Gilg}{} % at root of \classPath +%\classMember{Thors}{Hammer}{} +\classMember{Peter}{Pan}{A/_Thor} +\classMember{J\oct374rgen}{Gilg}{B/_Thor} +\classMember{Thors}{Hammer}{C/_Thor} + +\autoCopyOn % or \autoCopyOff + +%\distrToStudentsOff + +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} + +\begin{document} + +\thQuizHeader + +\noindent\textbf{Instructions:} (For the student) Press +`\textsf{Begin}' to begin the quiz; after completing the quiz, +press `\textsf{End}'. Use the `\textsf{Save}' button to save the +document. + +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} + \item\PTs{3} Which of these are true ? +\begin{answers}{4} +\Ans1 True & \Ans0 False +\end{answers} + + \item \PTs{4} Select which of the following is true. +\begin{answers}{4} +\Ans1 True & \Ans0 False & \Ans0 Maybe & \Ans0 Sometimes +\end{answers} + + \item\PTs{2} $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}$ + +\essayQ{5} % num points assigned +\item\PTs{5} Write a short history of Acro\negthinspace\TeX.\par +\RespBoxEssay{\linewidth}{1in} + +\item\PTs{3} Which of the following are numbers? +\begin{manswers}{6} +\bChoices + \Ans[-1]{0}d\eAns + \Ans[1]{1}17\eAns + \Ans[-1]{0}p\eAns + \Ans[1]{1}88\eAns + \Ans[-1]{0}s\eAns + \Ans[1]{1}105\eAns +\eChoices +\end{manswers} + +\multipartquestion + + \item\PTs{20} Answer each of the following multiple selection problems. Each correct answer + is worth $3$ points, and each incorrect answer is worth $-2$ points. + \begin{questions} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a President + of the United States. (Select all correct choices.) + + \begin{manswers}{2}% + \bChoices + \Ans[-2]{0} Henry Clay\eAns + \Ans[-2]{0} Ben Franklin\eAns + \Ans[3]{1}\label{aj} Andrew Jackson\eAns + \Ans[3]{1}\label{rr} Ronald Reagan\eAns + \Ans[-2]{0} George Meade\eAns + \Ans[3]{1}\label{gc} Grover Cleveland\eAns + \Ans[-2]{0} John Jay\eAns + \Ans[-2]{0} Paul Revere\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{9} Select which people who served as a Chancellor of the + German Republic. (Select all correct choices.) + \begin{manswers}{2}% + \bChoices[2] + \Ans[-2]{0} Gustav Heinemann\eAns + \Ans[-2]{0} Theodor Heu{\ss}\eAns + \Ans[3]{1} Konrad Adenauer\eAns + \Ans[-2]{0} Richard von Weizs\"{a}cker\eAns + \Ans[3]{1} Willy Brandt\eAns + \Ans[-2]{0} Heinrich L\"{u}bke\eAns + \Ans[-2]{0} Roman Herzog\eAns + \Ans[3]{1} Ludwig Erhard\eAns + \eChoices + \end{manswers} + +\rowsep{3pt} + + \item\PTs{2} If you select all choices in part~(a), you will + receive -1 points as a penalty for bad guessing. \textbf{Question:} + Determine the \emph{number of correct choices} in part~(a)? + \begin{answers}{4} + \bChoices + \Ans0 1\eAns + \Ans0 2\eAns + \Ans1 3\eAns + \Ans0 4\eAns + \Ans0 5\eAns + \Ans0 6\eAns + \Ans0 7\eAns + \Ans0 8\eAns + \eChoices + \end{answers} + \end{questions} + +%\essayQ{3} % num points assigned +%\item\PTs{3} Comment on the experience of taking a quiz `Thor's way.'.\par +%\RespBoxEssay{\linewidth}{1in} + +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer +\end{document} + + diff --git a/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/get-hash-string.tex b/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/get-hash-string.tex new file mode 100644 index 00000000..b20c438a --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/get-hash-string.tex @@ -0,0 +1,35 @@ +\documentclass{article} +\usepackage[designi]{web} +\usepackage{eforms} + +%\previewOn\pmpvOn + +\parindent0pt \parskip6pt + +\begin{document} + +\begin{defineJS}{\btnAct} +var resp=app.response({ + cQuestion: "Enter a PIN number", + cTitle: "Get Hash String" +}); +var f=this.getField("txt"); +if (resp!=null) f.value=Collab.hashString(resp); +\end{defineJS} + +Create a four digit (PIN) number and copy that number into the body of the +definition of the \verb|\PIN| command, which is defined in the source file +\texttt{quiz-pwd-to-correct-AR.tex}. This is to record and save the number. + +Push the button and enter the four digit number you just created into the +response box. When you press the \textsf{OK} button, the hash string of the +number you entered appears in the text field. Copy and paste this value into +the \texttt{quiz-pwd-to-correct-AR.tex} as the value of the +\texttt{\_PinCode} JavaScript variable. Now you're ready to compile the file +\texttt{quiz-pwd-to-correct-AR.tex}. + +\pushButton[\CA{Push}\AAmouseup{\btnAct}]{btn}{}{11bp}\olBdry +\textField[\textSize{8}]{txt}{2in}{11bp}\olBdry +\pushButton[\CA{Reset}\AAmouseup{this.resetForm();}]{reset}{}{11bp} + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AA.tex b/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AA.tex new file mode 100644 index 00000000..e84d9781 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AA.tex @@ -0,0 +1,190 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage[designi]{web} +\usepackage{exerquiz}[2019/10/14] + +%\previewOn\pmpvOn + +% save the original defn of \eq@@EndQuizButtonActions as \eq@@EndQuizButtonActionsSave +\efsave\eq@@EndQuizButtonActions\as\eq@@EndQuizButtonActionsDefSave + +\usepackage[ordinary]{thorshammer} + +\thQzHeaderL{PWD Quizzes} +\thQzHeaderCQ{Quiz 1} + +% save the revised defn of \eq@@EndQuizButtonActions as \eq@@EndQuizButtonActionsThorSave +\efsave\eq@@EndQuizButtonActions\as\eq@@EndQuizButtonActionsThorSave + +\renewcommand\eqQuizPointsMsg{% +"\eqptScore\space"+ptScore+" \eqOutOf\space"+nPointTotal} + +\let\app\textsf +\let\pkg\textsf +\let\uif\textsf +\let\env\texttt +\let\opt\texttt +\def\cs#1{\texttt{\char`\\#1}} + + +\execJSOn +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +% If the students have Acrobat, they can see the pin number +% if they know how; however, if we use a hash string, the actual +% PIN is not retained within document. +\def\PIN{5243} % PIN number, change as desired + +% save \CorrBtnActionsJS as \CorrBtnActionsJSSave +\efsave\CorrBtnActionsJS\as\CorrBtnActionsJSSave +\begin{defineJS*}[\makeesc\@]{\CorrBtnActionsPwdJS} +var resp=app.response({ + cQuestion: "Enter the PIN number", + cTitle: "View Answers", + bPassword: true +}); +var _resp=Collab.hashString(resp); +if (_resp==_PinCode) { + correctQuiz("@eqBaseName",@thequestionno); + if (typeof correctSumryTbl == "function") + correctSumryTbl("@eqBaseName",@thequestionno); +} +\end{defineJS*} + +\DeclareQuiz{qz1} + +\begin{execJS}{execjs} +this.addScript("Pin Code","var _PinCode = \"" + Collab.hashString("\PIN")+"\""); +\end{execJS} + +\begin{document} + +\section{Introduction} + +\noindent\textbf{Goal:} Make the \uif{Correct} button password +protected.\medskip + +\noindent\textbf{Discussion:} This file illustrates the methods +of protecting the \uif{Correct} button with a password. This +file requires \app{Acrobat} to create; while the companion file +(\texttt{quiz-pwd-to-correct-AR.tex}) does not. + +If only MC and MS questions are posed, the \pkg{thorshammer} +package is not needed; otherwise, it is needed to support the +other types of questions. + +Within \pkg{exerquiz} the command that holds the JavaScript +action of the \uif{Correct} button is \cs{CorrBtnActionsJS}. We +save this macro, and change over to \cs{CorrBtnActionsPwdJS}, +defined in the preamble. We use the commands \cs{efsave} and +\cs{efrestore}, defined in \pkg{eforms}, to change the default +action to the password action, and back again. We do the same +thing for the \uif{End Quiz} action. (\pkg{thorshammer} +redefines \cs{eq@@EndQuizButtonActions}, the JavaScript actio of +the \uif{End Quiz} button.) + + +\newpage + +\section{Quiz with PIN to correct} + +% require students to answer all questions +\renewcommand\minQuizResp{highThreshold} % 1 + +For the quiz below, the \uif{Correct} button has an encrypted +password. The password appears in parentheses for the convenience of the casual reader. + +% use password version of \CorrButton action +\efrestore\CorrBtnActionsJS\from\CorrBtnActionsPwdJS +\begin{quiz*}{\currQuiz} +Solve each +\begin{questions} + \item The sum of 1 and 1 is\dots +\begin{answers}{5} +\bChoices + \Ans0 0\eAns + \Ans0 1\eAns + \Ans1 2\eAns + \Ans0 3\eAns + \Ans0 4\eAns +\eChoices +\end{answers} +\item $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}\cgBdry\CorrAnsButton{17}$ +\end{questions} +\end{quiz*}\quad\PointsField{\currQuiz}\olBdry\CorrButton{\currQuiz} (PIN: \PIN)\vcgBdry + +\AnswerField{\currQuiz} + +\newpage + +\section{Quiz without PIN to correct} + +Now we try to create an ordinary \pkg{exerquiz} quiz without password protection. + +% restore \eq@@EndQuizButtonActions from its default defn +\efrestore\eq@@EndQuizButtonActions\from\eq@@EndQuizButtonActionsDefSave +% restore \CorrBtnActionsJS from \CorrBtnActionsJSSave +\efrestore\CorrBtnActionsJS\from\CorrBtnActionsJSSave + +\renewcommand\minQuizResp{lowThreshold} + +\begin{quiz*}{qz2} +Solve each +\begin{questions} + \item The sum of 1 and 1 is\dots +\begin{answers}{5} +\bChoices + \Ans0 0\eAns + \Ans0 1\eAns + \Ans1 2\eAns + \Ans0 3\eAns + \Ans0 4\eAns +\eChoices +\end{answers} +\item $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}\cgBdry\CorrAnsButton{17}$ +\end{questions} +\end{quiz*}\quad\PointsField{\currQuiz}\olBdry\CorrButton{\currQuiz}\vcgBdry + +\AnswerField{\currQuiz} + + +\newpage + +\section{Another quiz with PIN to correct} + +It is possible to have a different PIN number for this quiz (multiple PINs in one document), but +I see no need for this. + +\DeclareQuiz{qz3} + + +% restore \eq@@EndQuizButtonActions from \eq@@EndQuizButtonActionsThorSave +\efrestore\eq@@EndQuizButtonActions\from\eq@@EndQuizButtonActionsThorSave +% restore password protection for Correct button +\efrestore\CorrBtnActionsJS\from\CorrBtnActionsPwdJS + +% require students to answer all questions +\renewcommand\minQuizResp{highThreshold} + +\begin{quiz*}{qz3} +Solve each +\begin{questions} + \item The sum of 1 and 1 is\dots +\begin{answers}{5} +\bChoices + \Ans0 0\eAns + \Ans0 1\eAns + \Ans1 2\eAns + \Ans0 3\eAns + \Ans0 4\eAns +\eChoices +\end{answers} +\item $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}\cgBdry\CorrAnsButton{17}$ +\end{questions} +\end{quiz*}\quad\PointsField{\currQuiz}\olBdry\CorrButton{\currQuiz} (PIN: \PIN)\vcgBdry + +\AnswerField{\currQuiz} + + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AR.tex b/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AR.tex new file mode 100644 index 00000000..9123ce34 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/examples/ordinary-option/quiz-pwd-to-correct-AR.tex @@ -0,0 +1,174 @@ +% Requires Acrobat +\documentclass{article} +\usepackage{amstext} +\usepackage[designi]{web} +\usepackage{exerquiz}[2019/10/11] + +\efsave\eq@@EndQuizButtonActions\as\eq@@EndQuizButtonActionsDefSave + +\usepackage[ordinary]{thorshammer} + +\thQzHeaderL{PWD Quiz} +\thQzHeaderCQ{Quiz 1} + +\efsave\eq@@EndQuizButtonActions\as\eq@@EndQuizButtonActionsThorSave + +%\previewOn\pmpvOn + +\renewcommand\eqQuizPointsMsg{% +"\eqptScore\space"+ptScore+" \eqOutOf\space"+nPointTotal} + +\let\app\textsf +\let\pkg\textsf +\let\env\texttt +\let\opt\texttt +\let\uif\textsf + +\execJSOn +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] + +% If the students have Acrobat, they can see the pin number +% if they know how. + +\efsave\CorrBtnActionsJS\as\CorrBtnActionsJSSave +\begin{defineJS*}[\makeesc\@]{\CorrBtnActionsPwdJS} +var resp=app.response({ + cQuestion: "Enter the PIN number", + cTitle: "View Answers", + bPassword: true +}); +var _resp=Collab.hashString(resp); +if (_resp==_PinCode) { + correctQuiz("@eqBaseName",@thequestionno); + if (typeof correctSumryTbl == "function") + correctSumryTbl("@eqBaseName",@thequestionno); +} +\end{defineJS*} + +\DeclareQuiz{qz} + +\def\PIN{5243} % PIN number, change as desired +\begin{insDLJS}{pin}{Pin Code} +var _PinCode = "02JRVZdRgYgCA-Rtje8VkD"; +\end{insDLJS} + +\parindent0pt +\parskip6pt + +\begin{document} + +\noindent\textbf{Goal:} Make the \uif{Correct} button password protected.\medskip + +\noindent\textbf{Discussion:} +This demo file uses a \emph{hash string} to encode the password for the instructor to correct +the quiz, it avoids the use of \app{Adobe Acrobat} by getting the hash string from the +PDF \texttt{get-hash-string}. Copy the hash string generated from \texttt{get-hash-string} +as the value of the JavaScript variable \texttt{\_PinCode} in the \textsf{insDLJS} environment +seen in this source file for this document. Then, compile this document and distribute. + +%Delay the correction of this next quiz by expanding the new command +%\verb|\pwdCorrBtnJS|. + +\newpage + +\section{Quiz with PIN to correct} + +% require students to answer all questions +\renewcommand\minQuizResp{highThreshold} % 1 + +For the quiz below, the \uif{Correct} button has an encrypted +password. The password appears in parentheses for the convenience of the casual reader. + +% use password version of \CorrButton action +\efrestore\CorrBtnActionsJS\from\CorrBtnActionsPwdJS +\begin{quiz*}{\currQuiz} +Solve each +\begin{questions} + \item The sum of 1 and 1 is\dots +\begin{answers}{5} +\bChoices + \Ans0 0\eAns + \Ans0 1\eAns + \Ans1 2\eAns + \Ans0 3\eAns + \Ans0 4\eAns +\eChoices +\end{answers} +\item $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}\cgBdry\CorrAnsButton{17}$ +\end{questions} +\end{quiz*}\quad\PointsField{\currQuiz}\olBdry\CorrButton{\currQuiz} (PIN: \PIN)\vcgBdry + +\AnswerField{\currQuiz} + +\newpage + +\section{Quiz without PIN to correct} + +Now we try to create an ordinary \pkg{exerquiz} quiz without password protection. + +% restore \eq@@EndQuizButtonActions from its default defn +\efrestore\eq@@EndQuizButtonActions\from\eq@@EndQuizButtonActionsDefSave +% restore \CorrBtnActionsJS from \CorrBtnActionsJSSave +\efrestore\CorrBtnActionsJS\from\CorrBtnActionsJSSave + +\renewcommand\minQuizResp{lowThreshold} + +\begin{quiz*}{qz2} +Solve each +\begin{questions} + \item The sum of 1 and 1 is\dots +\begin{answers}{5} +\bChoices + \Ans0 0\eAns + \Ans0 1\eAns + \Ans1 2\eAns + \Ans0 3\eAns + \Ans0 4\eAns +\eChoices +\end{answers} +\item $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}\cgBdry\CorrAnsButton{17}$ +\end{questions} +\end{quiz*}\quad\PointsField{\currQuiz}\olBdry\CorrButton{\currQuiz}\vcgBdry + +\AnswerField{\currQuiz} + + +\newpage + +\section{Another quiz with PIN to correct} + +It is possible to have a different PIN number for this quiz (multiple PINs in one document), but +I see no need for this. + +\DeclareQuiz{qz3} + + +% restore \eq@@EndQuizButtonActions from \eq@@EndQuizButtonActionsThorSave +\efrestore\eq@@EndQuizButtonActions\from\eq@@EndQuizButtonActionsThorSave +% restore password protection for Correct button +\efrestore\CorrBtnActionsJS\from\CorrBtnActionsPwdJS + +% require students to answer all questions +\renewcommand\minQuizResp{highThreshold} + +\begin{quiz*}{qz3} +Solve each +\begin{questions} + \item The sum of 1 and 1 is\dots +\begin{answers}{5} +\bChoices + \Ans0 0\eAns + \Ans0 1\eAns + \Ans1 2\eAns + \Ans0 3\eAns + \Ans0 4\eAns +\eChoices +\end{answers} +\item $9+8=\RespBoxMath{17}{1}{.0001}{[0,1]}\cgBdry\CorrAnsButton{17}$ +\end{questions} +\end{quiz*}\quad\PointsField{\currQuiz}\olBdry\CorrButton{\currQuiz} (PIN: \PIN)\vcgBdry + +\AnswerField{\currQuiz} + +\end{document} \ No newline at end of file diff --git a/texmf-dist/doc/latex/thorshammer/folder-js/aeb-reader.js b/texmf-dist/doc/latex/thorshammer/folder-js/aeb-reader.js new file mode 100644 index 00000000..87783f86 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/folder-js/aeb-reader.js @@ -0,0 +1,50 @@ +/* + AEB Adobe Acrobat Reader JavaScript Methods + + Copyright (C) 2019 AcroTeX.Net + D. P. Story + http://www.acrotex.net + + Version 1.0 +*/ +// console.println("Version 1.0 (Reader DC)"); +if ( typeof aebTrustedFunctions == "undefined") { + aebTrustedFunctions = app.trustedFunction( function ( doc, oFunction, oArgs ) + { + app.beginPriv(); + var retn = oFunction( oArgs, doc ); + app.endPriv(); + return retn; + }); +} +aebSaveAs = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + app.execMenuItem("Save"); + app.endPriv(); +}); +aebDocSaveAs = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + var Msg=function(e){return (aebDocSaveAs.msg==undefined)?("Doc SaveAs Error: " + e.toString()):aebDocSaveAs.msg;} + var Action=function(){return ((aebDocSaveAs.action==undefined)?null:eval(aebDocSaveAs.action));} + app.beginPriv(); + try { + return retn = doc.saveAs(oArgs); + } catch(e){console.println(Msg(e));Action();} + app.endPriv(); + aebDocSaveAs.msg=undefined; + aebDocSaveAs.action=undefined; +}); +aebBrowseForDoc = app.trustPropagatorFunction( function ( oArgs ) +{ + app.beginPriv(); + return retn = app.browseForDoc(oArgs); + app.endPriv(); +}); +aebLaunchURL=app.trustPropagatorFunction ( function ( oArgs ) +{ + app.beginPriv(); + var retn = app.launchURL(oArgs); + app.endPriv(); +}); + diff --git a/texmf-dist/doc/latex/thorshammer/folder-js/aeb_pro.js b/texmf-dist/doc/latex/thorshammer/folder-js/aeb_pro.js new file mode 100644 index 00000000..31c6c2fd --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/folder-js/aeb_pro.js @@ -0,0 +1,158 @@ +/* + AEB Pro Document Assembly Methods + + Copyright (C) 2012 -- 2019 AcroTeX.Net + D. P. Story + http://www.acrotex.net + + Version 1.7.2 +*/ +// console.println("Version 1.7.2"); +if ( typeof aebTrustedFunctions == "undefined") { + aebTrustedFunctions = app.trustedFunction( function ( doc, oFunction, oArgs ) + { + app.beginPriv(); + var retn = oFunction( oArgs, doc ); + app.endPriv(); + return retn; + }); +} +aebAddWatermarkFromFile = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.addWatermarkFromFile(oArgs); + app.endPriv(); +}); +aebImportIcon = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.importIcon(oArgs); + app.endPriv(); +}); +aebInsertPages = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + var Msg=function(e){return (aebInsertPages.msg==undefined)?("Insert Pages Error: " + e.toString()):aebInsertPages.msg;} + app.beginPriv(); + try { doc.insertPages(oArgs); } catch(e) {console.println(Msg(e));} + app.endPriv(); + aebInsertPages.msg=undefined; +}) +aebAppOpenDoc = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + var Msg=function(e){return (aebAppOpenDoc.msg==undefined)?("App Open Doc Error: " + e.toString()):aebAppOpenDoc.msg;} + app.beginPriv(); + try { var retn = app.openDoc(oArgs); } catch(e) {console.println(Msg(e));} + app.endPriv(); + aebAppOpenDoc.msg=undefined; + return retn; +}) +aebImportTextData = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.importTextData(oArgs); + app.endPriv(); +}); +aebImportSound = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.importSound(oArgs); + app.endPriv(); +}); +aebSaveAs = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + app.execMenuItem("Save"); + app.endPriv(); +}); +// Version 1.7.2 +aebDocSaveAs = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + var Msg=function(e){return (aebDocSaveAs.msg==undefined)?("Doc SaveAs Error: " + e.toString()):aebDocSaveAs.msg;} + var Action=function(){return ((aebDocSaveAs.action==undefined)?null:eval(aebDocSaveAs.action));} + app.beginPriv(); + try { + return retn = doc.saveAs(oArgs); + } catch(e){console.println(Msg(e));Action();} + app.endPriv(); + aebDocSaveAs.msg=undefined; + aebDocSaveAs.action=undefined; +}); +aebExtractPages = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.extractPages(oArgs); + app.endPriv(); +}); +aebMailDoc = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.mailDoc(oArgs); + app.endPriv(); +}); +aebImportDataObject = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + return retn = doc.importDataObject(oArgs); + app.endPriv(); +}); +aebSignatureSign = app.trustPropagatorFunction( function ( oArgs, field ) +{ + app.beginPriv(); + return retn = field.signatureSign(oArgs); + app.endPriv(); +}); +aebSecurityHandlerLogin = app.trustPropagatorFunction( function ( oArgs, securityHandler ) +{ + app.beginPriv(); + return retn = securityHandler.login(oArgs); + app.endPriv(); +}); +aebSecurityGetHandler = app.trustPropagatorFunction( function ( oArgs, security ) +{ + app.beginPriv(); + return retn = security.getHandler(oArgs); + app.endPriv(); +}); +aebAppGetPath = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + var retn = app.getPath(oArgs); + app.endPriv(); + return retn; +}); +aebSignatureSetSeedValue = app.trustPropagatorFunction( function ( oArgs, field ) +{ + app.beginPriv(); + return retn = field.signatureSetSeedValue(oArgs); + app.endPriv(); +}); +aebAddIcon=app.trustPropagatorFunction( function ( oArgs, doc ) +{ + app.beginPriv(); + doc.addIcon(oArgs); + app.endPriv(); +}); +aebCreateTemplate = app.trustPropagatorFunction( function ( oArgs, doc ) +{ + var Msg=function(e){return (aebCreateTemplate.msg==undefined)?("Create Template Error: " + e.toString()):aebCreateTemplate.msg;} + app.beginPriv(); + try { doc.createTemplate(oArgs); } catch(e) {console.println(Msg(e));} + app.endPriv(); + aebCreateTemplate.msg=undefined; + +}) +// Version 1.7.1 removed doc from arg in browse and launch +aebBrowseForDoc=app.trustPropagatorFunction( function ( oArgs ) +{ + app.beginPriv(); + var retn = app.browseForDoc(oArgs); + app.endPriv(); +}); +// added aebLaunchURL Version 1.7 +aebLaunchURL=app.trustPropagatorFunction ( function ( oArgs ) +{ + app.beginPriv(); + var retn = app.launchURL(oArgs); + app.endPriv(); +}); + diff --git a/texmf-dist/doc/latex/thorshammer/install-action-seq.pdf b/texmf-dist/doc/latex/thorshammer/install-action-seq.pdf new file mode 100644 index 00000000..e7a68382 Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/install-action-seq.pdf differ diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/altclasspaths.txt b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/altclasspaths.txt new file mode 100644 index 00000000..67953493 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/altclasspaths.txt @@ -0,0 +1 @@ +# C:\Users\IEUser\Desktop\TestClass1 diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/cpquizzes.ps1 b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/cpquizzes.ps1 new file mode 100644 index 00000000..04e50266 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/cpquizzes.ps1 @@ -0,0 +1,51 @@ +# This script copies PDFs from the $startLocations to $destPath, but only +# if in a $baseName folder +$baseName="_Thor" +$classPath="C:\Users\dpstory\Desktop\Test Folder\target\myClass" +$destPath="C:\Users\dpstory\Desktop\Test Folder\target\_Thor\grade" +# Strip-and-Trim function +# Remove everything to the left of a comment character, then trim +function Strip-and-Trim { + param([string]$str) + $pos=$str.IndexOf("#") + If($pos -ne -1) { + $str=$str.substring(0,$pos) + } + $str=$str.trim() + return $str +} +# vars +$startLocations=@($classPath) +Write-Host "" +if(Test-Path -Path ./altclasspaths.txt) { + get-content ./altclasspaths.txt | %{ + $str= Strip-and-Trim($_) + if($str) { + Write-Host "Reading alternate path: $str" + $startLocations+=$str + } + } +} +$instrDest="$PWD\fromStudents" +# +# script starts here +# +$currentPath=Convert-Path . +foreach ($startLocation in $startLocations) { + Set-Location $startLocation + $numCopied=0 + Write-Host "`nCopying any PDFs files from within a `"$baseName`" subfolder of ` +`"$startLocation`" to ` +`"$instrDest`"" + Get-ChildItem -Path . -Filter "*.pdf" -Recurse | + Where-Object { $_.DirectoryName -match $baseName } -OutVariable fileName | + Copy-Item -Destination $destPath + if ($fileName.Name -eq $null) {Write-Host "`nNo files to copy"} + else { + Write-Host "`nReport:" + $numCopied=$fileName.Name.Count + $fileName.Name + } + Write-Host @( Get-ChildItem $PWD ).Count "folders examined, $numCopied files copied" + cd $currentPath +} diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkcfg.ps1 b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkcfg.ps1 new file mode 100644 index 00000000..53d67946 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkcfg.ps1 @@ -0,0 +1,71 @@ +# Make a complete cfg for thorshammer package from a csv list +# accepted list delimiters: , or ;. Spaces ar not allowed! Replace all german umlauts +# with ue, oe, ae, ss to avoid problems with thorshammer package +# +$classPath="C:\Users\dpstory\Desktop\Test Folder\target\myClass" +$instrPath="C:\Users\dpstory\Desktop\Test Folder\target\_Thor" +# Example list: +# First Name|Last Name|Folder +# Anton;Müller;AM29914M +#\classMember{Anton}{Mueller}{AM299/instructor-name} +# Anton;Müller;*C:/.../AM299 +#\classMember{Anton}{Mueller}*{C:/.../AM299/instructor-name} +# +If ( $args.Length -eq 0 ) { + Write-Host "A CSV file of the class members is required," ` + "see documentation" + exit +} else { + $listName=$args[0] + if(Test-Path -Path ./$listName.csv) { + } else { + Write-Host "Cannot find the file `"$listName.csv`" in the current folder," ` + "check the spelling, do not include the extension." + exit + } +} +get-content "$listName.csv" | foreach { +"\classMember{" + $_ ` ++ "/_Thor}" ` +-Replace ";", "}{" ` +-Replace ",","}{" ` +-Replace "{\*", "*{" } | Set-Content "convertedList.cfg" + +# Store convertedList.cfg in a variable +$convertedListCfg = get-content .\convertedList.cfg -Raw + +# function to replace umlauts +# https://www.datenteiler.de/powershell-umlaute-ersetzen/ +function Replace-Umlaute ([string]$s) { + $UmlautObject = New-Object PSObject | Add-Member -MemberType NoteProperty -Name Name -Value $s -PassThru + + # hash tables are by default case insensitive + # we have to create a new hash table object for case sensitivity + + $characterMap = New-Object system.collections.hashtable + $characterMap.ä = "ae" + $characterMap.ö = "oe" + $characterMap.ü = "ue" + $characterMap.ß = "ss" + $characterMap.Ä = "Ae" + $characterMap.Ü = "Ue" + $characterMap.Ö = "Oe" + + foreach ($property in "Name") { + foreach ($key in $characterMap.Keys) { + $UmlautObject.$property = $UmlautObject.$property -creplace $key,$characterMap[$key] + } + } + $UmlautObject +} + +# replace umlauts in .cfg and make a correctedListCfg +$correctedListCfg = Replace-Umlaute "$convertedListCfg" +$correctedListCfg.Name + +# Finally append correctedListCfg to desired +# cfg file, usually 00-class.cfg +add-content "00-class.cfg" "\classPath{$classPath)" +add-content "00-class.cfg" "\instrPath{$instrPath}" +add-content "00-class.cfg" $correctedListCfg.Name +Remove-Item convertedList.cfg diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkfolders.ps1 b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkfolders.ps1 new file mode 100644 index 00000000..7f7fcc3e --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/mkfolders.ps1 @@ -0,0 +1,60 @@ +$classPath="C:\Users\dpstory\Desktop\Test Folder\target\myClass" +# Create class folders +If ( $args.Length -eq 0 ) { + Write-Host "A CVS file of the class members is required," ` + "see documentation" + exit +} else { + $listName=$args[0] + if(Test-Path -Path ./$listName.csv) { + } else { + Write-Host "Cannot find the file `"$listName.csv`" in the current folder," ` + "check the spelling, do not include the extension." + exit + } +} +get-content "$listName.csv" | foreach { +$_ +">_Thor" -Replace ";","," } | Set-Content "commaList.csv" + +$argList=@() +get-content "commaList.csv" | %{ +# Write-Host "$_" + $split=$_.split(",") +# Write-Host $split[2] + $argList+=$split[2] +} +$currentPath=Convert-Path . +cd $classPath +Write-Host "Creating folder structure at `$classPath`"," ` + "with some exceptions" +for ($i=0; $i -lt $argList.length; $i++) { + $arg=$argList[$i] + $splitTwo=$argList[$i].split(">") + $firstName=$splitTwo[0] + $secondName=$splitTwo[1] + if ($firstName[0] -eq "*") { + $arg=$arg.substring(1) + $msg="Parsing the full path $arg" -Replace ">","/" + Write-Host $msg + Write-Host "Creating exceptional folders" + $firstName=$firstName.substring(1) +#Write-Host "$firstName" + Write-Host " Creating folder: $firstName" + New-Item $firstName -ErrorAction:Ignore -ItemType directory + $secondName=$firstName+"/$secondName" +#Write-Host "$secondName" + Write-Host " Creating folder: $secondName" + New-Item $secondName -ErrorAction:Ignore -ItemType directory + } else { + $msg="Parsing the relative path $arg" -Replace ">","/" + Write-Host $msg + Write-Host " Creating folder: $firstName" + New-Item $firstName -ErrorAction:Ignore -ItemType directory + cd $firstName + Write-Host " Creating subfolder of $firstName named: $secondName" + New-Item $secondName -ErrorAction:Ignore -ItemType directory + cd .. + } +} +cd $currentPath +Remove-Item commaList.csv diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/rmquizzes.ps1 b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/rmquizzes.ps1 new file mode 100644 index 00000000..02b35341 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/rmquizzes.ps1 @@ -0,0 +1,51 @@ +# Get-ExecutionPolicy +# Set-ExecutionPolicy RemoteSigned +# This script removes (deletes) PDFs from the $startLocation, but only if in a $baseName folder +$baseName="_Thor" +$classPath="C:\Users\dpstory\Desktop\Test Folder\target\myClass" +# +# Strip-and-Trim function +# Remove everything to the left of a comment character, then trim +function Strip-and-Trim { + param([string]$str) + $pos=$str.IndexOf("#") + If($pos -ne -1) { + $str=$str.substring(0,$pos) + } + $str=$str.trim() + return $str +} +# vars +$startLocations=@($classPath) +Write-Host "" +if(Test-Path -Path ./altclasspaths.txt) { + get-content ./altclasspaths.txt | %{ + $str= Strip-and-Trim($_) + if($str) { + Write-Host "Reading alternate path: $str" + $startLocations+=$str + } + } +} +$instrDest="$PWD\fromStudents" +# +# script starts here +# +$currentPath=Convert-Path . +foreach ($startLocation in $startLocations) { + Set-Location $startLocation + $numDel=0 + Write-Host "`nDeleting the following PDFs files from within a `"$baseName`" subfolder of ` +`"$startLocation`"" + Get-ChildItem -Path . -Filter "*.pdf" -Recurse | + Where-Object { $_.DirectoryName -match $baseName } -OutVariable fileName | + Remove-Item + if ($fileName.Name -eq $null) {Write-Host "`nNo files to delete"} + else { + Write-Host "`nReport: deleting files," + $numDel=$fileName.Name.Count + $fileName.Name + } + Write-Host @( Get-ChildItem $PWD ).Count "folders examined, $numDel files deleted" + cd $currentPath +} diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/runps1.bat b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/runps1.bat new file mode 100644 index 00000000..5960b5ba --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/runps1.bat @@ -0,0 +1,2 @@ +rem echo "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 +PowerShell.exe -ExecutionPolicy Bypass -Command "& './%1' %2" diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/sample-list.csv b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/sample-list.csv new file mode 100644 index 00000000..0f97aa0a --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/standalone/sample-list.csv @@ -0,0 +1,3 @@ +Mühle;Wäter;MW634B +Anton,Müller,AM256M +Laura,Vögt,LM356B diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/runps1.bat b/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/runps1.bat new file mode 100644 index 00000000..5960b5ba --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/runps1.bat @@ -0,0 +1,2 @@ +rem echo "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 +PowerShell.exe -ExecutionPolicy Bypass -Command "& './%1' %2" diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/sample-vars.txt b/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/sample-vars.txt new file mode 100644 index 00000000..6b5a2922 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/sample-vars.txt @@ -0,0 +1,8 @@ +alg1 # class +1 # number +maths # subject +factoring # theme +THOR # instrName +01.01.2019 # date +60 Min. # time +C:/temp # classPath diff --git a/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/thmclass.ps1 b/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/thmclass.ps1 new file mode 100644 index 00000000..2dcbc65c --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/system-scripts/thors-structure/thmclass.ps1 @@ -0,0 +1,713 @@ +# Version 1.3 changes +# ===================================================================================================== +# copyka.ps1 allows a comment character (#) +# delka.ps1 allows a comment character (#) +# ===================================================================================================== +# Version 1.2 changes +# ===================================================================================================== +# removed moveka.ps1 +# removed old version comments +# added template for altclasspath +# removed .ps1 from BAT helper file, that way one can easiear hit TAB for autocompletion in comamnd shell +# OPEN line 92: copyka.ps1 --> lines starting with # are *not* ignored at least here +# Workaround does not help: (get-content ./altclasspaths.txt) -notmatch '^#' WHY? + +# ===================================================================================================== +# +# This script makes a custom class folder for thorshammer with +# needed folders, adjusted path settings and templates for tex, cfg etc. +# +# Set path for thorshammer (local texmf dir} for Windows/Linux +# This has to be done only once +$pathThorshammerWin="C:\Users\$env:UserName\texmf\tex\latex\thorshammer" # Windows +$pathThorshammerWin="C:\Users\Public\Documents\My TeX Files\tex\latex\aeb\thorshammer" +$pathThorshammerLin="/home/manjothor/texmf/tex/latex/thorshammer" # Linux + +# Store the system locale in a var. We need them later in the script for localization +$locale = Get-UICulture +$myLocale = "de" + +# Remove everything to the left of a comment character, then trim +function Strip-and-Trim { + param([string]$str) + $pos=$str.IndexOf("#") + If($pos -ne -1) { + $str=$str.substring(0,$pos) + } + $str=$str.trim() + return $str +} +Write-Host "There are" $args.Length "arguments"; +$argList=@() +$listOfEight=$args[0] +if(Test-Path -Path ./$listOfEight) { + get-content $args[0] | %{ + Write-Host "Line: $_" + $argList+=$_ + } + $class = Strip-and-Trim($argList[0]) + $number = Strip-and-Trim($argList[1]) + $subject = Strip-and-Trim($argList[2]) + $theme = Strip-and-Trim($argList[3]) + $instrName = Strip-and-Trim($argList[4]) + $date = Strip-and-Trim($argList[5]) + $time = Strip-and-Trim($argList[6]) + $classPath= Strip-and-Trim($argList[7]) + +# Remove whitespace in $class and $instrName because we don't need whitespace +# in this two vars. + $class = $class.replace(' ','') + $instrName = $instrName.replace(' ','') + +############ +# folders # +############ + New-Item $class -ItemType directory + cd $class + New-Item $instrName -ItemType directory + Set-Location "$instrName" + New-Item backup -ItemType directory + If ($locale -like "*$myLocale*") { + New-Item vonSUS -ItemType directory + New-Item anSUS -ItemType directory + } else { + New-Item fromStudents -ItemType directory + New-Item toStudents -ItemType directory + } +} else { + Write-Host "The file" $listOfEight "cannot be found in the current folder," ` +"check the spelling, include the extension." + exit +} + +############## +# copyscript # +############## +# Version 1.3 +New-Item copyka.ps1 -ItemType file +Set-Content ./copyka.ps1 '# Get-ExecutionPolicy +# Set-ExecutionPolicy RemoteSigned +# This script copies PDFs from the $startLocation to $instrDest, but only +# if in a $instrName folder +# +# Strip-and-Trim function +# Remove everything to the left of a comment character, then trim +function Strip-and-Trim { + param([string]$str) + $pos=$str.IndexOf("#") + If($pos -ne -1) { + $str=$str.substring(0,$pos) + } + $str=$str.trim() + return $str +} +# vars +$instrName="#instrName" +$startLocations=@("#classPath") +Write-Host "" +if(Test-Path -Path ./altclasspaths.txt) { + get-content ./altclasspaths.txt | %{ + $str= Strip-and-Trim($_) + if($str) { + Write-Host "Reading alternate path: $str" + $startLocations+=$str + } + } +} +$instrDest="$PWD\#from" +# +# script starts here +# +$currentPath=Convert-Path . +foreach ($startLocation in $startLocations) { + Set-Location $startLocation + $numCopied=0 + Write-Host "`nCopying any PDFs files from within a `"$instrName`" subfolder of ` +`"$startLocation`" to ` +`"$instrDest`"" + Get-ChildItem -Path . -Filter "*.pdf" -Recurse | + Where-Object { $_.DirectoryName -match $instrName } -OutVariable fileName | + Copy-Item -Destination $instrDest + if ($fileName.Name -eq $null) {Write-Host "`nNo files to copy"} + else { + Write-Host "`nReport:" + $numCopied=$fileName.Name.Count + $fileName.Name + } + Write-Host @( Get-ChildItem $PWD ).Count "folders examined, $numCopied files copied" + cd $currentPath +}' +# replace markers with content of vars: #instrName, #classPath +(Get-Content -Path .\copyka.ps1) | ForEach-Object { + $_ -Replace '#instrName', $instrName ` + -Replace '#classPath', $classPath } | Set-Content -Path .\copyka.ps1 -encoding UTF8 + +If ($locale -like "*$myLocale*") { + (Get-Content -Path .\copyka.ps1) | ForEach-Object { + $_ -Replace '#from', 'vonSUS' } | Set-Content -Path .\copyka.ps1 -encoding UTF8 +} else { + (Get-Content -Path .\copyka.ps1) | ForEach-Object { + $_ -Replace '#from', 'fromStudents' } | Set-Content -Path .\copyka.ps1 -encoding UTF8 +} + +################# +# delete script # +################# +# Version 1.3 +Set-Content ./delka.ps1 '# Get-ExecutionPolicy +# Set-ExecutionPolicy RemoteSigned +# This script removes (deletes) PDFs from the $startLocation, but only if in a $instrName folder +# +# Strip-and-Trim function +# Remove everything to the left of a comment character, then trim +function Strip-and-Trim { + param([string]$str) + $pos=$str.IndexOf("#") + If($pos -ne -1) { + $str=$str.substring(0,$pos) + } + $str=$str.trim() + return $str +}# vars +# +$instrName="#instrName" +$startLocations=@("#classPath") +Write-Host "" +if(Test-Path -Path ./altclasspaths.txt) { + get-content ./altclasspaths.txt | %{ + $str= Strip-and-Trim($_) + if($str) { + Write-Host "Reading alternate path: $str" + $startLocations+=$str + } + } +} +$instrDest="$PWD\#from" +# +# script starts here +# +$currentPath=Convert-Path . +foreach ($startLocation in $startLocations) { + Set-Location $startLocation + $numDel=0 + Write-Host "`nDeleting the following PDFs files from within a `"$instrName`" subfolder of ` +`"$startLocation`"" + Get-ChildItem -Path . -Filter "*.pdf" -Recurse | + Where-Object { $_.DirectoryName -match $instrName } -OutVariable fileName | + Remove-Item + if ($fileName.Name -eq $null) {Write-Host "`nNo files to delete"} + else { + Write-Host "`nReport: deleting files," + $numDel=$fileName.Name.Count + $fileName.Name + } + Write-Host @( Get-ChildItem $PWD ).Count "folders examined, $numDel files deleted" + cd $currentPath +}' +# replace markers with content of vars: #instrName, #classPath +(Get-Content -Path .\delka.ps1) | ForEach-Object { + $_ -Replace '#instrName', $instrName ` + -Replace '#classPath', $classPath } | Set-Content -Path .\delka.ps1 -encoding UTF8 + +If ($locale -like "*$myLocale*") { + (Get-Content -Path .\delka.ps1) | ForEach-Object { + $_ -Replace '#from', 'vonSUS' } | Set-Content -Path .\delka.ps1 -encoding UTF8 +} else { + (Get-Content -Path .\delka.ps1) | ForEach-Object { + $_ -Replace '#from', 'fromStudents' } | Set-Content -Path .\delka.ps1 -encoding UTF8 +} + +##Begin Version 1.2 +########################## +# altclasspaths template # +########################## +Set-Content ./altclasspaths.txt -encoding UTF8 '# C:\Users\IEUser\Desktop\TestClass1' + +##End Version 1.2 + +############################# +# csv to cfg convert script # +############################# +Set-Content ./csvTOcfg.ps1 '# Make a complete cfg for thorshammer package from a csv list +# accepted list delimiters: , or ;. Spaces ar not allowed! Replace all german umlauts +# with ue, oe, ae, ss to avoid problems with thorshammer package +# +# Example list: +# First Name|Last Name|Folder +# Anton;Müller;AM29914M +#\classMember{Anton}{Mueller}{AM299/instructor-name} +# Anton;Müller;*C:/.../AM299 +#\classMember{Anton}{Mueller}*{C:/.../AM299/instructor-name} +# +If ( $args.Length -eq 0 ) { + Write-Host "A CSV file of the class members is required," ` + "see documentation" + exit +} else { + $listName=$args[0] + if(Test-Path -Path ./$listName.csv) { + } else { + Write-Host "Cannot find the file `"$listName.csv`" in the current folder," ` + "check the spelling, do not include the extension." + exit + } +}' +###################### +# Script starts here # +######################' +# Now append the script itself, this way we have to maintain only one script +# Remark: we must escape $ and ` with `$ and `` +Add-Content ./csvTOcfg.ps1 @" +get-content "`$listName.csv" | foreach { +"\classMember{" + `$_ `` ++ "/`#instrName}" `` +-Replace ";", "}{" `` +-Replace ",","}{" `` +-Replace "{\*", "*{" } | Set-Content "convertedList.cfg" + +# Store convertedList.cfg in a variable +`$convertedListCfg = get-content .\convertedList.cfg -Raw + +# function to replace umlauts +# https://www.datenteiler.de/powershell-umlaute-ersetzen/ +function Replace-Umlaute ([string]`$s) { + `$UmlautObject = New-Object PSObject | Add-Member -MemberType NoteProperty -Name Name -Value `$s -PassThru + + # hash tables are by default case insensitive + # we have to create a new hash table object for case sensitivity + + `$characterMap = New-Object system.collections.hashtable + `$characterMap.ä = "ae" + `$characterMap.ö = "oe" + `$characterMap.ü = "ue" + `$characterMap.ß = "ss" + `$characterMap.Ä = "Ae" + `$characterMap.Ü = "Ue" + `$characterMap.Ö = "Oe" + + foreach (`$property in "Name") { + foreach (`$key in `$characterMap.Keys) { + `$UmlautObject.`$property = `$UmlautObject.`$property -creplace `$key,`$characterMap[`$key] + } + } + `$UmlautObject +} + +# replace umlauts in $convertedList.cfg and make a correctedListCfg +`$correctedListCfg = Replace-Umlaute "`$convertedListCfg" +`$correctedListCfg.Name + +# Finally append correctedListCfg to desired +# cfg file, usually $class.cfg +add-content "..\`#class" `$correctedListCfg.Name +Remove-Item convertedList.cfg +"@ + +# Set correct class name +(Get-Content "csvTOcfg.ps1") | ForEach-Object { + $_ -Replace '#class', "00-$class.cfg" ` + -Replace '#instrName', $instrName } | Set-Content "csvTOcfg.ps1" -encoding UTF8 + +###################### +# General helper BAT # +###################### +New-Item "runps1.bat" -ItemType file +Set-Content "runps1.bat" ` +'rem echo "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 +PowerShell.exe -ExecutionPolicy Bypass -Command "& ''./%1'' %2"' ##Begin Version 1.2 + +################## +# class folders # +################## +New-Item classFolders.ps1 -ItemType file +Set-Content ./classFolders.ps1 '# Create class folders +If ( $args.Length -eq 0 ) { + Write-Host "A CVS file of the class members is required," ` + "see documentation" + exit +} else { + $listName=$args[0] + if(Test-Path -Path ./$listName.csv) { + } else { + Write-Host "Cannot find the file `"$listName.csv`" in the current folder," ` + "check the spelling, do not include the extension." + exit + } +} +get-content "$listName.csv" | foreach { +$_ +">#instrName" -Replace ";","," } | Set-Content "commaList.csv" + +$argList=@() +get-content "commaList.csv" | %{ +# Write-Host "$_" + $split=$_.split(",") +# Write-Host $split[2] + $argList+=$split[2] +} +$currentPath=Convert-Path . +cd "#classPath" +Write-Host "Creating folder structure at `"#classPath`"," ` + "with some exceptions" +for ($i=0; $i -lt $argList.length; $i++) { + $arg=$argList[$i] + $splitTwo=$argList[$i].split(">") + $firstName=$splitTwo[0] + $secondName=$splitTwo[1] + if ($firstName[0] -eq "*") { + $arg=$arg.substring(1) + $msg="Parsing the full path $arg" -Replace ">","/" + Write-Host $msg + Write-Host "Creating exceptional folders" + $firstName=$firstName.substring(1) +#Write-Host "$firstName" + Write-Host " Creating folder: $firstName" + New-Item $firstName -ErrorAction:Ignore -ItemType directory + $secondName=$firstName+"/$secondName" +#Write-Host "$secondName" + Write-Host " Creating folder: $secondName" + New-Item $secondName -ErrorAction:Ignore -ItemType directory + } else { + $msg="Parsing the relative path $arg" -Replace ">","/" + Write-Host $msg + Write-Host " Creating folder: $firstName" + New-Item $firstName -ErrorAction:Ignore -ItemType directory + cd $firstName + Write-Host " Creating subfolder of $firstName named: $secondName" + New-Item $secondName -ErrorAction:Ignore -ItemType directory + cd .. + } +} +cd $currentPath +Remove-Item commaList.csv' +# +# replace markers with content of vars: #instrName, #classPath +(Get-Content -Path .\classFolders.ps1) | ForEach-Object { + $_ -Replace "#instrName", $instrName ` + -Replace "#classPath", $classPath } | Set-Content -Path .\classFolders.ps1 + +############################ +# Sample csv file # +############################ +New-Item sample-list.csv -ItemType file +Set-Content ./sample-list.csv ` +'Mühle;Wäter;MW634B +Anton,Müller,AM256M +Laura,Vögt,LM356B' + +########################################### +# copy container.pdf, terminate-batch.pdf # +########################################### +If (Test-Path $pathThorshammerWin) { + Copy-Item "$pathThorshammerWin\container.pdf" -Destination "$PWD" + Copy-Item "$pathThorshammerWin\terminate-batch.pdf" -Destination "$PWD" +} +If (Test-Path $pathThorshammerLin){ +Copy-Item "$pathThorshammerLin/container.pdf" -Destination "$PWD" +Copy-Item "$pathThorshammerLin/terminate-batch.pdf" -Destination "$PWD" +} + +################ +# tex template # +################ +cd .. +New-Item "tex-template.tex" -ItemType file + +If ($locale -like "*$myLocale*") { +# German ###################################### +Set-Content "tex-template.tex" '%% Customize template ! %% +\documentclass[fontsize=11pt]{scrartcl} +\usepackage[% +german, +pro, +usesf, +navibar, +forcolorpaper +%forpaper +]{web} +\usepackage[top=20mm,left=20mm,right=20mm,bottom=25mm]{geometry} +\usepackage[usesumrytbls,allowrandomize]{exerquiz} +\usepackage{ran_toks} +\usepackage[% +% usebatch % copy to class folder +batchdistr % only copy to instructors folder +% testmode % testing quizzes +]{thorshammer} +\hypersetup{pdfencoding=auto} % include or remove hyperref options +%\usepackage{thorshammerConf} % place your own sty file here +\usepackage[autostyle=true]{csquotes} % change quotes globally + +\DeclareQuiz{q#number} +\setInitMag{fitwidth} +\hypersetup{pdfpagelayout=OneColumn} +\reversemarginpar +% It is important to freeze the seed to that (1) you can reproduce the exact +% same quiz at a later time; (2) allow content written to the AUX file to +% come up to date. This is important when using summary tables. +\useThisSeed{1344524586} + +% Class Path +\InputClassData{00-#class} +\autoCopyOn +% \autoCopyOff + +% Cover pages +%\DeclareCoverPage{0} + +% Header settings +\thQzName{#theme} % Thema +\thQzHeaderL{#class} % Klasse +\thQzHeaderCQ{#subject: \thqzname} +\thQzHeaderCS{Lösungen: \thqzname} + +% Title +\title{#class} +\subject{#subject} +\author{#instrName} +\keywords{#time} +\university{Freiherr-vom-Stein-Berufskolleg} % change to your institution +\version{#number} +\copyrightyears{#date} + +% input web.cfg (again) to declare or define commands +\inputWebCfg + +\begin{makeClassFiles} +\sadMultQuizzes +\end{makeClassFiles} + +\begin{document} +\makeinlinetitle +% Instructions + +% Declare Quiz bodys +\declareQuizBody{qzbody1} +%\declareQuizBody{qzbody2} +%\declareQuizBody{qzbody3} +%\declareQuizBody{qzbody4} + +\begin{qzbody1} +\bRTVToks{\currQuiz} +% Change margin settings for summary tables, and set it back after +% \thQuizHeader execution +\newgeometry{top=20mm,left=30mm,right=20mm,bottom=25mm} +\thQuizHeader +\newgeometry{top=20mm,left=20mm,right=20mm,bottom=25mm} + +\begin{quiz*}{\currQuiz} +% Bearbeiten Sie folgende Aufgaben. +\begin{questions} +\begin{rtVW} +\section{myTitle} +\item\PTs{2} my question text + +\end{rtVW} + +%% Change nothing here %% +\eRTVToks\displayListRandomly{\thisQuiz} +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer +\end{qzbody1} +% Randomize questions Now we input the qzbody back in two times, though it can +% be more than that. The quiz name modified in each instance. Each instance of +% the quiz has a randomized order +% +\InputQuizBody{qzbody1} +%\InputQuizBody{qzbody1} +%\InputQuizBody{qzbody1} +%\InputQuizBody{qzbody2} +\end{document}' +########################################### +} else { +# English ################################# +Set-Content "tex-template.tex" '%% Customize template ! %% +\documentclass{article} +\usepackage{amstext} +\usepackage{web} +\usepackage[usesumrytbls,allowrandomize]{exerquiz} +\usepackage{ran_toks} +\usepackage[usebatch]{thorshammer} + +\DeclareQuiz{q#number} + +% It is important to freeze the seed to that (1) you can reproduce the exact +% same quiz at a later time; (2) allow content written to the AUX file to +% come up to date. This is important when using summary tables. +\useThisSeed{1344524586} + +\setInitMag{fitwidth} +\hypersetup{pdfencoding=auto} +\reversemarginpar + +\showCreditMarkup + +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] +\PTsHook{($\eqPTs^{\text{pts}}$)} +\useMCCircles + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% For headers, title and other fine grained settings % +% refer to the thorshammer doku! % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Class Path +\InputClassData{00-#class} +\autoCopyOn +% \autoCopyOff + +% Cover pages +%\DeclareCoverPage{0} + +% Header settings +\thQzName{#theme} % topic +\thQzHeaderL{#class} % class +\thQzHeaderCQ{#subject: \thqzname} +\thQzHeaderCS{Solutions: \thqzname} + +% Title +\title{#class} +\subject{#subject} +\author{#instrName} +\keywords{#time} +\university{AcroTeX.edu} % change to your institution +\version{#number} +\copyrightyears{#date} + +% input web.cfg (again) to declare or define commands +\inputWebCfg + +\begin{makeClassFiles} +\sadMultQuizzes +\end{makeClassFiles} + +\begin{document} +\declareQuizBody{qzbody1} +\begin{qzbody1} + +\bRTVToks{\currQuiz} + +\thQuizHeader + +% Instructions +\begin{quiz*}{\currQuiz} +Solve each of these problems, passing is 100\%. +\begin{questions} +\begin{rtVW} + \item\PTs{3} Answer the question... + +\end{rtVW} +%% Change nothing here %% +\eRTVToks +\displayListRandomly{\thisQuiz} +\end{questions} +\writeProListAux +\end{quiz*}\quad\thQuizTrailer +\end{qzbody1} +% Randomize questions Now we input the qzbody back in two times, though it can +% be more than that. The quiz name modified in each instance. Each instance of +% the quiz has a randomized order +% +\InputQuizBody{qzbody1} +%\InputQuizBody{qzbody1} +%\InputQuizBody{qzbody1} +%\InputQuizBody{qzbody2} +\end{document}' +} + +################################### +# Generate TEX file from template # +################################### +New-Item "genquiz.ps1" -ItemType file +Set-Content "genquiz.ps1" ` +'# Remove everything to the left of a comment character, then trim +function Strip-and-Trim { + param([string]$str) + $pos=$str.IndexOf("#") + If($pos -ne -1) { + $str=$str.substring(0,$pos) + } + $str=$str.trim() + return $str +} +$argList=@() +get-content ../#varsList | %{ + Write-Host "Line: $_" + $argList+=$_ + } +$class = Strip-and-Trim($argList[0]) +$number = Strip-and-Trim($argList[1]) +$subject = Strip-and-Trim($argList[2]) +$theme = Strip-and-Trim($argList[3]) +$instrName = Strip-and-Trim($argList[4]) +$date = Strip-and-Trim($argList[5]) +$time = Strip-and-Trim($argList[6]) +$classPath= Strip-and-Trim($argList[7]) + +$templateName="$number-$class-$subject.tex" +Copy-Item ./tex-template.tex ./$templateName + +# replace markers with vars +(Get-Content $templateName) | ForEach-Object { + $_ -Replace ''#instrName'', $instrName ` + -Replace ''#class'', $class ` + -Replace ''#time'', $time ` + -Replace ''#number'', $number ` + -Replace ''#theme'', $theme ` + -Replace ''#subject'', $subject ` + -Replace ''#date'', $date } | Set-Content $templateName -encoding UTF8` +# Remove whitespace and umlauts from file name +Get-ChildItem *.tex | Rename-Item -NewName { + $_.Name -replace '' '',''-'' ` + -replace ''ä'',''ae'' ` + -replace ''ö'',''oe'' ` + -replace ''ü'',''ue'' ` + -replace ''ß'',''ss'' }' +(Get-Content "genQuiz.ps1") | ForEach-Object { + $_ -Replace '#varsList', $listOfEight } | Set-Content "genQuiz.ps1" +# Remove whitespace from tex template file +Get-ChildItem *.tex | Rename-Item -NewName { $_.Name -replace ' ','-' } + +###################### +# General helper BAT # +###################### +New-Item "runps1.bat" -ItemType file +Set-Content "runps1.bat" ` +'rem echo "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 +PowerShell.exe -ExecutionPolicy Bypass -Command "& ''./%1'' %2"' ##Begin Version 1.2 + +#################### +# web.cfg template # +#################### +New-Item "web.cfg" -ItemType file +Set-Content "web.cfg" ` +'% +% AeB Web Configuration file +% +\ExecuteOptions{dvips} +\bWebCustomize +% Insert redefinitions between these two marks +\eWebCustomize' + +################ +# cfg template # +################ +New-Item "00-$class.cfg" -ItemType file +Set-Content "00-$class.cfg" '%reset the paths for \instrPath and \classPath for your system +% Use relative (*!) paths here for instructor according to dir, where tex file is located +\classPath{/#class} +\instrPath*{#instrName/backup} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Syntax: +% \classMember{firstname}{lastname}{rel-path} +% \classMember{firstname}{lastname}*{full-path} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%' + +# replace markers with content of vars +$pattern = "\\" +$classPath = $classPath -replace $pattern, "/" +(Get-Content "00-$class.cfg") | ForEach-Object { + $_ -Replace '#instrName', $instrName ` + -Replace '#class', $classPath ` + -Replace ':', '' } | Set-Content "00-$class.cfg" -encoding UTF8 +cd .. diff --git a/texmf-dist/doc/latex/thorshammer/terminate-batch.pdf b/texmf-dist/doc/latex/thorshammer/terminate-batch.pdf new file mode 100644 index 00000000..61f4e377 Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/terminate-batch.pdf differ diff --git a/texmf-dist/doc/latex/thorshammer/terminate-batch.tex b/texmf-dist/doc/latex/thorshammer/terminate-batch.tex new file mode 100644 index 00000000..6c1303dc --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/terminate-batch.tex @@ -0,0 +1,24 @@ +%% +%% This is file `terminate-batch.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% thorshammer.dtx (with options: `bterminate') +%% +\documentclass{article} +\usepackage[designi]{web} +\parindent0pt\parskip6pt +\begin{document} +\null\vfil +\begin{center} +\fbox{\begin{minipage}{.67\linewidth} +This file is the last to be processed by \textsf{Thor's way}, +the batch action identifies it and gracefully terminates. +\end{minipage}} +\end{center} +\vfil +\end{document} +\endinput +%% +%% End of file `terminate-batch.tex'. diff --git a/texmf-dist/doc/latex/thorshammer/thmclass.pdf b/texmf-dist/doc/latex/thorshammer/thmclass.pdf new file mode 100644 index 00000000..50e2da72 Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/thmclass.pdf differ diff --git a/texmf-dist/doc/latex/thorshammer/thmclass.tex b/texmf-dist/doc/latex/thorshammer/thmclass.tex new file mode 100644 index 00000000..1603ce6c --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/thmclass.tex @@ -0,0 +1,970 @@ +\RequirePackage[use=publish]{spdef} +\documentclass{article} +\usepackage[fleqn]{amsmath} +\usepackage[designi,forcolorpaper,latextoc,extended]{web} +\usepackage{eforms} +\usepackage{dirtree} +\usepackage{fancyvrb} + +\usepackage{xbmks} +\xbmksetup{colors={int=red},styles={intbf}} +%\DeclareInitView{layoutmag={navitab:UseOutlines}} +\hypersetup{pdfpagemode=UseOutlines} + + +\ifpublish % developer packages +\def\useThese{\usepackage[altbullet]{lucidbry} +\usepackage[active]{srcltx}} +\expandafter\useThese\fi + +\newcommand\newtopic{\par\ifdim\lastskip>0pt\relax\vskip-\lastskip\fi +\vskip\medskipamount} + +\tocPartTitle{\tops{\protect\makebox[0pt][r]{\thepart\hspace{1em}}}{\thepart\space}#1} +\let\partSave\part +\def\part#1{\par\addvspace{4ex}\bgroup\let\newpage\relax\partSave{#1}\egroup\addvspace{2ex}} + +\let\tops\texorpdfstring + +\DeclareDocInfo +{ + university={Acro\negthinspace\TeX.Net}, +% title={The \textsf{thorshammer} package\tops{\\[1ex]}{: }% +% Documentation for \tops{\textsf}{}{thmclass.ps1}}, + title={The \textsf{thorshammer} package\tops{\\[1ex]}{: }% + Documentation for the system scripts}, + author={D. P. Story \& Thorsten Grothe}, + email={dpstory@acrotex.net}, + subject=Documentation for thmclass.ps1, + talksite={\url{www.acrotex.net}}, + version={1.5.7, 2020/01/13}, + Keywords={LaTeX, AcroTeX, Powershell, thorshammer}, + copyrightStatus=True, + copyrightNotice={Copyright (C) \the\year, D. P. Story}, + copyrightInfoURL={http://www.acrotex.net} +} + + +\useFullWidthForPaper + +\def\dps{$\mbox{$\mathfrak D$\kern-.3em\mbox{$\mathfrak P$}% + \kern-.6em \hbox{$\mathcal S$}}$} +\let\pkg\textsf +\def\cs#1{\texttt{\char`\\#1}} +\let\opt\textsf +\let\app\textsf +\let\uif\textsf +\def\thescript{\texttt{thmclass.ps1}} +\def\thebatch{\texttt{runps1.bat}} +\def\dtt#1{\texttt{\$#1}} +\def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}} +\def\meta#1{\textsl{\texttt{#1}}} +\def\darg#1{\texttt{\char123\relax#1\char125\relax}} +\newenvironment{lquote} + {\list{}{}% + \item\relax} + {\endlist} + +\makeatletter +%\setlength{\DT@offset}{(\linewidth-1.4in)/2} +\renewcommand{\paragraph} + {\@startsection{paragraph}{4}{0pt}{6pt}{-3pt}{\bfseries}} +\renewcommand{\subparagraph} + {\@startsection{subparagraph}{5}{\parindent}{6pt}{-3pt}% + {\normalfont\normalsize\bfseries}} +\def\chnglabelname#1{\edef\@currentlabelname{#1}} +\makeatother + +\begin{document} + +\maketitle + +\pdfbookmarkx[1]{Title Page}[action={\Named{FirstPage}}]{TitlePage} +\pdfbookmarkx[1]{The thorshammer package}[action={\GoToR/F(thors-the-man.pdf)/D[0 /Fit]},color=blue,style={bf}]{thorhammer} +\pdfbookmarkx[1]{Links to AcroTeX.Net}[action={/S/GoTo/D(undefined)},% + color=magenta,style={bf}]{acrotex} +\belowpdfbookmarkx{http://www.acrotex.net}[action={\URI{http://www.acrotex.net}},% + color=magenta,style={bf}]{home} +\belowpdfbookmarkx{http://blog.acrotex.net}[action={\URI{http://blog.acrotex.net}},% + color=magenta,style={bf}]{blog} + + +\selectColors{linkColor=black} +\tableofcontents +\selectColors{linkColor=webgreen} + +\section{Introduction} + +\textbf{\hyperref[PartI]{Part I}} describes how to execute {\thescript} and +documents all the subordinate files and folders it generates. +The \thescript\space file is a \app{Powershell} script file +written, for the most part, \emph{by the great Thor himself} to +meet the needs of his classes. It can be used ``as is'' or +modified to conform it to your requirements. The script is +designed to be used with the \pkg{thorshammer} package, but this +is not a requirement. + +The file structure of Thor may not be for everyone, \textbf{\hyperref[PartII]{Part II}} describes a set +of ``standalone'' scripts, which were derived from the scripts in \textbf{Part I}. + +\paragraph*{From the Acro\negthinspace\TeX{} Legal Department.} +We offer no guarantees and accept no liabilities. Test the +scripts extensively to be sure they are working for you. Modify the script +as you will, but don't bother us with your changes, unless they are improvements. %\verb|:-{)| + + +\paragraph*{Platforms.} The script has been tested on +\textsf{Windows OS} and \app{Linux}. It is our understanding +that \app{Powershell} can be installed and executed on +\textsf{MacOS}, so this script \emph{may} have use on that +platform as well. + +\part{Using the Thor system}\label{PartI} + +\noindent Thor has developed his own file structure for his class, this +structure may be useful to your own classroom. Here, we describe the system +that has been developed. Carefully read this part of the documentation to +determine if Thor's scheme can work for you. \medskip + +\section{Deploying {\thescript} \textsl{et al}} + +Locate the three files \thescript, \thebatch, and \texttt{sample-vars.txt} +from the \texttt{system-scripts} folder of the +\pkg{thorshammer} distribution. + +\paragraph*{The first things first.} (1) \emph{Copy} +\thescript, \thebatch, and \texttt{sample-vars.txt} to a +working folder. (2) Open the \app{Powershell} file \thescript{} +in a text editor and edit the value of the variable appropriate to your platform +\texttt{\$pathThorshammerWin} or \texttt{\$pathThorshammerLin}, +being sure the default path points to your \pkg{thorshammer} +folder, and if not, modify the path to point to the folder +of the \pkg{thorshammer} distribution on your computer.\footnote{The purpose of this is to +grab the two support files \texttt{container.pdf} and +\texttt{terminate-batch.pdf}. If your {\TeX} installation has +installed these two files elsewhere, find them, and modify the +path to point to the folder containing these two files.} + +\section{Executing \thescript} + +On \app{Windows}, the easiest way to execute \thescript\space is +through the BAT file \thebatch.\footnote{The authors have little +knowledge of how to do this on \app{Mac OS}. An interested user +on \app{Mac OS} would need to advise us.} Running the script +requires the input of eight (8) values for variables, these are +listed below and described in the order they are expected to be +input. + +\paragraph*{Eight basic variables}\label{para:eight} +\begin{enumerate} + \item \dtt{class}: The name of the class, could be name as + listed in the college catalog (MAT101, STA221, HH21B, + A21A, WF23, \dots) or something more understandable (calc1, + alg1, euhist, \dots)\footnote{The value of this variable is used in the file name + of the TEX template file; consequently, this value should be kept short, yet meaningful.} + + \item \dtt{number}: The quiz or exam number. The value of + this variable is not required to be a number.\footnotemark[\thefootnote] + + \item \dtt{subject}: Field of study, such as Math, German, + History, and so on.\footnotemark[\thefootnote] + + \item \dtt{theme}: The topic of this exam: factoring, grammar, 20thcentury, etc.\footnotemark[\thefootnote] + + + \item \dtt{instrName}: Instructor's name. The name should be + a single word that identifies the instructor (Thor, + Newton, Banach, and so on).\footnotemark[\thefootnote] + + + \item \dtt{date}: The date of the exam. + + + \item \dtt{time}: The length of the exam; this is, the time + the students have to work on the exam. + + \item \dtt{classPath}: The full path to the folder that + contains the quizzes of the class. + +\end{enumerate} + +\begin{comment} +\goodbreak +\section{Execution modes: interactive and automatic} + +There are two execution modes: (1) interactive and (2) +automatic. + +\subparagraph*{(1) Interactive:} If you execute \thebatch\space on the + \uif{Command Prompt}, you are offered three options:\footnote{Instructions are in German or English}\par\medskip + \begin{minipage}{\linewidth-\parindent} + \begin{enumerate} + \item[(1)] interactive query of individual variables (class, + teacher abbreviation, \dots) + + Here, you are asked in enter the values for each of the + above listed eight variables. + \item[(2)] No query: test with default values + + Used for testing purposes; automatically sets the values + of the eight variables. + \item[(q)] Exit the script + \end{enumerate} + \end{minipage} +\subparagraph*{(2) Automatic:} For the automatic, the script gets + the values for the eight variables from a TXT file. It is + this option that is the main approach to building your file + structure, and is the topic of the rest of the discussion in + the documentation. +\end{comment} + +\subsection{On running \thescript}\label{Focus} + +Now that you have read a brief description of the eight variables, rename the +file \texttt{sample-vars.txt} in your working folder to something short yet +appropriate to your work (perhaps rename it to just \texttt{class.txt}). In +this document, we shall refer to the renamed TXT file as +\texttt{\ameta{varlist}.txt}. Open \texttt{\ameta{varlist}.txt} in a text +editor and modify the left column to values appropriate to your class. The +contents of \ameta{varlist}\texttt{.txt} has the following form (shown with +default values which need to be changed): +\begin{Verbatim}[xleftmargin=\parindent] +alg1 # class +1 # number +maths # subject +factoring # theme or topic +THOR # instrName +01.01.2019 # date +60 Min. # time +C:/temp # classPath +\end{Verbatim} +Now execute \thebatch\space with arguments \texttt{thmclass} and +\texttt{\ameta{varlist}.txt} from the \uif{Command Prompt}:\footnote{The \uif{Command Prompt} needs +to be located in the folder that contains \thescript, \thebatch, and \texttt{sample-vars.txt}} +\begin{equation} + \fbox{\ttfamily runps1 thmclass \ameta{varlist}\texttt{.txt}}\label{dis:thmclass} +\end{equation} +\thescript\space reads the data contained in +\ameta{varlist}\texttt{.txt}. Using a batch file is the easiest way of executing the +\thescript\space with argument \texttt{\ameta{varlist}.txt}. + +\subsubsection{The results of running \tops{\thebatch}{runps1.bat}} + +Executing `\texttt{runps1 thmclass \ameta{varlist}.txt}', as +just described (see display~(\ref{dis:thmclass})), creates a +series of folders and files within the same folder in which +{\thebatch}, {\thescript}, and \texttt{\ameta{varlist}.txt} +reside.\medskip + +Suppose \texttt{\ameta{varlist}.txt} has the following symbolic +values: +\begin{quote}\ttfamily\obeyspaces\catcode`\#=12 +\ameta{class} # class\\ +\ameta{number} # number\\ +\ameta{subject} # subject\\ +\ameta{theme} # theme or topic\\ +\ameta{instrName} # instrName\\ +\ameta{date} # date\\ +\ameta{time} # time\\ +\ameta{classPath} # classPath +\end{quote} + + +\subsubsection{Structure displayed} Figure~\ref{fig:struct} represents the structure created by \thescript. + +\begin{figure}[htb] +\bgroup +\hfuzz120pt +%\makeatletter +%\hspace*{1.4in} +\fboxsep0pt\let\BOX\relax +\begin{center}\BOX{\begin{minipage}{3.5in} +\dirtree{% +.1 \ameta{working folder}. +.2 {runps1.bat}. +.2 {sample-vars.txt}\DTcomment{rename and edit\footnote{Generically referred to as \texttt{\ameta{varlist}.txt}}}. +.2 {thmclass.ps1}. +.2 \ameta{class}. +.3 \ameta{instrName}. +.4 backup. +.4 anSUS (toStudents). +.4 vonSUS (fromStudents). +.4 {runps1.bat}. +%.4 {classFolders.bat}. +.4 {csvTOcfg.ps1}. +.4 {classFolders.ps1}. +%.4 {csvTOcfg.bat}. +.4 {copyka.ps1}. +.4 {delka.ps1}. +.4 {moveka.ps1}. +.4 {sample-list.csv}\DTcomment{rename and edit\footnote{Generically referred to as \texttt{\ameta{list}.csv}}}. +.4 {container.pdf}. +.4 {terminate-batch.pdf}. +.3 {00-\ameta{class}.cfg}. +.3 {genquiz.ps1}. +.3 {runps1.bat}. +.3 {tex-template.tex}. +.3 {web.cfg}. +} +\end{minipage}}\hfill +\end{center} +\egroup +\caption{Structure created by \thescript}\label{fig:struct} +\end{figure} + +\subsubsection{Structure explained} + +We now attempt the Herculean task of explaining each of these. +\begin{description} + \item[\normalfont\ameta{class}] (folder) The folder created by the \ameta{class} variable. This folder + contains all the working files and folders of the class you are teaching. + \item[\normalfont\ameta{instrName}] (folder) This is a short name for the instructor. This folder contains + a number of other folders and files. + \begin{description} + \item[\normalfont\texttt{backup}] A folder that will contain the + instructor's copies of the quizzes generated. When + you open the file \texttt{00-\ameta{class}.cfg}, you + will find: + \verb|\instrPath*{|\ameta{instrName}\texttt{/backup}\verb|}|. + \item[\normalfont\texttt{anSUS} (\texttt{toStudents})] A folder to + drop the graded quizzes into. This folder name is + \texttt{anSUS} when the local language is German and + \texttt{toStudents} otherwise. + \item[\normalfont\texttt{vonSUS} (\texttt{fromStudents})] The + target destination of the script file + \texttt{copyka.ps1}. This folder name is + \texttt{vonSUS} when the local language is German + and \texttt{fromStudents} otherwise. + +% \item[\texttt{classFolders.bat}] This batch file that +% takes the contents of its argument and creates the +% class folder structure within the \ameta{classPath} +% folder. See the section on \texttt{classFolders} +% below for more details. + \item[\normalfont\texttt{csvTocfg.ps1}] A \app{Powershell} script + that reads the contents of the configuration file \texttt{\ameta{list}.csv} and modifies + \texttt{00-\ameta{class}.cfg} by appending appropriate \cs{classMember} + statements. + \item[\normalfont\texttt{classFolders.ps1}] A \app{Powershell} + script file that creates class folders based on the + contents of the \texttt{00-\ameta{class}.cfg} + file.\footnote{The sysadmin may now allow creation + of folders on the system drive; this script may be + used for testing on the instructor's own drive.} + \item[\normalfont\texttt{copyka.ps1}] A \app{Powershell} script that + copies the completed student quizzes from their + student folders to the folder \texttt{vonSUS} + (\texttt{fromStudents}) where the instructor can + operate on them. +% \item [\texttt{csvTocfg.bat}] A batch file that takes +% the contents of its argument and modifies +% \texttt{00-\ameta{class}.cfg}, one level up. It +% appends the \cs{classMember} data lines. +% See the section on \texttt{classFolders} below for more +% details. + \item[\normalfont\texttt{delka.ps1}] A \app{Powershell} script + that deletes the student quizzes from their personal + student folders. (This is done after they are copied + using \texttt{copyka.ps1}.) + \item[\normalfont\texttt{moveka.ps1}] The \app{Powershell} script + that copies and deletes the student quizzes from + their personal student folders. \textbf{Not + recommended!} I prefer to copy them and verify that + they are all successfully copied before deleted them + from the personal student folders. + \item[\normalfont\texttt{sample-list.csv}] A comma (or semi-colon) delimited file. Each line + of the file consists of three entries and has two formulations: + \begin{quote}\ttfamily + \ameta{first},\ameta{last},\ameta{rel-path}\\[3pt] + \ameta{first},\ameta{last},*\ameta{full-path} + \end{quote} + In the first case, \ameta{rel-path} is the path, relative to the argument of the \cs{classPath}, + to the student folder; in the second case, \ameta{full-path} is the full path to the student + folder. + + You should rename this file and modify its contents to + reflect the class names and folder names of your class. + + \item[\normalfont\texttt{container.pdf}] A PDF file used by + \textsf{Thor's way} action script. See the manual + for the \pkg{thorshammer} package for details. + \item[\normalfont\texttt{terminate-batch.pdf}] A PDF file used by + \textsf{Thor's way} action script. See the manual + for the \pkg{thorshammer} package for details. + \end{description} +\end{description} +At the top most level of this folder structure are four files. +\begin{description} + \item[\normalfont\texttt{genquiz.ps1}]\label{item:genquiz} A \app{Powershell} script + that works in concert with \texttt{tex-template.tex}. When executed, + it reads the \ameta{varlist}\texttt{.txt} file (one level up), the + variable list file used to create the folders and files, it then + creates a TEX file named + \texttt{\ameta{number}-\ameta{class}-\ameta{subject}.tex}, which is a + copy of \texttt{tex-template.tex}, with certain tagged variables in + \texttt{tex-template.tex} replaced with their values based on + \ameta{varlist}\texttt{.txt}; for example, the tagged variable + \texttt{\#class} in \texttt{tex-template.tex} is replaced by the + value of the class variable declared in \ameta{varlist}\texttt{.txt} + (perhaps it is replaced by ``alg1''). + + \textbf{Steps to change the default name.} You can + change the default name of the generated TEX file by + following these steps: (1) open \texttt{genquiz.ps1} in + your favorite text editor; (2) find the line, +\begin{quote}\ttfamily\catcode`\$=12 + $templateName="$number-$class-$subject.tex" +\end{quote} +and, finally, (3) change the assignment, perhaps to a function +of one or more of the above above variables. + + \item[\normalfont\texttt{tex-template.tex}] There are two renditions (or versions) for the TEX + template: (1) a German language version, and (2) an English language + version. The \app{Powershell} script \texttt{thmclass.ps1} detects + the language as set by your operating system and writes the proper + TEX template. The TEX template, which is \texttt{tex-template.tex} + by name, contains tagged variables {\def\AND{{\normalfont and + }}\catcode`\,=\active\def,{{\normalfont\string, + }\ignorespaces}\ttfamily\catcode`\#=12\relax #class, + #number,#subject,#theme,#instrName,#date, \AND #time}, which are + replaced by their counterparts {\def\AND{{\normalfont and + }}\catcode`\,=\active\def,{{\normalfont\string, + }\ignorespaces}\ttfamily\catcode`\$=12\relax $class, + $number,$subject,$theme,$instrName,$date, \AND $time}, as declared in + \ameta{varlist}\texttt{.txt}. + + \textbf{German.} This \texttt{tex-template.tex} file is + Thor's visualization of what his quizzes should look + like. When \texttt{genquiz.ps1} is executed, it reads + this file and saves it again under a different name, as + discussed above. + + \textbf{English.} This form of the TEX template is more + basic, without Thor's specialized features. + + The contents of \texttt{tex-template.tex} can be + modified to suite your own understanding of what your + quiz should look like. Use the tagged variables as you + wish in your personal template file. + + \item[\normalfont\texttt{00-\ameta{class}.cfg}] The configuration file + for building a quiz for the class. Initially, it has the + following form: +\begin{Verbatim}[fontsize=\small,commandchars={^~@}] +% Reset the paths for \instrPath and \classPath for your system +% Use relative paths here for instructor according to dir, where tex file is located +\classPath{^ameta~classPath@} +\instrPath*{^ameta~instrName@/backup} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Syntax: +% \classMember{firstname}{lastname}{rel-path} +% \classMember{firstname}{lastname}*{full-path} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{Verbatim} +Running \texttt{csvTocfg.ps1} appends \cs{classMember} to the file. On running, it might now read, +\begin{Verbatim}[fontsize=\small,commandchars={^~@}] +% Reset the paths for \instrPath and \classPath for your system +% Use relative paths here for instructor according to dir, where tex file is located +\classPath{^ameta~classPath@} +\instrPath*{^ameta~instrName@/backup} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Syntax: +% \classMember{firstname}{lastname}{rel-path} +% \classMember{firstname}{lastname}*{full-path} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\classMember{Muehle}{Waeter}{MW634B/^ameta~instrName@} +\classMember{Anton}{Mueller}{AM256M/^ameta~instrName@} +\classMember{Laura}{Voegt}{LM356B/^ameta~instrName}@ +\end{Verbatim} + + +% \item[\ameta{number}-\ameta{class}-\ameta{subject}-\ameta{theme}\texttt{.tex}] +% This is the TEX template file. This awkward, extremely +% long and painful file name is a result of German +% education. The file itself is a quiz template that uses +% the \pkg{web}, \pkg{exerquiz} packages, in addition to +% the \pkg{thorshammer} package. Bring this file into your +% favorite {\LaTeX} editor and modify as desired, or write +% your own from scratch. Of course, a change of name might +% be in order as well. + +\item[\normalfont\texttt{web.cfg}] The TEX template file uses the + \pkg{web} package, and as such, uses many + \pkg{web}-defined commands. These commands can be + redefined through the \texttt{web.cfg}. The file + \thescript{} creates its own \texttt{web.cfg}, for local + use. If you open this created file, its contents are, +\begin{Verbatim} +% +% AeB Web Configuration file +% +\ExecuteOptions{dvips} +\bWebCustomize +% Insert redefinitions between these two marks +\eWebCustomize +\end{Verbatim} +To illustrate the use of the \texttt{web.cfg}, modify the file to now read, +\begin{Verbatim} +% +% AeB Web Configuration file +% +\ExecuteOptions{dvips} +\bWebCustomize +\author{Herr Dr. Thor} +\university{AcroTeX.edu} +\eWebCustomize +\end{Verbatim} +Above, we have declared \verb|\author{Herr Dr. Thor}| and +\verb|\university{AcroTeX.edu}|. (The \cs{author} and \cs{university} +commands are defined in the \pkg{web} package.) There are no restrictions, other +redefinitions of commands defined by other packages are permitted. Freely +use the special character `\texttt{@}' without having to type +\cs{makeatletter}/\allowbreak\cs{makeatother} combination. + + The \pkg{thorshammer} package defines a new command, + that will be picked by \pkg{web} itself; the command is + \cs{inputWebCfg}. This command has been embedded in the + preamble of the TEX template. +\end{description} + +\paragraph*{Additional comments on the eight variables.} We +document how the eight variables are used throughout the files generated by +\thescript. +\begin{description} + \item[\normalfont\ameta{class}] is used to construct a top-level folder + containing all the files generated by \thescript. This + variable is the base name of the CFG file + (\texttt{00-\ameta{class}.cfg}). + \texttt{00-\ameta{class}.cfg} is input by the template + file using the \cs{InputClassData} macro. It also + appears as the argument of the \cs{thQzHeaderL} and + \cs{title} commands in the template file. + + \item[\normalfont\ameta{number}] This variable appears in the TEX template file as + the argument of the \cs{DeclareQuiz} and of the \cs{version} commands. + + \item[\normalfont\ameta{subject}] This variable appears as an argument + of \cs{thQzHeaderCQ} and \cs{subject} in the TEX + template file. + + \item[\normalfont\ameta{theme}] This variable appears as the argument of \cs{thQzName}. + + \item[\normalfont\ameta{instrName}] This variable appears in several + \uif{Powershell} script files: \app{copyka.ps1}, \app{moveka.ps1}, + \app{delka.ps1}, \app{csvTOcfg.ps1}, and \app{classFolders.ps1}. In + the TEX template file, it appears as the argument of \cs{author}. + Within \texttt{00-\ameta{class}.cfg}, \ameta{instrName} appears as an + argument of \cs{instrPath}. + + \item[\normalfont\ameta{date}] This variable is an argument of + \cs{copyrightyears} in the TEX template file. + + \item[\normalfont\ameta{time}] This variable appears in the argument of \cs{keywords} + + \item[\normalfont\ameta{classPath}] This variable is used in various + places: \app{copyka.ps1}, \app{moveka.ps1}, + \app{delka.ps1}, and \app{classFolders.ps1}. It also + appears as the argument of \cs{classPath} within + \texttt{00-\ameta{class}.cfg}. + +\end{description} + +\section{Procedures after running \texttt{thmclass.ps1}} + +After the folders and files of +\hyperref[fig:struct]{Figure~\ref*{fig:struct}} are created, go +into the \ameta{class} folder, you will see \ameta{instrName} (a +folder) and the two files \texttt{00-\ameta{class}.cfg} and +\texttt{tex-template.tex}. Now, change directories by moving +into the \ameta{instrName} folder. Now perform the following +tasks. +\begin{enumerate} + \item \textbf{Edit \texttt{sample-list.csv}.}\label{item:Editlist} Change the + name, if desired, of the file \texttt{sample-list.csv} + and open the renamed file in your text editor. For the + purpose of this documentation, we shall refer to the + renamed file \texttt{sample-list.csv} as + \texttt{\ameta{list}.csv}. The format of each line is + exemplified by the three sample lines provided. More + symbolically, each line consists of a comma (or + semi-colon) delimited list: +\begin{quote} + \ameta{first},\ameta{last},\ameta{rel-path} or\\ + \ameta{first};\ameta{last};\ameta{rel-path} +\end{quote} +One or more lines in this file may have an alternate syntax: +\begin{quote} + \ameta{first},\ameta{last},*\ameta{full-path} +\end{quote} +where the first character of the third entry is an \texttt*, +the rest of the entry is a full-path to the student's +folder.\footnote{This is done when the student's does not lie +in the path pointed to by the argument of \cs{classPath}.} + +To continue, enter the first and last names of each student in +the class, followed by the relative path (relative to \cs{classPath}) +to that student's folder. The sample file reads, +\begin{equation} +\begin{minipage}{.5\linewidth} +\begin{Verbatim}[commandchars=!()] +M!"(u)hle;W!"(a)ter;MW634B +Anton,M!"(u)ller,AM256M +Laura,V!"(o)gt,LM356B +\end{Verbatim} +\end{minipage}\label{disp:list} +\end{equation} +These sample entries are to be deleted and replaced by the +names and folders of the class members. If there are any +student exception---one whose student folder is outside +\cs{classPath}---, then a typical entry is has the following +form, +\begin{equation*} +\begin{minipage}{.5\linewidth} +\begin{Verbatim}[commandchars=!()] +Laura,V!"(o)gt,*C:/Users/dpstory/Desktop/TestFolder/myOtherClass/LM356B +\end{Verbatim} +\end{minipage} +\end{equation*} +For the last entry, the third element begins with an \texttt*, which signals that +what follows is full path to this student's folder. + + \item \textbf{Run \texttt{csvTOcfg.ps1}:} Now, execute + \texttt{csvTocfg.ps1} using the general purpose batch + file \texttt{run1.bat} with a command line arguments of + \texttt{csvTocfg} and \ameta{list} (a CSV file); for example, + on the \app{Command Prompt}, type, +\begin{equation} + \fbox{\ttfamily runps1 csvTocfg \ameta{list}}\label{dis:csvTocfg} +\end{equation} + +% \item \textbf{Run \texttt{csvTOcfg}.} Now, run the batch +% file \texttt{csvTOcfg.bat} with a command line argument +% of the CVS file; for example, on the \app{Command +% Prompt}, type. +%\begin{quote}\ttfamily +% csvTocfg sample-list +%\end{quote} +and execute by pressing the \uif{Enter} key. \emph{Do not +include the extension in the command line argument}. This will +append the student information to the end of the +\texttt{00-\ameta{class}.cfg} one level up. Each student has +an entry in \texttt{00-\ameta{class}.cfg} of +\cs{classMember\darg{\ameta{first}}\relax +\darg{\ameta{last}}\darg{\ameta{folder-name}}}. +\texttt{csvTocfg} also replaces all German umlauts with +non-problematic characters like so: \"{u} \texttt{->} ue, +\"{o} \texttt{->} oe, etc. + + \item \textbf{Run \texttt{classFolders.ps1}:} The next step, + if needed, creates the personal student + folders.\footnote{The sysadmin may not allow creation of + folders on the system system drive; this script may be + used for testing on the instructor's own drive.} This + step may not be needed if the folders already exist. Run + the \texttt{runps1.bat} with a command line arguments of + \texttt{classFolders} and the CVS file; for example, on + the \app{Command Prompt}, type, +\begin{equation} + \fbox{\ttfamily runps1 classFolders \ameta{list}}\label{dis:classFolders} +\end{equation} +and execute by pressing the \uif{Enter} key. \emph{Do not +include the extension in the command line argument}. If the +folders already exist, the script does not destroy them and +create them again. No harm done, I hope. +\item \textbf{Run \texttt{genquiz.ps1}:} (Optional) If you + want to use the \texttt{tex-template.tex} file to create a + TEX file for your quiz, run \texttt{genquiz.ps1} with + the following \uif{Command prompt}: +\begin{equation} + \fbox{\ttfamily runps1 genquiz}\label{dis:genquiz} +\end{equation} +Executing this line produces a TEX template file named +`\texttt{\ameta{number}-\ameta{class}-\ameta{subject}.tex}'. The file +\texttt{genquiz.ps1}, when executed, reads the +\texttt{\ameta{varlist}.txt}, located one directory up, to get the current +values of \ameta{number}, \ameta{class}, and \ameta{subject}. + +\end{enumerate} + +\paragraph*{Preliminaries are done! Have fun!} You are ready to +compose your quiz/exam! Open the TEX template file and modify +its contents to suite your needs, removing easy questions and +adding difficult ones, or copy one of the demo files from the +\texttt{examples} folder and modify it. For this part of the +process you must be knowledgable of \pkg{exerquiz} and the +documentation of the \pkg{thorshammer} package. The sample files +of \pkg{thorshammer} will help to compose the quiz using the +approach you want. + + +\paragraph*{Repeat.} There is no need to run `\texttt{runps1 thmclass \ameta{varlist}.txt}' +more than once a semester. As you work through the semester, you can copy an +old quiz with a new file with a new name and modify for the new material +studied or run \texttt{genquiz.ps1} to obtain a new clean template file: +\[ + \fbox{\ttfamily runps1 genquiz} +\] +The file \texttt{genquiz.ps1} reads the +\texttt{\ameta{varlist}.txt} one level up; you might want to +first edit this file and change the value of \ameta{number}. + +The contents of \texttt{00-\ameta{class}.cfg} remains unchanged; if students +drop out of the course simply delete that student's line from +\texttt{00-\ameta{class}.cfg} or if students add the course simply append a +line to \texttt{00-\ameta{class}.cfg} using the template +\cs{classMember\darg{\ameta{first}}\relax +\darg{\ameta{last}}\darg{\ameta{folder-name}}}. Read the discussion on how to +handle \nameref{para:exceptions} to these general rules. + +\section{Deploying the quizzes} + +The quizzes may be deployed to the student folders in two ways: +\begin{enumerate} + \item When a quiz is compiled with the \opt{usebatch} option, the + \cs{sadQuizzes} command executes JavaScript lines when first opened + in \app{Acrobat}, which builds and distributes the quizzes to the + designated instructor folder and deploys individualized quizzes to + the correct student folder. + \item When the \opt{batchdistr} option is specified, + \cs{sadQuizzes} does its thing, but does not send the + quizzes to the individualized student folders. To + deploy them, either use the action sequence + \textsf{Thor protects and distributes} or just + \textsf{Thor distributes}. The end result of these two + is to deploy the quizzes to their designated student + folders. +\end{enumerate} + +\section{Retrieving the quizzes} + +After the exam period is over the quizzes need to be retrieved +from the student folders and placed in a folder where the +instructor can grade them. The mechanics of doing this are +explained next: +\begin{itemize} + \item \texttt{copyka.ps1} copies the quizzes from their respective student folders + in the class folder declared by the \cs{classPath} command to the folder designated + by the \cs{instrPath}. These two declarations can be found in \texttt{00-\ameta{class}.cfg}. + \item \texttt{delka.ps1} delete the quizzes from their + respective student folders in the class folder declared + by the \cs{classPath} command. + \textcolor{red}{\textbf{Important:}} Do not run this + script until you've first run \texttt{copyka.ps1} + \emph{and} you've \emph{verified} all files have indeed been + transferred. + \item \texttt{moveka.ps1} copies and then deletes the + quizzes. \textbf{Not recommended}, use a \texttt{copyka.ps1} $\rightarrow$ verify + $\rightarrow$ \texttt{delka.ps1} workflow. +\end{itemize} +\paragraph*{\color{red}Danger Will Robinson!} These scripts dig +down deep into the folder structure (pointed to by \cs{classPath} +or any exception paths (refer to \nameref{para:exceptions}) looking for PDFs in the student's folder, in +the subfolder named \ameta{instr}. If there are more than one +PDF in this folder, the scripts will copy, delete, and move all +PDFs found in the \ameta{instr} subfolder. + +\paragraph*{Running these scripts:} In the \uif{Command Prompt} and with the cursor in the same folder +as the scripts you are to execute, type, +\begin{align*} + &\fbox{\ttfamily runps1 copyka}\\[1ex] + &\fbox{\ttfamily runps1 delka}\\[1ex] + &\fbox{\ttfamily runps1 moveka} +\end{align*} +\paragraph*{Exceptions:}\chnglabelname{Exceptions}\label{para:exceptions} In an ideal semester, each of the students +takes the class for the first time and no additional information +is needed by the above three scripts; however, for students who +are taking the class again, their class folder may not be +located on the \cs{classPath}. The three scripts make a +provision for this. The above PS1 files look for a file named +\texttt{altclasspaths.txt} in the current directory. The +contents of this file is a list of \emph{alternate class paths}. For example, suppose +we declare +\begin{quote} +\verb|\classPath{/C/Users/dpstory/Desktop/myClass}| +\end{quote} +but there are students whose class folder is located on the path +\begin{quote} +\verb|/C/Users/dpstory/Desktop/TestFolder/myOtherClass| +\end{quote} +To service these `exceptional' students, create a file named +\texttt{altclasspaths.txt} and add the following line to that TXT file +\begin{quote} +\verb|/C/Users/dpstory/Desktop/TestFolder/myOtherClass| +\end{quote} +BTW, on \app{Windows}, you can use standard \app{Windows} notation (with forward slashes) as well: +\begin{quote} +\verb|C:/Users/dpstory/Desktop/TestFolder/myOtherClass| +\end{quote} +When any of the above three scripts is run, it will first perform its task for the main +\cs{classPath}, then it will perform the same task for the paths listed in +\texttt{altclasspaths.txt}. + +\section{Redeploying the quizzes} + +After the quizzes are marked and saved in a folder of the instructor's +choice, you can (optionally) return the graded quizzes to the students. To do +this, use the \textsf{Thor distributes} action sequence. + +\section{How to execute a PS1 file without a BAT file} There are two methods. +\begin{description} + \item [\normalfont Using the \texttt{\app{Powershell} App}:] From + \uif{File Explorer}, open a window and navigate to the + folder containing the PS1 file. Now select \uif{File} + \texttt{>} \uif{Open Windows Powershell} (or perhaps + the administrator version). In the \app{Powershell} command prompt, type +\begin{quote}\ttfamily +Powershell -ExecutionPolicy Bypass -Command .\cs{\ameta{basename}.ps1} +\end{quote} +The \texttt{-ExecutionPolicy Bypass} allows the script to run +without security warnings. + +To run a PS1 file with argument, +\begin{quote}\ttfamily +Powershell -ExecutionPolicy Bypass -Command .\cs{thmclass.ps1} myVars.txt +\end{quote} + +\item [\normalfont Using the \texttt{\app{Powershell} ISE App}:] This + application has a built-in editor. Start \app{Powershell} + ISE. Here you can load in your PS1 file by simply dragging + and dropping it into the window. Be sure the command + prompt is showing the folder where the script file is + located. Change directories using the \uif{cd} command, as + needed. For a PS1 file that does not have an argument, + simple press on the \uif{Run Script} icon on the toolbar, + or choose the \uif{Run} menu item from the \uif{File} + menu. + + To run a PS1 file with argument, type, for example, +\begin{quote}\ttfamily +Powershell -ExecutionPolicy Bypass -Command .\cs{thmclass.ps1} myVars.txt +\end{quote} +into the command prompt window and press the \uif{Enter} key to execute that line. +\end{description} + +\part{Using a standalone system}\label{PartII} + +\noindent +Using the Thor system of class structure (see \hyperref[fig:struct]{Figure~\ref*{fig:struct}}) may not be for +everyone. For this reason, some standalone scripts are provided +in the \texttt{standalone} folder of the \texttt{system-scripts} +folder. + +\newtopic\noindent +\textbf{Important:} The contents of the \texttt{standalone} folder should be +copied to your working folder, the one that contains the source files for +your quizzes you are developing. + +\newtopic\noindent +Within the \texttt{system-scripts/standalone} folder, the following files are provided:\medskip +\begin{description} +\item[\normalfont\texttt{cpquizzes.ps1}] A renamed and modified version of \texttt{copyka.ps1}. To use this script, +first open it in your editor and modify the following lines: +\end{description} +\begin{quote}\ttfamily +\$baseName="\ameta{baseName}"\\ +\$classPath="\ameta{classPath}"\\ +\$destPath="\ameta{destPath}" +\end{quote} +\begin{itemize} +\item[] +The value of \texttt{\$baseName} is usually one word that +represents the instructor (eg, THOR), but it does not have to be +the instructor's name. \texttt{\$classPath} is the path to the +class folders. The script searches \texttt{\$classPath} and +copies all PDFs within \emph{any} subfolder with +\texttt{\$baseName} as its name. It copies the PDFs to +\texttt{\$destPath}. The quizzes all must be uniquely named +because they are all copied to the same destination folder +(\texttt{\$destPath}). Any older PDFs (perhaps from earlier +quizzes, or actually any latent PDFs) are also copied, so you +must set up your protocols appropriately. Execute this script +from the \uif{Command Prompt}: +\begin{flushleft} + \fbox{\ttfamily runps1 cpquizzes} +\end{flushleft} +\end{itemize} +\begin{description} +\item[\normalfont\texttt{rmquizzes.ps1}] After you've run \texttt{cpquizzes.ps1} and verified that all required +files have been copied, you can safely delete (or remove) the quizzes from the student quiz folders. +Open \texttt{rmquizzes.ps1} in your editor, and modify the values of this variables: +\end{description} +\begin{quote}\ttfamily +\$baseName="\ameta{baseName}"\\ +\$classPath="\ameta{classPath}" +\end{quote} +\begin{itemize} +\item[] The meanings of the variables \texttt{\$baseName} and \texttt{\$classPath} are the same as above in the +description of \texttt{cpquizzes.ps1}. Run the script as follows: +\begin{flushleft} + \fbox{\ttfamily runps1 rmquizzes} +\end{flushleft} +\item[] These first two scripts are basic and the class can be conducted using only \texttt{cpquizzes.ps1} +and \texttt{rmquizzes.ps1}. The next two scripts can be considered optional. +\end{itemize} +\begin{description} +\item[\normalfont\texttt{mkcfg.ps1}] This is a modified and renamed + version of \texttt{csvTOcfg.ps1}, refer to the description of \texttt{csvTOcfg.ps1}. Prior to using this + script, delete the file \texttt{00-web.cfg} in the current + folder (this file is created by \texttt{mkcfg.ps1}). Open + your editor and modify the values of the following + variables: +\end{description} +\begin{quote}\ttfamily +\$classPath="\ameta{classPath}"\\ +\$instrPath="\ameta{instrPath}" +\end{quote} +\begin{itemize} +\item[] The values of these variables correspond to \cs{classPath} and +\cs{instrPath}, respectively. The script is executed from the +\uif{Command Prompt} as follows: +\begin{equation*} + \fbox{\ttfamily runps1 mkcfg \ameta{list}} +\end{equation*} +\item[] where the argument \ameta{list} is a list of class members and + folder locations data, as described in `Edit \texttt{sample-list.csv}' + on page~\pageref{item:Editlist}. + +The purpose of this script is to create the \texttt{00-web.cfg} +file. Once created, move this file to the same file as your +quizzes; input this file using \cs{InputClassData\darg{00-web}}. Examples of the use +of \cs{InputClassData} are found in the \texttt{examples/cfgs} folder. +As described earlier, the format of this file is, +\begin{Verbatim}[commandchars=!()] +\classPath{!ameta(classPath)} +\instrPath{!ameta(instrPath)} +\classMember{Muehle}{Waeter}{MW634B/_Thor} +\classMember{Anton}{Mueller}{AM256M/_Thor} +\classMember{Laura}{Voegt}{LM356B/_Thor} +\end{Verbatim} +\item[] Here, the sample class members of \texttt{sample-list.csv} are +shown. For the \cs{classPath} and \cs{instrPath}, \emph{use only full +paths}. Refer to `\textbf{Edit \texttt{sample-list.csv}}' on +page~\pageref{item:Editlist} for more information. +\end{itemize} +\begin{description} +\item[\normalfont\texttt{mkfolders.ps1}] This is a modified and renamed + version of \texttt{classFolders.ps1}. This script is used for testing + purposes; it can also be used to set up class folders provided you have + the necessary permissions. Run this script from the \uif{Command prompt}: +\end{description} +\begin{itemize} +\item[] Open the file and edit the variable +\begin{quote}\ttfamily +\$classPath="\ameta{classPath}" +\end{quote} +where \ameta{classPath} is the full path to the root of the class folders. Run this script +from the \uif{Command prompt}: +\begin{equation*} + \fbox{\ttfamily runps1 mkfolders \ameta{list}} +\end{equation*} +where the argument \ameta{list} is a list of class members and + folder locations data, as described in `Edit \texttt{sample-list.csv}' + on page~\pageref{item:Editlist}. +\end{itemize} +%\end{description} + +\part{My retirement} + +Now, I simply must get back to it. \dps + +\end{document} diff --git a/texmf-dist/doc/latex/thorshammer/thors-the-man.pdf b/texmf-dist/doc/latex/thorshammer/thors-the-man.pdf new file mode 100644 index 00000000..d67db59e Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/thors-the-man.pdf differ diff --git a/texmf-dist/doc/latex/thorshammer/thors-the-man.tex b/texmf-dist/doc/latex/thorshammer/thors-the-man.tex new file mode 100644 index 00000000..be267d67 --- /dev/null +++ b/texmf-dist/doc/latex/thorshammer/thors-the-man.tex @@ -0,0 +1,2178 @@ +\documentclass{article} +\usepackage{amstext} +\usepackage[ + web={centertitlepage,designv,forcolorpaper,tight*,latextoc,extended}, + eforms={usealtadobe,setcorder},aebxmp +]{aeb_pro} +%\usepackage[ImplMulti]{dljslib} +\usepackage{graphicx,array,fancyvrb} +\usepackage{aeb_mlink} +%\usepackage{myriadpro} +%\usepackage{calibri} +\usepackage[altbullet]{lucidbry} + +\usepackage{xbmks} +\DeclareInitView{layoutmag={navitab:UseOutlines}} +\xbmksetup{colors={int=red},styles={intbf}} + + +\makeatletter +\renewcommand*\l@section[2]{% + \ifnum \c@tocdepth >\z@ + \addpenalty\@secpenalty + \addvspace{.75em \@plus\p@}% make less space + \setlength\@tempdima{1.5em}% + \begingroup + \parindent \z@ \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + \leavevmode \bfseries + \advance\leftskip\@tempdima + \hskip -\leftskip + #1\nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss #2}\par + \endgroup + \fi} +\makeatother + +\let\tops\texorpdfstring + +\def\FmtMP#1{\marginpar{\small\itshape\raggedleft#1}} + +\hfuzz2pt +%\makePDasXOn + +%\previewOn\pmpvOn + +\def\hardspace{{\fontfamily{cmtt}\selectfont\symbol{32}}} +\let\uif\textsf + +\advance\marginparwidth12pt + +\usepackage{acroman} +\usepackage[active]{srcltx} + +\edef\amtIndent{\the\parindent} + +\addtolength{\marginparwidth}{2pt} + +\urlstyle{tt} + +\def\STRUT{\rule{0pt}{14pt}} + +\makeatletter +\newcount\hesheCnt \hesheCnt=-1 +\def\heshe{\@ifstar{\heshei}{\global\advance\hesheCnt1\relax\heshei}} +\def\heshei{\ifodd\hesheCnt she\else he\fi} +\def\HeShe{\@ifstar{\HeShei}{\global\advance\hesheCnt1\relax\HeShei}} +\def\HeShei{\ifodd\hesheCnt She\else He\fi} +\def\hisher{\@ifstar{\hisheri}{\global\advance\hesheCnt1\relax\hisheri}} +\def\hisheri{\ifodd\hesheCnt her\else his\fi} +\def\himher{\@ifstar{\himheri}{\global\advance\hesheCnt1\relax\himheri}} +\def\himheri{\ifodd\hesheCnt her\else him\fi} +\makeatother + +\DeclareDocInfo +{ + university={\AcroTeX.Net}, + title={The \textsf{thorshammer} Package}, + author={D. P. Story}, + email={dpstory@acrotex.net}, + subject=Documentation for the thorshammer package, + talksite={\url{www.acrotex.net}}, + version={1.5.7, 2020/01/13}, + Keywords={assessment workflow, LaTeX, AcroTeX}, + copyrightStatus=True, + copyrightNotice={Copyright (C) \the\year, D. P. Story}, + copyrightInfoURL={http://www.acrotex.net} +} + +\universityLayout{fontsize=Large} +\titleLayout{fontsize=LARGE} +\authorLayout{fontsize=Large} +\tocLayout{fontsize=Large,color=aeb} +\sectionLayout{indent=-62.5pt,fontsize=large,color=aeb} +\subsectionLayout{indent=-31.25pt,color=aeb} +\subsubsectionLayout{indent=0pt,color=aeb} +\subsubDefaultDing{\tops{$\bullet$}{\textrm\textbullet}} + + +\chngDocObjectTo{\newDO}{doc} +\begin{docassembly} +var titleOfManual="The thorshammer Package"; +var manualfilename="Manual_BG_Print_thorshammer.pdf"; +var manualtemplate="Manual_BG_Brown.pdf"; // Blue, Green, Brown +var _pathToBlank="C:/Users/Public/Documents/ManualBGs/"+manualtemplate; +var doc; +var buildIt=false; +if ( buildIt ) { + console.println("Creating new " + manualfilename + " file."); + doc = \appopenDoc({cPath: _pathToBlank, bHidden: true}); + var _path=this.path; + var pos=_path.lastIndexOf("/"); + _path=_path.substring(0,pos)+"/"+manualfilename; + \docSaveAs\newDO ({ cPath: _path }); + doc.closeDoc(); + doc = \appopenDoc({cPath: manualfilename, oDoc:this, bHidden: true}); + f=doc.getField("ManualTitle"); + f.value=titleOfManual; + doc.flattenPages(); + \docSaveAs\newDO({ cPath: manualfilename }); + doc.closeDoc(); +} else { + console.println("Using the current "+manualfilename+" file."); +} +var _path=this.path; +var pos=_path.lastIndexOf("/"); +_path=_path.substring(0,pos)+"/"+manualfilename; +\addWatermarkFromFile({ + bOnTop:false, + bOnPrint:false, + cDIPath:_path +}); +\executeSave(); +\end{docassembly} + +\begin{document} + +\maketitle + +\pdfbookmarkx[1]{Title Page}[action={\Named{FirstPage}}]{TitlePage} +\pdfbookmarkx[1]{Documentation of the system scripts}[action={\GoToR/F(thmclass.pdf)/D[0 /Fit]},color=blue,style={bf}]{sysscripts} +\pdfbookmarkx[1]{How to install Action sequences}[action={\GoToR/F(install-action-seq.pdf)/D[0 /Fit]},color=blue,style={bf}]{instAS} +\pdfbookmarkx[1]{Links to AcroTeX.Net}[action={/S/GoTo/D(undefined)},% + color=magenta,style={bf}]{acrotex} +\belowpdfbookmarkx{http://www.acrotex.net}[action={\URI{http://www.acrotex.net}},% + color=magenta,style={bf}]{home} +\belowpdfbookmarkx{http://blog.acrotex.net}[action={\URI{http://blog.acrotex.net}},% + color=magenta,style={bf}]{blog} + + +\selectColors{linkColor=black} +\tableofcontents +\selectColors{linkColor=webgreen} + +\section{Acknowledgements} + +The author would like to acknowledge Thorsten G. (a.k.a., Thor) who proposed +this workflow and who contributed many ideas, the proposed workflow I found +to be interesting and worth my time developing the idea; and to J\"{u}rgen G. +(a.k.a., Loki) who also contributed many good ideas, enthusiasm, questions, +bug detection, and motivation. High regards and respect to both. +\begin{flushright} +D. P. Story (a.k.a., Odon) +\end{flushright} + +\begin{center} + \fbox{% + \parbox{.75\linewidth}{\textbf{\textcolor{red}{Warning!}} The workflow of the \pkg{thorshammer} + package requires the instructor to use \textbf{\textsf{Adobe Acrobat + XI}}, or later. Any PDF creator may be used to build the quizzes, + however, but \app{Acrobat} is needed to execute one-time JavaScript + (\cs{sadQuizzes}) and to run the action sequences (formerly called batch + sequence by \app{Adobe}) such as \textsf{Thor's way}. Only \app{Adobe + Reader} is required for the students. Of course, this is the + full-featured \app{Adobe Reader} of a desktop or laptop, not the + \app{Adobe Reader} found on tablets, smartphones, and such. + }}% +\end{center} + +\section{Introduction}\label{intro} + +Thor has asked me to assist him in creating a quiz system, based on +Acro\negthinspace\TeX, to be delivered to his classes. His workflow for this +assessment system is as follows:\footnote{As my occasional friend J\"{u}rgen +says, this workflow is a real hammer, so I titled this package `Thors(ten) +hammer', or simply \pkg{thorshammer}.} +\begin{enumerate} + \item The \env{quiz} environment is used to pose the questions, which + consist of MC, numerical fill-in the blank, and \emph{extended response + questions}.\footnote{Extended response questions are the interesting + part.} Though the \env{quiz} environment is used, the score is not + reported to the student upon finishing the quiz. + \item The students takes the quiz in a computer lab, each student has + {\hisher} own personal student folder. The quizzes are dropped into the + personal folders. + \item When the student finishes the exam, taken in \app{AR},\footnote{\app{AR} + refers to \app{Adobe Reader DC}.} {\heshe} presses the \textsf{End + Quiz} control and saves the document. + \item At some point, the instructor's script moves the student quizzes + to the instructor's folder. + \item The instructor opens the PDF and finishes marking the extended + response questions and assigns a grade. + \item System scripts then returns the quizzes to the students. +\end{enumerate} +The original concept was expanded considerably as the package was developed: +extensive \hyperref[s:sysscrpts]{system scripts} were written to support the +system; and \hyperref[actSeq]{action sequences} were written, also to support +Thor's way. + + +\section{Preliminaries} + +Most important is the correct installation of \pkg{thorshammer} along with +its required packages and folder JavaScript files. + +\subsection{Package requirements} + +The most recent version of the packages \pkg{insdljs} (2019/10/23), +\pkg{exerquiz} (2019/10/13), \pkg{eq-save} (2019/08/07) are required. These three packages +were modified slightly to obtain features needed by \pkg{thorshammer}. + +The \pkg{thorshammer} package ships with two folder JavaScript files +\texttt{aeb\_pro.js}\FmtMP{\textsf{aeb\_pro.js}} (Version 1.7.2 or later, +required) and \texttt{aeb-reader.js}\FmtMP{\textsf{aeb-reader.js}} (Version +1.0 or later); these two are found in \texttt{folder-js} +folder\FmtMP{\texttt{folder-js} folder}. The latter is a new JavaScript file, +the former ships with the \pkg{aeb\_pro} package. These files give access to +security restricted JavaScript methods. If you already have \pkg{aeb\_pro} +installed, be sure you have Version 1.7.2 of \texttt{aeb\_pro.js}, if not, +install Version 1.7.2 provided by this distribution. + +The \texttt{aeb\_pro.js} is used on the instructor's system, along with +\app{Acrobat} (\app{AA}), to author quizzes. \app{Distiller} is not used unless the +author prefers a TEX $\rightarrow$ DVI $\rightarrow$ PS $\rightarrow$ PDF +workflow, using \app{Distiller} as the PDF creator. For this workflow, +\app{pdflatex}, \app{lualatex}, and \app{xelatex} will work as PDF creators; +however, \app{Acrobat} ia needed to execute the JavaScript code generated by +the command \cs{sadQuizzes} and to execute the action sequences provided by +this package. + +Once the quizzes are created, the author can take the quizzes in \app{Adobe +Reader} (\app{AR}) to get the same experience as his students. Additionally, +\texttt{aeb-reader.js} can be installed on the instructor's system and on the +student's work environment, if possible/permitted. \texttt{aeb-reader.js} +contains a subset of JavaScript methods taken from \texttt{aeb\_pro.js} that +\emph{will enhance student experience}. The author can install this file on +his system to take the quizzes in the same environment, again using +\app{Adobe Reader}. \textbf{Warning:}\FmtMP{\textbf{Warning}} Do not install +\texttt{aeb\_pro.js} in any folder where an \app{Adobe Reader} used by +students would read it. + +\paragraph*{Other enhancements to user experience.} \app{Adobe Reader} is by default in \uif{Protected Mode}. +Then \uif{Protected Mode} is enabled, one or more security dialog boxes popup +as the student saves his/her document. To eliminate this annoyance, clear the +\uif{Enable Protected Mode at startup} checkbox, as shown in the +\hyperref[fig:PM]{Figure~\ref*{fig:PM}}. On your personal system, open +\app{AR}, press \uif{Ctrl+K}\FmtMP{\uif{Ctrl+K}}, select \uif{Security +(Enhanced)} from the \uif{Categories} panel, finally, clear the checkbox, as +shown in \hyperref[fig:PM]{Figure~\ref*{fig:PM}}.\footnote{For \app{AA}, this +checkbox is cleared by default.} The installation of \texttt{aeb-reader.js} +and clearing the checkbox to disable \uif{Protected Mode} most likely require +the sysadmin\FmtMP{sysadmin permission} to make those changes. +\begin{figure}[htb]\centering +\includegraphics[width=\linewidth]{graphics/protected-mode} +\caption{Clear \textsf{Protected Mode} checkbox}\label{fig:PM} +\end{figure} + +%which gives access to security restricted JavaScript methods used by this +%package.\footnote{If you have the \pkg{aeb\_pro} package already installed, +%the you also have \texttt{aeb\_pro.js} (Version 1.7.2 or later, required); +%you can use \texttt{aeb\_pro.js} instead of \texttt{aeb-reader.js}.} +%Additionally, the file \texttt{aeb\_pro.js}\FmtMP{\textsf{aeb\_pro.js}} is +%required to be correctly installed on your computer. The file comes with the +%\pkg{aeb\_pro} package, though the package itself is not required. As a convenience, +%\texttt{aeb\_pro.js} is also include in the \texttt{folder-js} folder. + +\paragraph*{Installation of JS files for \app{Acrobat}.} The JavaScript file \texttt{aeb-reader.js} +is provided in the \texttt{folder-js} folder. Discussion of how and where to +install folder JavaScript files is found in the file +\texttt{docs/install\_jsfiles.pdf}. Read and follow the directions carefully. + +\paragraph*{Installation of JS files for \app{Adobe Reader}.} The folder JavaScript +file \texttt{aeb-reader.js} may be installed for use by \app{Adobe Reader} as +well. Installing \texttt{aeb-reader.js} enhances the experience of the +students as they save their quiz document after completing the quiz. +Normally, it is not possible to install such a JavaScript file for use by +students; however, if the students take the quiz in a Computer Lab, the +sysadmin can install \texttt{aeb-reader.js} on all the computers used in the +Computer Lab. Discussion of how and where to install folder JavaScript files +is found in the file \texttt{docs/install\_jsfiles.pdf}. Read and follow the +directions carefully. (\app{Reader} looks for its folder JavaScript files in +the same location where \app{Acrobat} would look for them.) + + +\subsection{Package options} + +There are seven options for this package. +\begin{description} + \item[\opt{nocfg}] There is a language localization file, discussed in + Section~\ref{s:lang}, that is loaded as a matter of course. When this + option is taken, the configuration file is not loaded. In this case, + the default English language definitions are used for all strings. + \item[\opt{testmode}] When this option is specified, the quizzes are + regular quizzes that can be tested in the usual \pkg{exerquiz}-way. A + \textsf{Correct} button is available to correct the quiz. + \item[\opt{!testmode}] A convenience option for putting the document into + the default mode: Quizzes are ready to be taken by the students, + pressing the \textsf{End Quiz} does not give any score for their + effort, but students are prompted to save the quiz. + \item[\opt{useclass}] Use this option to bring in additional code to + declare each member of the class, to automatically build a custom quiz + for each class member, to distribute these quizzes to a designated + folder of the instructor, and to distribute the quizzes the respective + class folder. Refer to Section~\ref{ss:uc} for details. + \item[\opt{usebatch}] This option executes the \opt{useclass} option; + however, there is a batch sequence, called \textsf{Thor's way}, that + the instructor uses to process all class quizzes after the class has + finished with them. Refer to Section~\ref{ss:ub} for details. + \item[\opt{batchdistr}] The option automatically passes the + \opt{usebatch} and the \opt{useclass} options. + Additionally, the document assembly script does not + distribute copies of the quizzes to the student folders, + rather, it is expected the author uses either + \textsf{Thor distributes} or \textsf{Thor protects and + distributes} action wizards to perform the distribution + task. The quizzes can later be distributed using an + operating system script. Refer to Section~\ref{ss:bd} + for details. + \item[\opt{ordinary}] When this option is passed, ordinary + quizzes are created, \emph{ones that do not follow Thor's + Hammer workflow}. The \opt{testmode} option is + automatically executed, as well as other changes. Refer + to section~\ref{ordinary} for more details and examples. +\end{description} + +\section{Necessary conditions that would make this system work} + +In recent years, browser technology has \emph{devolved} to the point that +\app{Adobe Reader} is no longer supported---with the exception of Microsoft's +\app{Internet Explorer~11}---within a browser window. For documents using +\pkg{exerquiz}, which relies heavily on \app{Acrobat} JavaScript API, +interactive quizzes can no longer be taken within a brower; hence, if an +instructor wants to use \pkg{exerquiz} to author quizzes to be taken by +{\hisher} students, the quizzes must be taken on a desktop or laptop from +within the \app{Adobe Reader} application.\footnote{At this time, \app{Adobe +Reader} on mobile and tablets do not support form fields and JavaScript.} + +\subsection{The effectiveness of using PDF quizzes for assessment} + +The effectiveness of an in-class quiz is closely tied to quiz security. In a +normal classroom setting, students take the quiz/test---all at the same +time---under the glaring gaze of responsible adult. This is to ensure there +is no `cheating.' This is the method used for paper quizzes/tests that are a +major part of the students grade. However, security becomes more lax when +students work on assignments with lesser weight in the final grade. Homework +assignments are an example. + +For PDF quizzes, the philosophy is the same, for lesser credit, the students +can take the quizzes on their own. If the quizzes are for major credit in the +course, then one would expect stricter security. + +\paragraph*{The ideal condition.} The following list comprises the ideal conditions +for assessment using PDF quizzes. +\begin{itemize} + \item \textbf{An exam period.} There is a definite (time) period the + students are to take the quizzes. The quizzes are moved to the + private student folders at the beginning of the assessment period, + and removed again at the end of the assessment. + \item The ideal condition is for the students to take the quiz only in a + CBT lab (computer-based testing lab) under supervision. + + \item \textbf{CBT Lab.} The student must use \app{Adobe Reader}, must not + use email or a thumb-drive (to transmit the PDF quiz), and must not + print the quiz. For Thor's workflow, the student finds the quiz in + the his/her personal folder. + + \item \textbf{No access to private folder.} The students do not have access to the private folder outside of + the CBT lab. +\end{itemize} +The workflows devised in this package will work well for class quizzes taken under these ideal conditions. + +\subsection{Authoring a quiz} + +The \pkg{thorshammer} package uses post-pdf creation JavaScript methods. For +these methods to have any effect, the document author must use the \app{Adobe +Acrobat}\FmtMP{\app{Acrobat} required} application. The PDF creation can be +any of the usual {\LaTeX} workflows: \app{dvips/Adobe Distiller}, +\app{pdflatex}, \app{lualatex}, or \app{xelatex}. In all cases, after PDF +creation, the newly created file must be opened in \app{Acrobat} before any +auxiliary files are deleted. When opened in \app{Acrobat} the first time, +certain code lines of JavaScript execute to perform a number of tasks. + +There is another JS file that needs to be either located or created, the file +name is \texttt{config.js}\FmtMP{edit \textsf{config.js}}. It is a standard +\app{Acrobat} file and is located in the same folder in which +\texttt{aeb-reader.js} (or, perhaps, \texttt{aeb\_pro.js}) reside. The file +\texttt{install\_jsfiles.pdf}, found in the \texttt{docs} folder, discusses +where \app{Acrobat} expects to find folder JavaScript files. Find or create +\texttt{config.js} and insert the following line: +\begin{Verbatim}[xleftmargin=\amtIndent,commandchars=!~@] +var _thorshammer=true;!quad//!sffamily~ secret variable@ +\end{Verbatim} +This JavaScript variable plays an interesting role: Certain form elements in +the quiz only appear when this variable is present, in particular, the +\textsf{Mark it} control only appears when the document is opened in +\app{Acrobat} and the above script line appears in the \texttt{config.js} +file.\footnote{\textbf{Important!} Do not install \texttt{config.js} where +any \app{AR} used by a student; otherwise, the \textsf{Mark It} control will +be displayed to the student, which we don't want.} You'll have to see it to +believe it. + +\newtopic\noindent +Once the quiz has been built, the quizzes themselves require only \app{Adobe +Reader} to take. + +\newpage + +\section{Workflows for interactive assessment using PDF} + +The document author has several choices for student/instructor experience. We +discuss these in this section. + +\subsection{Basic methods}\label{ss:BMs} + +A \emph{basic method}\FmtMP{basic method} is one in which none of the ``class options'' are used; these +are \opt{useclass}, \opt{usebatch}, and \opt{batchdistr}. +This method is illustrated in sample file \texttt{thexb.tex}. Compiling this file +produces a single quiz, which is distributed to the class. + +\subsubsection{Preamble} + +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small,commandchars={!~@}] +\documentclass{article} +\usepackage{amstext} %!textsf~ (optional, used in a minor way below)@ +\usepackage{web} %!textsf~ (optional)@ +\usepackage[usealtadobe]{insdljs} +\usepackage[usesumrytbls]{exerquiz} +!textbf~\usepackage{thorshammer}@ %!textsf~ (basic methods imply no options taken)@ + +\setInitMag{fitwidth} %!textsf~ (optional, defined in this package)@ +\hypersetup{pdfpagelayout=OneColumn} %!textsf~ (optional, from hyperref )@ + +%!textsf~ Optional customizations@ +%\useNameToCustomize +%\enumQuizzes{3} +%\instrPath{/C/Users/!ameta~username@/Desktop/Test Folder/target/_Thor} +%\classPath{/C/Users/!ameta~username@/Desktop/Test Folder/target/myClass} +%\distrQuizzes{{A/_Thor}{B/_Thor}{C/_Thor}} + +\reversemarginpar +\showCreditMarkup %!textsf~ always include this command, it is required@ +%\previewOn\pmpvOn +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] +\PTsHook{($\eqPTs^{\text{pts}}$)} +\useMCCircles + +%!textsf~ Declare the quiz name@ +\DeclareQuiz{q1} +%!textsf~ Post document creation JavaScript@ +\begin{docassembly} +\sadQuizzes +\end{docassembly} +\begin{document} +... +\end{Verbatim} +There are two new commands and one new environment above to mention: +\bVerb\small\takeMeasure{\string\setInitMag\darg{fitpage|actualsize|fitwidth|fitheight|fitvisible|inheritzoom}}% +\begin{dCmd}[fontsize=\small]{\bxSize} +\setInitMag{fitpage|actualsize|fitwidth|fitheight|fitvisible|inheritzoom} +\end{dCmd} +\eVerb This command determines the initial magnification. There are a choice +of six values for the argument; the default is \texttt{fitpage}. + +\paragraph*{Optional customizations.}\label{para:OCs} There are a several commands to customize the creation of +the quizzes. +\bVerb\small\takeMeasure{\string\distrQuizzes\darg{\darg{*\ameta{path\SUB1}}\darg{*\ameta{path\SUB2}}...\darg{*\ameta{path\SUB{num}}}}}% +\begin{dCmd}[fontsize=\small,commandchars=!()]{\bxSize} +\useNameToCustomize +\enumQuizzes{!ameta(num)} +\instrPath{!ameta(path)} +\classPath{!ameta(path)} +\distrQuizzes{{*!ameta(path!SUB1)}{*!ameta(path!SUB2)}...{*!ameta(path!SUB(num))}} +\end{dCmd} +\eVerb When none of these commands appear in the preamble, compiling the quiz +document, produces a single quiz; e.g., compiling \texttt{thexb.tex} produces +\texttt{thexb.pdf}. Otherwise, compiling \texttt{thexb.tex} produces, for +example, enumerated copies of the quiz files: +\texttt{thexb-1.pdf}, \texttt{thexb-2.pdf}, \dots, +\texttt{thexb-\meta{num}.pdf}. +\begin{description} + \item[\cs{useNameToCustomize}] When the instructor makes the final + assessment, {\heshe} presses the \textsf{Mark It} button and a + \textsf{Save As} dialog box opens: by default, the name of the + current file is pre-filled into the \textsf{File name} input field; + if \cs{useNameToCustomize} is in force, however, when \textsf{Mark + It} is pressed, the suggested file name in the \textsf{Save As} + dialog box is pre-filled as + \texttt{\cs{jobname}-\ameta{first}\_\ameta{last}-g.pdf}, where + \cs{jobname} is the base name of the original {\LaTeX} source file. + The values of \ameta{first} and \ameta{last} are taken from the + name fields of the document, where the student is expected to enter + {\hisher} name. + \item[\cs{enumQuizzes\darg{\ameta{num}}}] When this command is present + in the preamble, the command \cs{sadQuizzes} (described below) + creates \ameta{num} copies of the quiz, and labels them + \cs{jobname-1.pdf}, \cs{jobname-2.pdf}, \dots, + \cs{jobname-\meta{num}.pdf}. + \item [\cs{instrPath\darg{\ameta{path}}}] (The instructor folder) The + \cs{instrPath} command is the path to the folder of the instructor. + A copy of all quizzes produced are placed at the end of this path. + \item [\cs{classPath\darg{\ameta{path}}}] (The class folder root) The + \cs{classPath} command is the path to the root of the class folders + of the students. + \item[\cs{distrQuizzes\darg{*\darg{\ameta{path\SUB1}}\darg{*\ameta{path\SUB2}}...\darg{*\ameta{path\SUB{num}}}}}] + The argument takes a series of paths: (1) if the star-option + (\texttt*) is \emph{not present}, then \ameta{path} is the relative + path to the student folder, relative to the class folder root; (2) + if the star-option (\texttt*) is present, the \ameta{path} is the + full path to the student folder. Each folder path is enclosed in + braces (\darg{}). +\begin{Verbatim}[fontsize=\small] +\classPath{/C/Users/dpstory/Desktop/Test Folder/target/myClass} +\newcommand{\altClassPath} + {/C/Users/dpstory/Desktop/Test Folder/target/myOtherClass} +\distrQuizzes{{A/_Thor}{*\altClassPath/B/_Thor}{C/_Thor}} +\end{Verbatim} +Quizzes are placed (by \cs{sadQuizzes}) in the student folders: +\begin{Verbatim}[fontsize=\small] +/C/Users/dpstory/Desktop/Test Folder/target/myClass/A/_Thor} +/C/Users/dpstory/Desktop/Test Folder/target/myOtherClass/B/_Thor} +/C/Users/dpstory/Desktop/Test Folder/target/myClass/C/_Thor} +\end{Verbatim} +When the \cs{classPath}/\cs{distrQuizzes} combination is used, the +\cs{enumQuizzes} command is ignored. The number of quizzes to be created is +determined by the number of folder paths listed in \cs{distrQuizzes}. +\end{description} + +\paragraph*{Declaring quiz name.} Also in preamble is the declaration of the quiz name. +\begin{Verbatim}[xleftmargin=\amtIndent,commandchars={!~@}] +\DeclareQuiz{!ameta~qz-name@}!quad%!textsf~ defined in exerquiz@ +\end{Verbatim} +The \ameta{qz-name} should consist of alpha-numeric characters only (eg, +\texttt{quiz1}), and no umlauts, Loki!\footnote{I am informed by the mighty +Thor himself that umlauts can simply rendered in German with `ue' instead of +\"{u}, `oe' instead of \"{o}, and so on; however, we don't want to encourage +Loki. I wish he would have told Loki years ago, it would have saved me a lot +of headaches.} The command saves the quiz name in several ways: +\begin{itemize} + \item As equivalent text macros, \cs{thisQuiz} and \cs{currQuiz}. Either of these + of these two must be used to reference the quiz name when you set up the \env{quiz} + environment; for example, +\begin{Verbatim}[fontsize=\small,commandchars={!~@}] +\DeclareQuiz{q1} +... +\begin{document} +... +\begin{quiz*}{\thisQuiz}!quad%!textsf~ or @\begin{quiz*}{\currQuiz} +... +\end{quiz} +\end{Verbatim} + \item As the text macro \cs{thQuizName}\FmtMP{\cs{thQuizName}}. This + command was created to solve a problem with the Thor's hammer. (Can + you believe it?) When a parent file has multiple renditions of the + quiz, Thor's hammer names them differently. For example, if we + declare \cs{DeclareQuiz\darg{q1}}, in the first rendition, the quiz + name is \texttt{q1a}, in the second rendition, the quiz name is + \texttt{q1b}, and so on. (There is a limitation of 26 renditions, + though the use of alphabetic letters can easily be changed to + numbers.) The command \cs{thQuizName} always expands the original + quiz name. +\end{itemize} +While on the topic of quiz names, Thor has forged with his mighty hammer, a +convenience command, +\bVerb\small\takeMeasure{\string\thQzName\darg{\ameta{text}}}% +\setlength{\eflength}{\widthof{\sffamily(\cs{thQuizName})}}% +\edef\x{\the\eflength}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\rlap{\hskip\x\relax\qquad\cs{def}\cs{thqzname\darg{\ameta{text}}}}\sffamily(\cs{theQuizName})}} +\begin{dCmd}[fontsize=\small,commandchars=!()]{\bxSize} +!1\thQzName{!ameta(text)} +\end{dCmd} +\eVerb The expression in the parentheses above is the default value; in the third column is the underlying +text macro definition. Declaring \cs{theQzName\darg{Quiz \#1}} defines the text macro \cs{thqzname} that +expands to `Quiz \#1'. + +\paragraph*{Post document creation JavaScript.} It is important to insert the \cs{sadQuizzes} +command just above \verb~\begin{document}~, within the \env{docassembly} +environment. +\bVerb\takeMeasure{\string\begin\darg{docassembly}}\par\vskip3pt %\vskip-\baselineskip +\begin{dCmd}[commandchars=!~@]{\bxSize} +\begin{docassembly} +!textbf~\sadQuizzes@ +\end{docassembly} +\end{dCmd} +\eVerb The \env{docassembly} environment (also available in the +\pkg{aeb\_pro} package) is a verbatim write environment; it writes its +contents verbatim to the file \texttt{docassembly.cut} then inputs it back in +immediately. In this application, place \cs{sadQuizzes} in the body of the +environment. + +\paragraph*{What does \cs{sadQuizzes} do?} The command expands to a series of +JavaScript lines. What is does depends on several factors. +\begin{itemize} + \item The script identifies the solution pages, extracts and saves them + to the current folder under the name + \cs{jobname-thsolns4-\ameta{qz-name}.pdf}; it then removes the + solution pages from the parent document. The solution pages are later + appended to the quiz after the students take the quiz by the instructor + when {\heshe} presses the \textsf{Freeze Quiz} button. + \item If \cs{enumQuizzes\darg{\ameta{num}}} is used, \cs{sadQuizzes} makes + \meta{num} copies of the quiz, labeling them \cs{jobname-1.pdf}, + \cs{jobname-2.pdf}, and so on. Files are saved to the folder of the + source file. + \item If the \cs{classPath}/\cs{distrQuizzes} combination is used, \cs{sadQuizzes} makes enumerated + copies of the quiz and places each in a separate folder designated by the argument + of \cs{distrQuizzes}. +\end{itemize} + +\subsubsection{The body of the document} + +%The first item in the body is the declaration of the quiz name. +%\begin{Verbatim}[xleftmargin=\amtIndent,commandchars={!~@}] +%\DeclareQuiz{!ameta~qz-name@}!quad%!textsf~ defined in exerquiz@ +%\end{Verbatim} +%The \ameta{qz-name} should consist of alpha-numeric characters only (eg, +%\texttt{quiz1}), and no umlauts, Loki!\footnote{I am informed by the mighty +%Thor himself that umlauts can simply rendered in German with `ue' instead of +%\"{u}, `oe' instead of \"{o}, and so on; however, we don't want to encourage +%Loki. I wish he would have told Loki years ago, it would have saved me a lot +%of headaches.} The command saves the quiz name in several ways: +%\begin{itemize} +% \item As equivalent text macros, \cs{thisQuiz} and \cs{currQuiz}. Either of these +% of these two must be used to reference the quiz name when you set up the \env{quiz} +% environment; for example, +%\begin{Verbatim}[fontsize=\small,commandchars={!~@}] +%\DeclareQuiz{q1} +%... +%\begin{document} +%... +%\begin{quiz*}{\thisQuiz}!quad%!textsf~ or @\begin{quiz*}{\currQuiz} +%... +%\end{quiz} +%\end{Verbatim} +% \item As the text macro \cs{thQuizName}\FmtMP{\cs{thQuizName}}. This +% command was created to solve a problem with the Thor's hammer. (Can +% you believe it?) When a parent file has multiple renditions of the +% quiz, Thor's hammer names them differently. For example, if we +% declare \cs{DeclareQuiz\darg{q1}}, in the first rendition, the quiz +% name is \texttt{q1a}, in the second rendition, the quiz name is +% \texttt{q1b}, and so on. (There is a limitation of 26 renditions, +% though the use of alphabetic letters can easily be changed to +% numbers.) The command \cs{thQuizName} always expands the original +% quiz name. +%\end{itemize} +%While on the topic of quiz names, Thor has forged with his mighty hammer, a +%convenience command, +%\bVerb\small\takeMeasure{\string\thQzName\darg{\ameta{text}}}% +%\setlength{\eflength}{\widthof{\sffamily(\cs{thQuizName})}}% +%\edef\x{\the\eflength}% +%\setlength{\eflength}{\bxSize}% +%\def\1{\rlap{\hskip\eflength\rlap{\hskip\x\relax\qquad\cs{def}\cs{thqzname\darg{\ameta{text}}}}\sffamily(\cs{theQuizName})}} +%\begin{dCmd}[fontsize=\small,commandchars=!()]{\bxSize} +%!1\thQzName{!ameta(text)} +%\end{dCmd} +%\eVerb The expression in the parentheses above is the default value; in the third column is the underlying +%text macro definition. Declaring \cs{theQzName\darg{Quiz \#1}} defines the text macro \cs{thqzname} that +%expands to `Quiz \#1'. + + +\newtopic\noindent +Thor \emph{requires}\FmtMP{required} a first and last name field. +\bVerb\takeMeasure{\string\FirstName[\ameta{opts}]\darg{\ameta{wd}}\darg{\ameta{ht}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\FirstName[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\LastName[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\end{dCmd} +\eVerb The \ameta{opts} argument is for changing the appearance of these text +fields. These fields are placed at the top of the quiz. +\bVerb\takeMeasure{\string\thfullnameFmt\darg{\ameta{how-to-format}}}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\textsf{(See \texttt{examples/misc/thexrt.tex})}}} +\def\2{\rlap{\hskip\eflength\textsf{(Default: \texttt{\string\thfullnameFmt\darg{\#1+" "+\#2}})}}} +\begin{dCmd}[commandchars=!()]{\bxSize} +!1\FullName[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +!2\thfullnameFmt{!ameta(how-to-format)} +\end{dCmd} +\eVerb The \cs{FirstName} and \cs{LastName} fields are required; however, the +\cs{FullName} command can explicitly appear as well, perhaps on the cover +page. This command gets its value from the values of the \cs{FirstName} and +\cs{LastName} fields; \ameta{how-to-format} is a JavaScript string that +displays how you want the full name to appear. Within the argument of +\cs{thfullnameFmt}, \texttt{\#1} is the first name and \texttt{\#2} is the +second name. Another example of this formatting is +\verb~\thfullnameFmt{#2+", "+#1}~, here, the full name is presented as last name first, followed by a +command, then the first name. These ideas are demonstrated in +\texttt{examples/misc/thexrt.tex}. + +\newtopic +The name fields\FmtMP{importance of the \emph{required} name fields} play a +critical role in Thor's way of doing things. In addition to providing text +fields for the student to identify \himher self, the \emph{required} name +fields are used to mark the beginning of a quiz page. \emph{The required name +fields must appear at the top of the page} and above the beginning of the +quiz. Some of the JavaScript of \pkg{thorshammer} interprets the page on +which the required name fields appear as the page that marks the beginning of +the quiz. + +\newtopic\noindent +The following fields are an integral part of Thor's way: +\bVerb\takeMeasure{\string\displaySumryTbl[\ameta{opts}]\darg{\string\currQuiz}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\markQz[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\freezeOrSave[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\studentReport[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\studentGrade[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\begin{sumryTblAux}{\currQuiz} +\displaySumryTbl[!ameta(opts)]{\currQuiz} +\end{sumryTblAux} +\end{dCmd} +\eVerb These commands and environments are aesthetically arranged at the top of the quiz file along with +the name fields, though the \cs{displaySumryTbl} can be placed anywhere (see the \pkg{exequiz} documentation +on this summary table structure). +\begin{description} +\item[\cs{markQz}] This button appears in \app{Acrobat} only when the + secret variable is detected. After the students have taken the quiz and + they are back in the possession of the instructor, the instructor opens + each completed quiz and presses this button, whose default caption is + \textsf{Mark It}. The underlying script marks up the quiz, showing + which problems were answered correctly, how many points received for + each response, etc. + + One of the features of Thor's way is to have extended response + questions. The student responses to this type of question must be read and + corresponding points must be assigned in the box provided. +\item[\cs{freezeOrSave}] This button appears only after the \textsf{Mark It} button has been pressed. + It has two different forms: + \begin{enumerate} + \item When the \opt{usebatch} option (or higher) is \emph{not in + effect}, this button appears with caption \textsf{Freeze Quiz}. + The action of this button is to attach any solution pages and + make all form fields \emph{in the entire document} readonly. It + also flattens all annotations in the document. \emph{Press this + button only} after all markups are finished and document is ready + to be moved into the student's folder. + + \item[] \textbf{Control of flattening.} There are options to have the + \textsf{Freeze Quiz} button to flatten or not. +\cs{thQuizHeader} and \cs{thQuizHeaderLayout}: +\bVerb\takeMeasure{\string\flattenOn\quad\string\flattenOff}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\flattenOn!quad\flattenOff +\end{dCmd} +\eVerb For basic methods, the default is \cs{flattenOff}, while for + \opt{useclass} it is \cs{flattenOn}. Normally, when you use the + \opt{useclass} option, all fields are flattened when the \textsf{Freeze + Quiz} button is pressed. This means you cannot run the quizzes through + \textsf{Thor's way} to extract the grades; recording of grades is done + in the tradional way, by hand. However, turning \cs{flattenOff} enables + you to use \texttt{Thor's way} even with the \opt{useclass} option. (Or, + simple change the option to \opt{usebatch}.) + + \item[] \textbf{Applies to basic methods.} The following command is + obeyed only when there is no ``class option'' option specified. +\bVerb\takeMeasure{\string\useNameToCustomize}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\sffamily{\enspace Obeyed for basic methods only}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +!1\useNameToCustomize +\end{dCmd} +\eVerb When the \cs{freezeorSave} button is pressed, the \textsf{Save As} + dialog is opened to save the file, the file name offered is + either \cs{jobname.pdf} (the default) or + \cs{jobname-\ameta{first}\_\ameta{last}-g.pdf} (provided + \cs{useNameToCustomize} has been expanded in the preamble. + \item When the \opt{usebatch} option (or higher) option \emph{is in + effect}, the caption is \textsf{Save \& Close}. As the caption + suggests, the action is to save the document the current folder + and close the document in \app{Acrobat}. With the \opt{usebatch} + option, the implication is that the instructor is to use one of + the action-wizards to continue processing the students' quizzes. + \end{enumerate} +\item[\cs{studentReport}] (text field) This readonly field shows the number + of points awarded and the total points (eg, 15 / 20). The field is initially hidden, + and becomes visible when \textsf{Mark It} is pressed. +\item[\cs{studentGrade}] (text field) A field for assigning some sort of + grade, which can be a letter or number. The field is initially hidden, + and becomes visible when \textsf{Mark It} is pressed. +\end{description} +Speaking of aesthetically pleasing arrangement, \pkg{thorshammer} defines, +\cs{thQuizHeader} and \cs{thQuizHeaderLayout}: +\bVerb\takeMeasure{\string\thQuizHeaderLayout}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\thQuizHeader* +\thQuizHeaderLayout +\end{dCmd} +\eVerb The \cs{thQuizHeader} command does nothing more than to test for the presence of +the \texttt{*} option; if \emph{not present}, a \cs{newpage} command is +issued, otherwise, no \cs{newpage} is forced. Throughout the sample files, +\cs{thQuizHeader} is used. The \cs{thQuizHeaderLayout} is the command that +actually contains the arrangement of the design elements. Do not redefine +\cs{thQuizHeader}; but you may define \cs{thQuizHeaderLayout}; look at +\pkg{thorshammer.dtx} for the definition \cs{thQuizHeaderLayout}, this will +give you insight for any redefinition. + +\paragraph*{Placement.} \cs{DeclareQuiz} is preferably placed in the preamble\FmtMP{preamble} and +\cs{thQuizHeader} is placed prior to the first quiz. +\begin{Verbatim}[xleftmargin=\amtIndent,commandchars=!()] +... +\DeclareQuiz{!ameta(qz-name)} +... +\begin{document} +... +\thQuizHeader +... +!sffamily!ameta(begin-quiz) +\end{Verbatim} +Following the above elements comes some instructions\FmtMP{instructions} for the students, then +an \pkg{exerquiz} quiz environment, +\begin{Verbatim}[xleftmargin=\amtIndent,commandchars=!()] +\begin{quiz*}{\currQuiz} +!textsf(Solve each of these problems, passing is 100\%.) +\begin{questions} +... +\end{questions} +\end{Verbatim} +The quiz itself is a standard \pkg{exerquiz} quiz, which, if you are using +this package, you should be familiar with. Thor's way, however, incorporates +extended response questions into it that must be personally evaluated by the +instructor. For extended response questions, \pkg{exerquiz} provides the +command \cs{RespBoxEssay}. This command has rarely been used. Below is the +syntax for this command as well as one support command (\cs{essayQ}), +contained in a rough quiz outline below. +\bVerb\takeMeasure{ \%\textsf{ allow space to respond to the question}}% +\setlength{\eflength}{\linewidth-(\bxSize)-\fboxsep}% +\edef\x{\the\eflength}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\smash{\parbox[t]{\x}{\sffamily +Use the \cs{essayQ} command prior to the use of \cs{RespBoxEssay}. The argument +of \cs{essayQ} is the number of points for the question. The number of points +is repeated again with the \cs{PTs} command. +}}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\begin{quiz}{\currQuiz} +... +\begin{questions} +\item !ameta(a question) +... +!1!textbf(\essayQ{!ameta(nPts)}) +\item\PTs{!ameta(nPts)} !ameta(pose-question)\par + %!textsf( allow space to respond to the question) + !textbf(\RespBoxEssay[!ameta(opts)]{!ameta(wd)}{!ameta(ht)}) + +!textbf(\essayitem{!ameta(nPts)}) !ameta(pose-question)\par + %!textsf( allow space to respond to the question) + !textbf(\RespBoxEssay[!ameta(opts)]{!ameta(wd)}{!ameta(ht)}) +... +\end{questions} +\end{quiz} ... +\end{dCmd} +\eVerb The \cs{essayQ} generates a text field in the margin. During the +instructor review phrase, the instructor can award points for the essay +problem by entering a numerical value into the text field. The value entered +will be figured into the totals displayed by the text field created by +\cs{LngPtsFld} (discussed below). The (default) width and height of the \cs{essayQ} +are \verb~\def\EsW{33bp}\def\EsH{14bp}~. The \cs{essayitem} is a convenience command, +it expands to \cs{essayQ\darg{\ameta{nPts}}}\allowbreak\cs{item}\cs{PTs\darg{\ameta{nPts}}}. + +%\essayQ +%\essayitem{!ameta(nPts)} +%\item[\cs{essayitem}] A convenience macro, expands to +%\cs{essayQ\darg{\ameta{nPts}}}\allowbreak\cs{item}\cs{PTs\darg{\ameta{nPts}}} + + +\newtopic\noindent +Following the quiz are several form fields. %{\PtFW}{\DefaultHeightOfWidget} +\bVerb\takeMeasure{\string\completeMsgFld[\ameta{opts}]\darg{\ameta{wd}}\darg{\ameta{ht}}}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\textsf{wd:\,}\cs{PTFW}\textsf{, ht:\,}\cs{DefaultHeightOfWidget}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\completeMsgFld[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +\stuSaveBtn[!ameta(opts)]{!ameta(wd)}{!ameta(ht)} +!1\ShrtPtsFld[!ameta(opts)]{\currQuiz} +!1\LngPtsFld[!ameta(opts)]{\currQuiz} +!1\TotalsFld[!ameta(opts)]{\currQuiz} +\end{dCmd} +\eVerb These form elements are arranged according your design preferences. +\begin{description} +\item[\cs{completeMsgFld}] Initially hidden, the text field becomes + visible when the student presses the \textsf{End Quiz} control. The + appearing text field reminds the student to save the quiz. + +\item[\cs{stuSaveBtn}] Initially hidden, the button becomes visible + when the student presses the \textsf{End Quiz} control. When the + student presses the button, the document is presented with a dialog to + save the document. After saving, the document is automatically closed. + +\item[\cs{ShrtPtsFld}] Initially hidden, the text field changes to visible + when the instructor presses the \textsf{Mark It} control. This field + is the \cs{PointsField} command of \pkg{exerquiz}, and contains the number + of points award for all non-extended response problems. + +\item[\cs{LngPtsFld}] Initially hidden, the text field becomes visible + when the instructor presses the \textsf{Mark It} control. It is a field + that will hold the total points awarded by the instructor for extended response + questions. + +\item[\cs{TotalsFld}] Initially hidden, the text field becomes visible + when the instructor presses the \textsf{Mark It} control. This field holds + the total of \cs{ShrtPtsFld} and \cs{LngPtsFld}. +\end{description} +The above elements may be used directly in the document, but it is easier to +use the command \cs{thQuizTrailer}: +\bVerb\takeMeasure{\string\end\darg{quiz*}\string\quad\string\thQuizTrailer}% +\edef\LW{\the\linewidth}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\enspace\sffamily\bfseries Skeleton outline of a quiz}}% +\def\2{\rlap{\hskip\eflength\enspace\smash{\parbox[t]{\LW-\eflength-1em}{\sffamily\raggedright% +The placement of the \cs{thQuizHeader} and \cs{thQuizTrailer} commands}}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +!1\DeclareQuiz{!ameta(qz-name)} +!2\begin{document} +!textbf(\thQuizHeader) +\begin{quiz*}{\currQuiz} +!ameta(!sffamily(Instructions)) +\begin{questions} +... +\end{questions} +\end{quiz*}\quad!textbf(\thQuizTrailer) +\end{dCmd} +\eVerb which incorporates the design elements described above. Throughout the +sample files, bothe \cs{thQuizHeader} and \cs{thQuizTrailer} are used. + + +\paragraph*{Student's experience.}\label{para:basic-SE} The student is presented with a quiz built +from \env{quiz} environment of the \pkg{exerquiz} package. To begin the quiz, +{\heshe*} presses the \textsf{Begin Quiz} control. If {\heshe*} has not +filled the name fields, an alert box appears to instruct {\himher*} fill in +the name fields. {\HeShe*} cannot begin the quiz until that occurs. Once the +name fields are filled, the student can once again press the \textsf{Begin +Quiz} and is allowed to respond to the questions. On finishing, the student +presses the \textsf{End Quiz} control. An alert box appears querying the +student whether {\heshe*} truly wants to end the quiz. (Ending the quiz means +the student cannot make any changes to {\hisher*} responses without having to +start over again.) After the student responds by pressing the \textsf{Yes} +control on the alert box, the \textsf{Save} control appears, and the student +can press it and open a \textsf{Save As PDF} dialog, which eventually ends +with saving the file (hopefully in the student's private folder). After a +successful save, the document is immediately closed. + +\paragraph*{Instructor's experience.}\label{para:basic-IE} When the +instructor opens a completed quiz, {\heshe} presses the \textsf{Mark It} +control. The \textsf{Freeze Quiz} control appears; the fields +\cs{completeMsgFld} and \cs{stuSaveBtn} are hidden; and the fields +\cs{ShrtPtsFld}, \cs{LngPtsFld}, and \cs{TotalsFld} become visible. +Additionally, the credit mark up fields appear in the margins indicating the +number of points the student received for each response. If there are any +extended response questions, the instructor enters an evaluation of the +student's responses in the \cs{essayQ} field. Changes in score are reflected +in the \cs{LngPtsFld}, \cs{TotalsFld}, and in the summary table. To complete +{\hisher*} evaluation of the quiz, {\heshe*} enters a value into the +\cs{studentGrade} (this is required, saving the file is not permitted, +otherwise) and then presses the \textsf{Freeze \& Save} control. The file is +saved under the name \cs{jobname-\ameta{first}\_\ameta{last}}, where +\ameta{first} and \ameta{last} are the values entered into the name fields by +the student. The instructor must manually record\FmtMP{manually record} the +student's score. + +\newtopic\noindent That is the simple case! Again, see the sample file \texttt{theb.tex}. + +\begin{figure}[p]\fboxsep0pt \centering +\parbox[b][215pt][t]{.45\linewidth}{\fbox{\includegraphics[width=\linewidth-2\fboxrule]{graphics/quiz-1}}\vfill +\centering (a) Student's view: quiz taken}\hfill +\parbox[b][215pt][t]{.45\linewidth}{\fbox{\includegraphics[width=\linewidth-2\fboxrule]{graphics/quiz-2}}\vfill +\centering (b) Instructor's view: Mark It pressed}\\[16pt] +\parbox[b][215pt][t]{.45\linewidth}{\fbox{\includegraphics[width=\linewidth-2\fboxrule]{graphics/quiz-3}}\vfill +\centering (c) Instructor's view: quiz is marked}\hfill +\parbox[b][215pt][t]{.45\linewidth}{\fbox{\includegraphics[width=\linewidth-2\fboxrule]{graphics/quiz-4}}\vfill +\centering (d) Student view: quiz returned frozen} +\caption{Student and Instructor experiences}\label{fig:qwf} +\end{figure} + +\newtopic\noindent +\hyperref[fig:qwf]{Figure~\ref*{fig:qwf}} on page~\pageref*{fig:qwf} shows +the workflow: (a) The student views and takes the quiz; the screenshot is +just before the \textsf{End} control is pressed; (b) shows the same quiz +after the instructor has pressed the \textsf{Mark It} control; (c) the +instructor has given some points in the extended response question (5 pts) +and set the grade as 4; (d) this screenshot shows the quiz after the +\textsf{Save \& Close} button is pressed. + +\subsection{Quizzes that specify the \tops{\protect\opt{useclass}}{useclass} option}\label{ss:uc} + +A \textit{class method}\FmtMP{class method} is one in which one of the ``class options'' are used; +these are \opt{useclass}, \opt{usebatch}, and \opt{batchdistr}. + +\newtopic\noindent +The sample file for this section is \texttt{thexuc.tex}. + +\newtopic\noindent +All the elements of the basic methods of Section~\ref{ss:BMs} are still +critical to the construction of the quiz, additionally, we use the +\opt{useclass} option. When this option is taken, it is expected that class +information is read into the document, see the discussion below. + +\subsubsection{Preamble} + +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small,commandchars={!~@}] +\documentclass{article} +\usepackage{amstext} %!textsf~ (optional, used in a minor way below)@ +\usepackage{web} %!textsf~ (optional)@ +\usepackage[usesumrytbls]{exerquiz} +!textbf~\usepackage[useclass]{thorshammer}@ %!textsf~ (because I am a classy guy)@ + +\setInitMag{fitwidth} %!textsf~ (optional, defined in this package)@ +\hypersetup{pdfpagelayout=OneColumn} %!textsf~ (optional, from hyperref )@ +\reversemarginpar +\showCreditMarkup +%\previewOn\pmpvOn +\useBeginQuizButton[\CA{Begin}] +\useEndQuizButton[\CA{End}] +\PTsHook{($\eqPTs^{\text{pts}}$)} +\useMCCircles + +!ameta~!sffamily~insertion of class info@@ + +%!textsf~ Perform certain tasks when opened in Acrobat the first time@ +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} +\begin{document} +... +\end{Verbatim} +Information on the \ameta{\sffamily{insertion of class info}}, on the +\env{makeClassFiles} environment, and on the \cs{sadQuizzes} command are +found in the next two sections. + +\subsubsection{The insertion of class information}\label{sss:CI} + +Thor's way states that quizzes are distributed to student private folders, and copies +are saved to the instructor folder. + +\newtopic\noindent\textbf{Required information:} +\begin{itemize} + \item The path to the instructor folder + \item The path to the class folder + \item For each student in the class, the first name, last name, and path to the student's folder, relative + to the class folder. +\end{itemize} +These three items are passed to \pkg{thorshammer} through the following commands. +\bVerb\takeMeasure{\string\classMember*\darg{\ameta{first}}\darg{\ameta{last}}*\darg{\ameta{full-path}}}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\textsf{wd:\,}\cs{PTFW}\textsf{, ht:\,}\cs{DefaultHeightOfWidget}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\instrPath*{!ameta(path)} +\classPath*{!ameta(path)} +\classMember*{!ameta(first)}{!ameta(last)}{!ameta(folder)} +\classMember*{!ameta(first)}{!ameta(last)}*{!ameta(full-path)} +\end{dCmd} +\eVerb Details of these commands are found next. +\begin{description} + \item[\cs{instrPath}] The path to the instructor's folder. Copies of all + files are dumped into this folder. The instructor uses this folder to + archive the quizzes. The \ameta{path} may be a full path, which is the + default, or a path relative to the folder the source file is being + compiled in. The \ameta{path} is interpreted as relative to the + current path when the \texttt*-option is taken; for example: +\setlength\eflength{\widthof{\ttfamily\small\string\instrPath*\darg{myclass}\quad}} +\def\1{\rlap{\hskip\eflength\%\sffamily\space assumes source is in the algebra folder}} +\begin{Verbatim}[fontsize=\small,commandchars=!()] +\instrPath{/c/users/thor/documents/myuni/spr19/algebra/myclass} +!1\instrPath*{myclass} +\end{Verbatim} + \item[\cs{classPath}] The path to the class folder. The \ameta{path} is an absolute + path by default, or a relative path, relative to the source folder. For example, + +\setlength\eflength{\widthof{\ttfamily\small\string\instrPath*\darg{myclass/staging}\quad}} +\begin{Verbatim}[fontsize=\small,commandchars=!()] +\classPath{/c/users/thor/documents/myuni/spr19/algebra/myclass/staging} +!1\classPath*{myclass/staging} +\end{Verbatim} + \item[\cs{classMember}] The arguments for this command provide the basic + information needed for Thor's way. When the \emph{first} \texttt*-option is taken, + the three arguments are filtered through \cs{pdfstringdef} + (\pkg{hyperref}). When the \emph{second} \texttt*-option is present, the last required + argument \ameta{full-path} must be full path to the student folder.\footnote{In a perfect world, + all student folders are at the end of the (current) class path; however, some students' class folder + may be elsewhere, this second \texttt*-option is designed for these ``exceptional'' students.} + + There needs to be one \cs{classMember} command for + each member of the class. + + \textbf{On the topic of accents.} The first and last name arguments + may contain accents from a local language. There are several ways of + handling them. + \begin{itemize} + \item (\texttt*-option) \verb~\classMember*{J\"{u}rgen}{Loki}{JL53456/thor}~ + \item (octal-method) \verb~\classMember{J\oct374rgen}{Loki}{JL53456/thor}~ + \item (unicode-method) \verb~\classMember{J\u00FCrgen}{Loki}{JL53456/thor}~ + \end{itemize} +\end{description} +There are three methods of introducing the required class information into the quiz document. + +\paragraph*{Direct placement in the source file.} +This is the method that messes up your preamble the most: +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small] +\instrPath{/c/users/thor/documents/myuni/spr19/algebra/myclass} +\classPath{/c/users/thor/documents/myuni/spr19/algebra/myclass/staging} +\classMember{Fred}{Flintstone}{FF34345/thor} +\classMember*{J\"{u}rgen}{Loki}{JL53456/thor} +... +\classMember{Peter}{Pan}{PP75464/thor} +\end{Verbatim} +If the third argument of the \cs{classMember} command is empty, the corresponding +quiz is placed in the folder determined by the path given in +\cs{classPath}. + +\newtopic\noindent +The next two methods use a (class) configuration file to load the info. + +\paragraph*{Use \cs{InputClassData} to input class info.} This is the simplest method. +It consists of the direct method cut and pasted into a CFG file. +\bVerb\small\takeMeasure{\string\InputClassData\darg{\ameta{base-name}}}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\%\textsf{ preamble only}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +!1\InputClassData{!ameta(base-name)} +\end{dCmd} +\eVerb This command inputs the configuration file +\texttt{\ameta{base-name}.cfg}. To repeat, the contents of +\texttt{\ameta{base-name}.cfg} is simply the lines as displayed in the direct +placement method above. + +\paragraph*{Use \cs{InputFormattedClass} to input class info.} This is a more flexible method +of inputting class info. The syntax for \cs{InputFormattedClass} is, +\bVerb\small\takeMeasure{\string\InputFormattedClass[\ameta{\cs{cmd}}]\darg{\ameta{base-name}}}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\%\textsf{ preamble only}}}% +\begin{dCmd}[commandchars=!()]{\bxSize} +!1\InputFormattedClass[!ameta(\cmd)]{!ameta(base-name)} +\end{dCmd} +\eVerb The optional \ameta{\cs{cmd}} is used to process each class member's info and ultimately +builds the \cs{classMember} command for that class member. The default for \ameta{\cs{cmd}} +is the command \cs{classMember}. The name of the configuration file is +\texttt{\ameta{base-name}.cfg}. The file format is as follow: +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small,commandchars=!()] +\instrPath{!ameta(path)} +\classPath{!ameta(path)} +\bClassData +!ameta(entry1) +!ameta(entry2) +... +\end{Verbatim} +Above the \cs{bClassData} marker, direct input is performed, so the \cs{instrPath} +and \cs{classPath} command are placed there. Below the \cs{bClassData} marker is the +class members individual data, represented here by \ameta{entry}. When +the configuration file is input, \ameta{\cs{cmd}} is prefixed to each entry: +\begin{flushleft}\ttfamily +\ameta{\cs{cmd}}\ameta{entry1}\\ +\ameta{\cs{cmd}}\ameta{entry2}\\ +... +\end{flushleft} +A straightforward example is, +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small] +\instrPath{/c/users/thor/documents/myuni/spr19/algebra/myclass} +\classPath{/c/users/thor/documents/myuni/spr19/algebra/myclass/staging} +\bClassData +{Fred}{Flintstone}{FF34345/thor} +*{J\"{u}rgen}{Loki}{JL53456/thor} +... +{Peter}{Pan}{PP75464/thor} +\end{Verbatim} +When we expand \cs{InputFormattedClass\darg{algclass}}, the lines below +\cs{bClassData} marker are read in as: +\begin{flushleft}\ttfamily +\cs{classMember}\darg{Fred}\darg{Flintstone}\darg{FF34345/thor}\\ +\cs{classMember}*\darg{J\string\"\darg{u}rgen}\darg{Loki}\darg{JL53456/thor}\\ +...\\ +\cs{classMember}\darg{Peter}\darg{Pan}\darg{PP75464/thor} +\end{flushleft} +To illustrate the greater flexibility, we offer up this example. +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small,commandchars=!()] +\instrPath{/c/users/thor/documents/myuni/spr19/algebra/myclass} +\classPath{/c/users/thor/documents/myuni/spr19/algebra/myclass/staging} +\bClassData +{Fred}{Flintstone}{!ameta(other-data)}{FF34345/thor} +*{J\"{u}rgen}{Loki}{!ameta(other-data)}{JL53456/thor} +... +{Peter}{Pan}{!ameta(other-data)}{PP75464/thor} +\end{Verbatim} +Notice the entry has an addition piece of information (perhaps a university ID number). Here, +each \ameta{entry} has more information than is required, so we need to extract what we need. +For this purpose, we define \cs{ParseClassMember} and input it as the optional argument +of \cs{InputFormattedClass}. +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small,commandchars=!()] +\newcommand\ParseClassMember[4]{\classMember{#1}{#2}{#4}} +\InputFormattedClass[\ParseClassMember]{myalgclass} +\end{Verbatim} +The first \ameta{entry} is processed as follows: +\begin{Verbatim}[xleftmargin=\amtIndent,fontsize=\small,commandchars=!()] +\ParseClassMember{Fred}{Flintstone}{!ameta(other-data)}{FF34345/thor} +\end{Verbatim} +which, in turn, expands to \verb~\classMember{Fred}{Flintstone}{FF34345/thor}~. + +In theory, \ameta{entry} can be quite general, but the \ameta{\cs{cmd}} must to be able to parse +it and generate the expected data (\cs{classMember*\darg{\ameta{first}}\darg{\ameta{last}}\darg{\ameta{folder}}}). + +\subsubsection{The \tops{\protect\cs{sadQuizzes}}{\textbackslash{sadQuizzes}} command}\label{sss:sadQs} + +We now discuss the insertion of the following environment and command: +\bVerb\takeMeasure{\string\begin\darg{makeClassFiles}}% +\begin{dCmd}{\bxSize} +\begin{makeClassFiles} +\sadQuizzes +\end{makeClassFiles} +\end{dCmd} +\eVerb The \env{makeClassFiles} environment is a simplified version of the +\env{execJS} environment of the \pkg{insdljs} package and is similar to +\env{docassembly} introduced earlier. The \cs{sadQuizzes} command (it does not +mean sad news for the students on this quiz) expands to some JavaScript that +\underbar{s}aves \underbar{a}nd \underbar{d}istributes the quizzes of the +students to the designated folders, but \cs{sadQuizzes} do more than that: +\begin{itemize} + \item If solution pages are present, these pages are extracted from the + parent document, saved to the instructor's folder, and then deleted from + the parent document. + \item If there are cover pages, these are removed and saved to the + instructor's folder. + \item For each member of the class, it builds a customize quiz + \begin{itemize} + \item It reinserts the cover pages, if any. + \item It populates the name fields with the first and last name of the + current class member being processed. + \item It saves each (customized) quiz to the appropriate student folder + with the file name \cs{jobname-\ameta{first}\_\ameta{last}.pdf} + \item It saves a copy of the (customized) quiz to the instructor's + designated folder. + \end{itemize} +\end{itemize} + +\paragraph*{Student's experience.} Same as \textbf{Student's experience}, as described in +Section~\ref{ss:BMs} on page~\pageref{para:basic-SE}, but the student does +not enter {\hisher} name in the name fields. One of the tasks of +\cs{sadQuizzes} is to pre-populate the name fields with the names of the +students. + +\paragraph*{Instructor's experience.} Same as \textbf{Instructor's experience}, as described in +Section~\ref{ss:BMs}on page~\pageref{para:basic-IE}. The instructor must manually record\FmtMP{manually record} the +student's score. + +%\subsection{Quizzes that specify \tops{\protect\opt{usebatch}}{usebatch} option}\label{ss:ub} +\subsection{The \tops{\protect\opt{usebatch}}{usebatch} option: single rendition source}\label{ss:ub} + +The demonstration file for this section is \texttt{theexub.tex}. + +\newtopic\noindent +There can be only one quiz (as declared by the +\cs{DeclareQuiz\darg{\ameta{qz-name}}} command); however, there can be more +than one \textit{rendition}\FmtMP{rendition discussed} (or one variation) of the quiz. In this section, +we deal with the simplest case: the source file has only one rendition of the +quiz. In \hyperref[ss:mr]{Section~\ref*{ss:mr}}, the case of multiple renditions is covered. + +\paragraph*{File construction.} A quiz constructed with the \opt{usebatch} option is the same as one that +uses \opt{useclass} (see \hyperref[ss:uc]{Section~\ref*{ss:uc}}); in fact, +specifying the \opt{usebatch} option automatically passes the \opt{useclass} +option to \pkg{thorshammer}. The difference is in the instructor's +experience; when the instructor presses the \textsf{Mark It} control, instead +of the \textsf{Freeze Quiz} button appearing, the \textsf{Save \& Close} +button appears. After the instructor is finished marking up the quiz, as +described in \textbf{Instructor's experience} on +page~\pageref{para:basic-IE}, {\heshe*} presses the \textsf{Save \& Close} +button, which saves and closes the quiz document. After the instructor has +inspected each of the quizzes, {\heshe*} is ready to use \textsf{Thor's way} +action-wizard (or batch sequence). + +\subsubsection{How to use the \textsf{Thor's way} action}\label{sss:TW} + +A powerful feature of the \app{Acrobat} application is the \textsf{Action +Wizard}. The user-interface allows you to define a custom action that +performs a series of tasks on each PDF in the list of PDFs to be processed. +The \pkg{thorshammer} package provides its own action-wizard titled +`\textsf{Thor's way}'. + +\paragraph*{What does \textsf{Thor's way} do?} For each of the quizzes that are +designated as the files to be processed, this action-wizard performs the following tasks: +\begin{enumerate} + \item If solutions were provided for this quiz, the solution pages are + retrieved from the instructor's folder and inserted onto the end of + the quiz. + \item Gets the values for the name, student report and student grade + fields, and holds them as JavaScript variables. + \item Freezes the document (makes all fields readonly and flattens all + pages) + \item Saves the frozen quiz under the name + \texttt{\ameta{filename}-g.pdf}. Recall the \texttt{filename} is + \texttt{\cs{jobname}-\ameta{first}\_\ameta{last}}, where \cs{jobname} + is the base name of the (parent) {\LaTeX} source file that generated + the quizzes to begin with. The file is saved to the folder designated + as the `save folder.' +\end{enumerate} +Additional details are contained in the paragraph \textbf{How to use +\textsf{Thor's way}} found below. + +\paragraph*{How to install \textsf{Thor's way}.} +\begin{enumerate} + \item Start \app{Acrobat} + \item select \textsf{Tools} from the toolbar + \item Find and open the \textsf{Action Wizard} + \item Select \textsf{Manage Actions} + \item In the \textsf{Manage Actions} dialog box, press the + \textsf{Import} button on the right-hand side + \item Navigate to the \texttt{action-wizards} folder of the + \pkg{thorshammer} package and choose either \textsf{Thor's way (en).sequ} + or \textsf{Thor's way (de).sequ} (both can be installed). + The wizard is now installed. + \item Back out of where you are, saving as you go +\end{enumerate} + +\paragraph*{How to use \textsf{Thor's way}.}\label{para:UTW} Use this action after +the instructor has finished reviewing each of the quizzes by first pressing the +\textsf{Mark It} button, assigning additional points as needed, and pressing +the \textsf{Save \& Close} button. + +\newtopic\noindent\textbf{Preliminaries}\vspace{-6pt}\relax +\begin{enumerate} +\item[] This package comes with two files: \texttt{control.pdf} and + \texttt{terminate-batch.pdf}. \emph{These two files are always placed in + the same folder together}.\footnote{Source files for these two PDFs are provided so you + can localize any instructions to the land of your choice.} Copy these two files to some folder convenient to the + work you are doing. +\end{enumerate} + +%\goodbreak + +\newtopic\noindent\textbf{Preparation phase}\vspace{-6pt}\relax +\begin{enumerate} + \item Open the \texttt{container.pdf} file in the \app{Acrobat} window, + see Figure~\ref{cap:container}. Purpose of this file is to provide + the \textsf{Thor's way} some needed basic information, it also holds + the summary of the quiz results as an attachment. The document contains + two push buttons, two text fields, and two check boxes. + +\begin{figure}[tbh]\centering\setlength\fboxsep{0pt} +\fbox{\includegraphics[width=.67\linewidth]{graphics/container}}\\ +\caption{\texttt{container.pdf}}\label{cap:container} +\end{figure} + +\item With the \texttt{container.pdf} file open, in the top most text field, + enter a name for the quiz. This will be the base name for the + tab-delimited TXT file that is attached to \texttt{container.pdf} +\item In the bottom most text field, enter the folder (path) where the quiz files + are to be saved. (These are the ones named \texttt{\cs{filename-g.pdf}}) + The folder path you enter can be a relative to the folder that contains \texttt{container.pdf}, + or it can be a full (absolute) path to the folder. eg, + \begin{flushleft}\ttfamily + /c/users/thor/documents/myuni/spr19/algebra/myclass/graded + \end{flushleft} + Notice the method of referencing the path, this is the + device-independent file path reference in the Acrobat JavaScript API Reference manual. + See the short article at \href{https://acrobatusers.com/tutorials/print/file-paths-acrobat-javascript}{AcrobatUsers.com} + for more information.\footnote{On \app{Windows}, a \app{Windows} path seems to work as well: \texttt{c:\string\users\string\thor\string\...\string\graded}} +\item \checkBox[\DV{Yes}\V{Yes}\Ff\FfReadOnly]{apslns}{11bp}{11bp}{Yes} \uif{Append solutions, if they exist}\\ + This check box is checked by default. Clear this box if you don't want + any solutions to the quiz appended. The \uif{Thor's way} action + sequence appends the solutions or not according to the state of this + checkbox. +\item \checkBox[\DV{Yes}\V{Yes}\Ff\FfReadOnly]{rcddt}{11bp}{11bp}{Yes} + \uif{Record class data}\\ + This check box is checked by default. If you don't want to record the + class data, clear this check box. Normally, this box is always checked; + however, if you run \uif{Thor's way} with \uif{Append solutions, if + they exist} cleared and at a later time you want to append the + solutions, run \uif{Thor's way} again on the same set of quizzes with + \uif{Record class data} cleared. The quiz data file attached to the + \texttt{container.pdf} will be preserved. +\item Now press the button labeled \textsf{Push}. The information of the + text fields are saved as global JavaScript variables that can be + accessed by the batch sequence. When you press \textsf{Push}, the file + \texttt{container.pdf} closes, don't worry. +\end{enumerate} + +\newtopic\noindent\textbf{Action phase}\vspace{-6pt}\relax +\begin{enumerate}\setcounter{enumi}{4} + \item Open the \textsf{Action Wizard} and choose \FmtMP{{Action: }\textsf{Thor's + way}}\textsf{Thor's way} from + the list of actions. + +\begin{figure}[tbh]\centering\setlength\fboxsep{0pt} +\includegraphics[width=.33\linewidth]{graphics/action-down-arrow}\\ +\caption{\textsf{Select files to be processed}}\label{cap:ada} +\end{figure} + + \item \textbf{Select files to be processed.} Click on the down arrow + control, as indicated in Figure~\ref{cap:ada}. Choose the \textsf{Add + Folders...} control if your quizzes are in a folder structure, + \app{Acrobat} should find all PDFs in the folder (including + subfolders) and list them. Choose the \textsf{Add Files...} controls + if the quizzes are all in the same folder and you can select them + all. + +\begin{figure}[tbh]\centering\setlength\fboxsep{0pt} +\includegraphics[width=.67\linewidth]{graphics/ManageFiles}\\ +\caption{\textsf{ManageFiles dialog box}}\label{cap:fmd} +\end{figure} + + \item \textbf{Select \texttt{terminate-batch.pdf}.} With the \textsf{Add + Files...}\ control, select the package file \texttt{terminate-batch.pdf}, which resides + in the same folder as \texttt{control.pdf}. This file must be last in + the list of files to be processed; if necessary, press the down arrow + control and select \textsf{Manage Files} (see Figure~\ref{cap:ada}). + The \textsf{Manage Files} dialog box, Figure~\ref{cap:fmd}, lists all + the files to be processed. Using the down arrow control in the right, + move the \texttt{terminate-batch.pdf} to it is last in the list. + +\item Keeping your fingers crossed and press the \textsf{Start} control. Each + of the quizzes is brought into the \app{Acrobat} window, form field + information is extracted, frozen, saved, and closed. + +\item When the \texttt{terminate-batch.pdf} is reached (bottom of the + list), no extracting or freezing occurs, but what happens is the + \texttt{control.pdf} document is opened once again. + +\begin{figure}[tbh]\centering\setlength\fboxsep{0pt} +\includegraphics[width=.67\linewidth]{graphics/quiz-results}\\ +\caption{\textsf{Results displayed}}\label{cap:qr} +\end{figure} + +\item Look at the \textsf{Attachments} panel, using the user-interface, + save the attachment to where you want it. Figure~\ref{cap:qr} shows the + results of a test run of \textsf{Thor's way}. The produced TXT file is + a tab-delimited file that can be opened in \textsf{Microsoft Excel}. + These saved quiz results can be merged, no doubt, into a parent + \textsf{Excel} spreadsheet. + +\end{enumerate} + +\subsection{The \tops{\protect\opt{usebatch}}{usebatch} option: multiple renditions source}\label{ss:mr} + +The demonstration files for this section are \texttt{thexr.tex} and \texttt{thexrt.tex}. + +\newtopic\noindent +In this section we discuss techniques for introducing multiple renditions of +a quiz into the workflow. To be fair the student, the renditions should be roughly equivalent or the students will cry +``foul!'' We don't want that to happen, we have enough troubles. + +\subsubsection{Preamble} + +Same preamble as previously described, including the use of \cs{sadQuizzes}. + +\subsubsection{The body of the document} + +Following the \cs{DeclareQuiz} command, declare one or more quiz body names using +the \cs{declareQuizBody} command. Each quiz body declaration has a corresponding quiz +body environment that contains a quiz. A rough outline is seen below. + +\begin{Verbatim}[xleftmargin=\amtIndent,commandchars=!()] +%!textsf( declare the name of this quiz) +\DeclareQuiz{!ameta(quiz-name)} + +%!textsf( declare the names of the renditions) +\declareQuizBody{!ameta(qb-name!SUB1)} +... +\declareQuizBody{!ameta(qb-name!SUB(k))} + +%!textsf( each rendition is a complete quiz within its own environment) +%!textsf( call these environments ``quiz body'' environments) +\begin{!ameta(qb-name!SUB1)} + !ameta(quiz-rendition!SUB1) +\begin{!ameta(qb-name!SUB1)} +... +\begin{!ameta(qb-name!SUB(k))} + !ameta(quiz-rendition!SUB(k)) +\begin{!ameta(qb-name!SUB(k))} +\end{Verbatim} +Actually, there may be only one rendition ($k=1$), but there is randomness built into +the single rendition to produce a different, yet equivalent, version of the quiz. + +The \env{\ameta{qb-name}} environments are verbatim environments that write their contents +to a CUT file, which are later input back into the document. + +\newtopic\noindent Following the \env{\ameta{qb-name}} environments comes the final step, +we input these back into the document. +\begin{Verbatim}[xleftmargin=\amtIndent,commandchars=!()] +\InputQuizBody{!ameta(qb-name!SUB1)} +... +\InputQuizBody{!ameta(qb-name!SUB(k))} +\end{Verbatim} +You can input some or all of the declared quiz bodies, and the quiz bodies may be input several +times, especially useful if a quiz body has a degree of randomness built into it. + +When you \cs{DeclareQuizBody}, there is an associated version (or rendition) +number in the form of the text macro \cs{QzVer}\FmtMP{\cs{QzVer}}, that +expands to a number (1, 2, 3, and so on). This number can be incorporated +into various section titles, such as in the \cs{sqslsectitle}, +\cs{thQzHeader}, and \cs{thQzHeaderCS} commands, for example. Refer to +\texttt{examples/misc/thexrt.tex} for illustrations. + +\subsubsection{The \tops{\protect\cs}{\textbackslash}{sadQuizzes} command (revisited)} + +When you compile a multi-rendition file, and bring the resulting PDF into a +PDF viewer, you'll see you have $n$-quizzes contained in the document, where +$n$ is the number of \cs{InputQuizBody} commands used. Here is a brief +description of the action of \cs{sadQuizzes} in a multi-rendition document. +\begin{itemize} + \item If solution pages are present, these pages are extracted from the + parent document, saved to the instructor's folder, and then + deleted from the parent document. + \item If there are cover pages, these are removed and saved to the + instructor's folder. + \item As the script goes through the list of students, it extracts one of + the $n$ quizzes in the parent document and populates it with the name + data. + \item If there are cover pages for this quiz set, the cover pages are + retrieved from the instructor's folder and inserted onto the front of + the quiz. + \item The extraction of a subset of pages preserves the document JavaScript, + but some elements vital to the whole workflow are lost. The script + restore these lost elements. + \item It saves each (customized) quiz to the appropriate student folder + with the file name \cs{jobname-\ameta{first}\_\ameta{last}.pdf} + \item It saves a copy of the (customized) quiz to the instructor's + designated folder. +\end{itemize} +What you should get is several versions assigned to the class members: +\begin{itemize} + \item class member 1 gets the first rendition + \item class member 2 gets the second rendition + \item[]... + \item class member $n$ gets the $n^{\text{th}}$ rendition, where $n = \text{number of \cs{InputQuizBody}}$ statements + \item class member $n+1$ gets the first rendition + \item[]... +\end{itemize} +When the parent document is opened in \app{Acrobat}, \cs{sadQuizzes} +executes creates and distributes the quizzes to the instructor's folder and +to the student's individual folder. It's just that simple. + +\paragraph*{Student's experience.} Same as their earlier experience, hopefully, this time around it will +be a better experience, better results, happier student, we can only hope. + +\paragraph*{Instructor's experience.} Same as above, except {\heshe} has different quizzes to evaluate within +a class. Poor instructor. After {\heshe*} has finished marking the quizzes, +{\heshe*} runs them through \textsf{Thor's way} (\Nameref{sss:TW}), which +leads to happiness for the instructor. The student's score is automatically +recorded\FmtMP{automatically recorded} by the \textsf{Thor's way} action +sequence. + +\subsection{Quizzes that specify the \tops{\protect\opt{batchdistr}}{batchdistr} option}\label{ss:bd} + +The \opt{batchdistr} option is the same as the \opt{usebatch} option, with +only one difference: After the source file is compiled and opened in +\app{Acrobat}, the newly created quizzes are distributed to the instructor's +folder (as declared by \cs{instrPath}), but \emph{the quizzes are not +distributed to the student folders}. The quizzes are distributed to the +student's folder using batch sequences, to be detailed in subsequent +paragraphs. + +\paragraph*{Apply security before distributing quizzes.} The real purpose of +delaying the distribution of the quizzes to the student folders is to place +\emph{password security} on the quiz files. After building the instructor's +copies of the quizzes, the instructor can use the action \textsf{Thor +protects and distributes}. The details of the workflow follows: +\begin{enumerate} +\item \textbf{Build:} Build the source quiz file using the \opt{batchdistr} option. + +\item[] When the source file is opened in \app{Acrobat} the first time, the + custom-named quiz files are saved into the instructor's folder (as + specified by \cs{instrPath}); no quizzes are deposited in the student + folders yet. + +\item \textbf{Secure and distribute:} With the \app{Acrobat} window empty, + open the \textsf{Action Wizard} and select the \FmtMP{{Action: }\textsf{Thor + protects and distributes}}\textsf{Thor protects and distributes} action. + For the \textsf{Files to be processed}, select the quizzes that have + just been dropped into the instructor's folder. Perform the action by + pressing \textsf{Start}. + + Note: To delay the distribution of the quizzes, apply + \textsf{Thor protects} and later apply \textsf{Thor distributes}. + +\item \textbf{Examination period:} Now the students take the quiz, the quiz + has password security so the student cannot snoop around with the file, + even if the student has access to \app{Acrobat}. + +\item \textbf{Marking period:} Following the exam period, the instructor + examines each quiz: Press the \textsf{Mark It} button, award any points + for extended response questions, assign a student grade, and press the + \textsf{Save \& Close} button. + +\item \textbf{Remove security:}\label{item:RS} Press \textsf{Ctrl+K} to + open the \textsf{Preferences} dialog box. In the left-hand panel, + select \textsf{Action Wizard}. In the right-hand panel change + \textsf{Security Method}, using the dropdown menu to \textsf{Password + Security}. Save your changes by pressing the \textsf{OK} control in the + lower-right corner. + +\item[] With the \app{Acrobat} window empty, open the \textsf{Action + Wizard} and select the \FmtMP{{Action: }\textsf{Thor removes + protection}}\textsf{Thor removes protection} action. For the + \textsf{Files to be processed}, select the quizzes in the student + folders. Use either \textsf{Add Folder...} or \textsf{Add Files...} to + select all the quizzes. Perform the action by pressing \textsf{Start}. + +\item Press \textsf{Ctrl+K} to open the + \textsf{Preferences} dialog box. In the left-hand panel, select + \textsf{Action Wizard}. In the right-hand panel change \textsf{Security + Method}, using the dropdown menu to \textsf{Do not ask for password}. Save + your changes by pressing the \textsf{OK} control in the lower-right + corner. + +%Thor allows changes (password) student folders container +\item \textbf{Thor's way:} Now apply the \FmtMP{{Action: }\textsf{Thor's + way}}\textsf{Thor's way} action, as described in the paragraph + \textbf{\nameref{para:UTW}} on page~\pageref{para:UTW}. +\end{enumerate} + +\section{Bells and whistles} + +\subsection{Running Headers} + + The scheme used here assumes no other {\LaTeX} package has been used to take over the running + headers (and footers). If that is the case, use the values of the commands below to design + your own. +\bVerb\small\takeMeasure{\string\thQzHeaderCQ\darg{\ameta{text}}}% +\setlength{\eflength}{\widthof{\sffamily(Solutions: \cs{thQuizName})}}% +\edef\x{\the\eflength}% +\setlength{\eflength}{\bxSize}% +\def\1{\rlap{\hskip\eflength\rlap{\hskip\x\relax\quad\cs{def}\cs{th@QzHeaderLQ\darg{\ameta{text}}}}\sffamily(Thor's class)}} +\def\2{\rlap{\hskip\eflength\rlap{\hskip\x\relax\quad\cs{def}\cs{th@QzHeaderCQ\darg{\ameta{text}}}}\sffamily(Quiz \cs{thQuizName})}} +\def\3{\rlap{\hskip\eflength\rlap{\hskip\x\relax\quad\cs{def}\cs{th@QzHeaderCS\darg{\ameta{text}}}}\sffamily(Solutions: \cs{thQuizName})}} +\def\4{\rlap{\hskip\eflength\rlap{\hskip\x\relax\quad\cs{def}\cs{t@hQzHeaderR\darg{\ameta{text}}}}\sffamily(\cs{thepage})}} +\begin{dCmd}[fontsize=\small,commandchars=!()]{\bxSize} +!1\thQzHeaderL{!ameta(text)} +!2\thQzHeaderCQ{!ameta(text)} +!3\thQzHeaderCS{!ameta(text)} +!4\thQzHeaderR{!ameta(text)} +\end{dCmd} +\eVerb These command declarations allow you to set the left, center (for quiz +pages and solution pages), and right running headers. The content of the +parentheses to the right are the default values, which obviously need to be +changed, except, perhaps, for the right header. The declarations in the first column, +define text macros, whose definitions are given in the third column. + +The special command \cs{thQuizName} expands to the name of the \ameta{qz-name}, where \ameta{qz-name} +was declare earlier by \cs{DeclareQuiz\darg{\ameta{qz-name}}}. Typically, the choice +for the quiz name very simple, such as \texttt{q1}. You can have a more meaningful +name by declaring \cs{thQzName\darg{\ameta{friendly-qz-name}}}; such a declaration +defines the text macro \cs{thqzname} that expands to \ameta{friendly-qz-name}. The package +initially declares \cs{thQzName\darg{\cs{thQuizName}}}; for example, +\begin{Verbatim}[xleftmargin=\amtIndent] +\thQzHeaderCQ{Pr\"{u}fung: \thqzname} +\thQzHeaderCS{L\"{o}sungen: \thqzname} +\thQzName{Grammatik 1} +\end{Verbatim} +The \cs{rhPgNumsOnly}\FmtMP{\cs{rhPgNumsOnly} discussed} command removes all +running headers, except for the page number in the right header. Expand in +the preamble. + +\subsection{Solution pages} + +Thor's hammer does support solutions to questions via the usual +\env{solution} environment. When the parent document is built and opened in +\app{Acrobat}, the solution pages are identified, extracted, saved to the +instructor's folder,\footnote{For a parent document that uses basic methods +(no options), the solutions are saved to the current folder of the parent +document.} and deleted from the parent document. As a result, the quiz the +student sees does not contain the solution pages. + + +\subsection{Cover pages} + +While Thor is hammering away on the solution pages, Thor's hammer also +supports the notion cover pages, these are one or more pages appearing in the +front of the parent document (prior to any quizzes). These pages are normally +ignored when the process of building the custom quizzes for the class; +however, if you declare in the \emph{preamble}\FmtMP{preamble only}, +\bVerb\small\takeMeasure{\string\DeclareCoverPage\darg{\ameta{bPg[-ePg]}}}% +%\setlength{\eflength}{\bxSize}% +\begin{dCmd}[fontsize=\small,commandchars=!()]{\bxSize} +\DeclareCoverPage{!ameta(bPg[-ePg])} +\end{dCmd} +\eVerb where \ameta{bPg[-ePg]} are the beginning (\meta{bPg}) and ending +(\meta{ePg}) page numbers; this forms a range of page numbers. As indicated +by the syntax, \cs{ePg} is optional. The values of these page numbers are +0-based\FmtMP{0-based numbering}; that is 0 is the first page of the parent +document, 1 is the second page, and so on. \cs{DeclareCoverPage\darg{0}} +states that page~0 is a cover page, while \cs{DeclareCoverPage\darg{0-1}} +declares the first two pages in the parent document are cover pages. (Page~0 +might be a title page, page~1 might be extensive instructions and other +information.) Use your knowledge of {\LaTeX} so that there are no page numbers\FmtMP{no page numbers on cover pages} +on the cover pages. + +\subsection{Switches to control program flow} + +In this section, we provide switches that give control over the behavior the creation +and function of a quiz. +\bVerb\small\takeMeasure{\string\distrToStudentsOn \string\distrToStudentsOff}% +%\setlength{\eflength}{\bxSize}% +%\def\1{\rlap{\hskip\eflength D}} +\begin{dCmd}[fontsize=\small,commandchars=!()]{\bxSize} +\autoCopyOn \autoCopyOff + +\instrAutoSaveOn \instrAutoSaveOff +\instrAutoCloseOn \instrAutoCloseOff + +\stuAutoSaveOn \stuAutoSaveOff +\stuAutoCloseOn \stuAutoCloseOff + +\distrToInstrOn \distrToInstrOff +\distrToStudentsOn \distrToStudentsOff +\end{dCmd} +\eVerb The defaults for the above commands are the `On' versions. +\begin{description} +\item[\cmd\autoCopyOn] During document development, you don't want to copy + the files each time you build and review the document in \app{Acrobat}. + Set \cs{autoCopyOff} during quiz development, and declare + \cs{autoCopyOn} when you want to distribute. The default is + \cs{autoCopyOn}. + +\item[\cs{instrAutoSaveOn}] When the instructor presses the freeze quiz + control, there is an option to automatically save the document or not. + \cs{instrAutoSaveOn} saves the document; however, if + \cs{instrAutoSaveOff} is expanded in the preamble, no automatic save is + performed. The default is \cs{instrAutoSaveOn}. + +\item[\cs{instrAutoCloseOn}] When the instructor presses the freeze quiz control, there is an option + to silently close the document or not. \cs{instrAutoCloseOn} closes the document; however, if + \cs{instrAutoCloseOff} is expanded in the preamble, no automatic + closing occurs. The default is \cmd{\instrAutoCloseOn}. + +\item[\cs{stuAutoSaveOn}] When expanded in the preamble, a save button will appear + (created by \cs{stuSaveBtn}) when the \textsf{End Quiz} control is pressed. A + dialog appears to save the file, the student can choose the file + location and the file name at that time. When \cs{stuAutoSaveOff} is in + effect, the save button does not appear, and the student must press the + save button the on \app{Adobe Reader} toolbar. The default is + \cs{stuAutoSaveOn}. + +\item[\cs{stuAutoSaveOff}] This command is obeyed only if + \cmd{\stuAutoSaveOn} is in effect. After the student presses the save + button (\cmd\stuSaveBtn), the document is closed after the student save + the document. Note that if the student cancels saving the document and + if the document still needs saving, the document is not closed. The + default is \cmd\stuAutoCloseOn. + +\item[\cs{distrToInstrOff}] Allow the instructor to turn off the + distribution of the quizzes to himself by using \cs{distrToInstrOff}, + the default is \cs{distrToInstrOn}. + +\item[\cmd\distrToStudentsOff] This switch allows the instructor to turn off + the distribution of the quizzes to the student folders, the default is + \cs{distrToStudentsOn}. (Note: The \opt{batchdistr} option expands + \cs{distrToStudentsOff}. + +\end{description} +Except for \cs{autoCopyOn} and \cs{autoCopyOff}, there is normally no reason +to change these switches from their defaults. They are here to provide +additional control. + +\subsection{Language localization}\label{s:lang} + +There are a number of language dependent phrases that appear in the +document, these have conveniently been gathered into the file +\texttt{thorshammer.cfg}. If found on the {\LaTeX} search path, it is +automatically loaded, unless the \opt{nocfg} option is in force. This file +can be localized to your own language, hopefully no umlauts needed. + + +\subsection{System scripts}\label{s:sysscrpts} + +In the course of developing this package, several +\uif{Powershell} system scripts were written to illustrate the +workflow to ourselves. During the long development of this +package, the scripts were folded into a single \uif{Powershell} +script file \texttt{thmclass.ps1}. The use of +\texttt{thmclass.ps1} is described in the file +\texttt{thmclass.pdf}, found in the \texttt{docs} folder. + +\begin{comment} +\newtopic\noindent The scripts are assume the folder structure of mighty Thor himself +is used. The scripts use three variables that need to be modified: +\texttt{\$instrName} (\texttt{instrName}), \texttt{\$instrDest} +(\texttt{instrDest}), and \texttt{\$startLocation} (\texttt{startLocation}). +For PowerShell, variables begin with a dollar sign, where is in bash shell +they do not. +\begin{itemize} + \item \textbf{Windows PowerShell scripts} + \begin{itemize} + \item \texttt{getquizzes.ps1}\\ \emph{Copies} every PDF file residing in a folder + with name \texttt{\$instrName} to the folder defined + by the path \texttt{\$instrDest}. + \item \texttt{rmquizzes.ps1}\\ \emph{Removes} (deletes) every PDF file residing in a folder + with name \texttt{\$instrName}. + \item \texttt{mvquizzes.ps1}\\ \emph{Moves} every PDF file residing in a folder + with name \texttt{\$instrName} to the folder defined + by the path \texttt{\$instrDest}. + \end{itemize} +\goodbreak + \item \textbf{Linux bash scripts} + \begin{itemize} + \item \texttt{getquizzes.sh}\\\emph{Copies} every PDF file residing in a folder + with name \texttt{instrName} to the folder defined + by the path \texttt{instrDest} + \item \texttt{rmquizzes.sh}\\ \emph{Removes} (deletes) every PDF file residing in a folder + with name \texttt{instrName}. + \item \texttt{mvquizzes.sh} \emph{Moves} every PDF file residing in a folder + with name \texttt{instrName} to the folder defined + by the path \texttt{instrDest}. + \end{itemize} +\end{itemize} +Having each quiz in an folder with the instructor's name (\texttt{\_Thor}, or +some other unique name) allows the scripts to find the quiz PDFs, \emph{and no +others}. + +\paragraph*{Executing these scripts.} To begin with, I'm no expert. \verb~:-{)~ +\begin{itemize} + \item \textbf{Windows PowerShell scripts.} You must grant the + permissions for the scripts to executed: open PowerShell (run as + administrator)1, paste \texttt{Set-ExecutionPolicy RemoteSigned} at + the prompt and execute this line. + \item[] The easiest way of working with PowerShell is through the Windows + PowerShell ISE app. Press the Search icon in the lower left corner of + windows and type in PowerShell and amongst the matches presented is + Windows PowerShell ISE. To executed one of the scripts, use the + File menu to open \texttt{getquizzes.ps1}, for example. There you can edit + and save the script in the editor provided. To run the script, press the Run Script (F5) + on the toolbar. + \item \textbf{Linux bash scripts} On Linux there are permissions to be granted as well, I refer + the interested reader to \href{https://ryanstutorials.net/bash-scripting-tutorial/bash-script.php}{this web page}.\footnote + {\url{https://ryanstutorials.net/bash-scripting-tutorial/bash-script.php}} This web page is just one of many + found by a Google search. +\end{itemize} +\end{comment} + +\section{List of sample files} + +The sample files are found in the \texttt{example} folder. Fundamentally, +there are only six demonstration files, but these are replicated several times +and distributed over several times in sub-folders of the main \texttt{examples} folder. +The sample files, listed in increasing complexity, and their brief descriptions follow: +\begin{description} + \item[\texttt{thexb.tex}] uses no option and represents the basic + methods described in Section~\ref{ss:BMs}. + \item[\texttt{theuc.tex}] uses the \opt{useclass} option, as described + in Section~\ref{ss:uc}. + \item[\texttt{thexub.tex}] uses the \opt{usebatch} option, as described + in Section~\ref{ss:ub}. The instructor can use \textsf{Thor's way} + action sequence on these quizzes to automatically record the + student scores. + \item[\texttt{thexbd.tex}] uses the \opt{batchdistr} option, as described + in Section~\ref{ss:bd}. For this file, distribution of the student + quizzes is delayed. It is expected to apply some security first. + \item[\texttt{ther.tex}] uses the \opt{usebatch} option with the + \opt{allowrandomize} option for \pkg{exerquiz}. As a results, + certain MC and MS choices are randomized. The \env{quizbody} + environment encloses the body of the quiz and input back into the + document twice. As a result, we obtain two versions of the same + quiz, with two randomized order for MC and MS choices. + \item[\texttt{theexrt.tex}] uses the \opt{usebatch} option with the + \opt{allowrandomize} option for \pkg{exerquiz} and uses the + \pkg{ran\_toks} package as well. The \pkg{ran\_toks} package is + used to randomize the order of the questions, in addition to the + randomization of the choices of \texttt{thexr.tex}. The + \env{quizbody} environment is used twice on two distinct set of + quiz questions, and input back in several times. The results are + three ``renditions'' of two distinct quizzes, the order of the + questions and choices are randomized. +\end{description} +The above files may appear in the following folders. +\begin{description} + \item [\texttt{nosolns} folder:] This is the original collection of demonstration files, + all having no solutions associated with any of the questions. (The + simplest case.) + \item [\texttt{wthsolns} folder:] The same six demo files, but with selected solutions to + the questions. The \texttt{thexb.tex} demonstrates how to set of the + document with a screen design (\opt{designi}). It also uses the + \pkg{spdef} package (provided) to format the document with or without + a design option of \pkg{web}. Some of the files use running headers. + \item[\texttt{cfg} folder:] There are several files in this folder, each + using the \opt{usebatch} option. They illustrate how to input + instructor and student data through CFG files, as described in + section entitled \Nameref{sss:CI}. + \item[\texttt{misc} folder:] The \texttt{thexrt.tex} file is in this + folder. The file has been modified several ways. + \cs{thQuizHeaderLayout} is redefined to hide the \cs{FirstName} and + \cs{LastName} fields. (Do not delete these two commands, they are + required, but we can hide them.) Instead of displaying the first and + last name, the \cs{FullName} command is used on the cover page. The + \cs{FullName} command gets its value from the values of + \cs{FirstName} and \cs{LastName}. The changes give the quizzes a + slightly different look. + \item[\texttt{target} folder:] The demo files that use the \opt{useclass} + option, need a target to drop the instructor's copies of the quizzes + and the student copies of the files. In each of the demo files where + class information is provided, you need to adjust the paths to taget + the subfolders of the \texttt{target} folder. The \texttt{target} + folder may be copied to the desktop, as I did, and target the quiz + files there. +\end{description} + +\section{Summary of action sequences provided}\label{actSeq} + +By ``actions sequences'' we mean batch sequences of \app{Acrobat} that +perform a series of tasks. Refer the document +\href{install-action-seq.pdf}{install-action-seq.pdf} for information on +how to install action sequences, found in the \texttt{docs} folder of this +distribution. +\begin{itemize} + \item\textbf{\textsf{Thor's way} action.} This action is performed on the (student) + completed and (instructor) marked quizzes. Refer to + \textbf{\nameref{sss:TW}} on page~\pageref{sss:TW} for more information + on \textsf{Thor's way}. + \begin{itemize} + \item \textbf{Applies to} quizzes compiled with the + \opt{usebatch} or \opt{batchdistr} option. + \item\textbf{What it does:} For each quiz, it extracts first + name, last name, score, total points from the quiz and saves + them to an attachment of \texttt{container}; it flattens + the quiz and saves the flattened quiz with a suffix of + \texttt{"-g"} to the folder designated by the + \texttt{container} file. + \item\textbf{Steps to run the \textsf{Thor's way} action} + \begin{itemize} + \item Open the file \texttt{container.pdf} + (\hyperref[cap:container]{Figure~\ref*{cap:container}}) + and fill out the fields provided and press the + \textsf{Push} button. The file saves the data entered in + the form fields then closes. + \item Select the tool \textsf{Action Wizard}, then select + \textsf{Thor's way} + \item\textsf{Files to be processed:} Selected the quizzes + (using the \textsf{Add Folder} and/or \textsf{Add Files} + controls), then select the special file + \texttt{terminate-batch.pdf}. This latter file \emph{must + be the last file to be processed}. + \item Start the batch by pressing the \textsf{Start} control + \end{itemize} + \end{itemize} + \item[] After the action is finished, the \texttt{control} document + should be in the \app{Acrobat} window. Check the console window + to see if there are any errors. The attachment to this file + contains the quiz results, save and do with them what you will, + perhaps merging them into a larger spreadsheet. + \item \textbf{\textsf{Thor protects} action.} Applies to a collection of + newly created quizzes that specify the \opt{batchdistr} option. + Running this action places security on the quizzes so the student's + cannot view the answers even if they are using \app{Acrobat}. + \item \textbf{\textsf{Thor distributes} action.} A general purpose action + that returns quizzes from the instructor's folder (or subfolder) to their + respective student folders. There are two situations where you would apply + this action: + \begin{itemize} + \item The \textsf{Thor's way} action drops the completed and + marked quizzes (with suffix \texttt{"-g"}) into the folder + designated in the \texttt{container} file. This action copies + them back into the student folders. + \item For a quiz this is compiled with the \opt{batchdistr}, the + distribution of the quizzes is delayed (possibly to place + security restrictions on them using the \textsf{Thor + protects} action). At the time where you want to deploy the + quizzes to the students folders, you can use \textsf{Thor + distributes} to accomplish that task. + \end{itemize} + \item \textbf{\textsf{Thor protects and distributes} action.} Applies to + a collection of newly created quizzes that specify the + \opt{batchdistr} option. Refer to + \hyperref[ss:bd]{Section~\ref{ss:bd}} for more details. The action is + to apply security to the quizzes and then to distribute them to the + student folders. This is a combination of \textsf{Thor protects} and + \textsf{Thor distributes}. + +\goodbreak + \item[]\textbf{Steps to run the \textsf{Thor protects and distributes} action} + \begin{itemize} + \item Select the tool \textsf{Action Wizard}, then select + \textsf{Thor protects and distributes} + \item\textsf{Files to be processed:} Selected the quizzes + (using the \textsf{Add Folder} and/or \textsf{Add Files} + controls). These are undistributed quizzes and should + reside in the instructor's folder. + \item Start the batch by pressing the \textsf{Start} control. + \end{itemize} + \item[] After this action is completed, copies of the secured files should + now be in the student folders. + \item \textbf{\textsf{Thor removes protection} action.} This action is a + natural continuation of \textsf{Thor protects and distributes}. It + removes the security previously placed on the quizzes. This is needed + to flatten the quizzes later in the work flow. The whole workflow is + described in \hyperref[ss:bd]{Section~\ref{ss:bd}}. In particular, + see \hyperref[item:RS]{item~\ref*{item:RS}} titled \textbf{Remove Security}. + After removing security, we continue with the \textsf{Thor's way} action. +\end{itemize} + +\section{Further discussion of Basic Methods} + +The essential difference between these two methods is how the quiz files are +named: +\begin{itemize} + \item For basic methods, when multiple quiz files are produced, the + naming convention is \cs{jobname-1.pdf}, \cs{jobname-2.pdf}, and so + on. When only a single quiz file is created, it is named + \cs{jobname.pdf}. + \item For class methods, the quizzes are named as + \cs{jobname-\ameta{first\SUB1}\_\ameta{last\SUB1}.pdf}, + \cs{jobname-\ameta{first\SUB2}\_\ameta{last\SUB2}.pdf}, and so on. +\end{itemize} +Class methods have three options \opt{useclass}, \opt{usebatch}, and \opt{batchdistr}. +It is the \opt{useclass} that distinguishes basic and class methods. + +%\subsection{Basic Methods} +\newtopic\noindent +The following are the scenarios for basic methods: +\begin{itemize} + \item None of the \textbf{\nameref{para:OCs}} listed on + page~\pageref{para:OCs} are specified in the preamble. A single quiz + is produced \emph{for each rendition} in the source file. By default flattening is off, so + returned quizzes can be run through \textsf{Thor's way} action + sequence. The source file can be compiled with \cs{flattenOff}, in + which case manual recording of the grades is needed. + \begin{itemize} + \item Files are created in the source file folder. + \item It is up to the instructor to deliver these quizzes to the + class. + \item You can place security on the files using the \textsf{Thor protects} action sequence. + \end{itemize} + \item \cs{enumQuizzes\darg{\ameta{num}}}: \ameta{num} copies of the file + is created (with rendition variations if they exist). All files are + dropped into the source file folder. Returned files can be run + through \textsf{Thor's way} to record results, unless \cs{flattenOff} + is specified in the preamble. + \begin{itemize} + \item Analogous to the \opt{usebatch} option. + \item Files are created in the source file folder. + \item It is up to the instructor to deliver these quizzes to the + class. + \item You can place security on the files using the \textsf{Thor + protects} action sequence. Quizzes are delivered manually. When + the returned quizzes are to be marked, use \textsf{Thor removes + protection} followed by the instructor markup step, followed by + \textsf{Thor's way} to record the quizzes. This roughly models + \textsf{batchdistr}, but without the distribution part. + \end{itemize} + \item \cs{enumQuizzes\darg{\ameta{num}}} and + \cs{instrPath\darg{\ameta{path}}} are specified: \ameta{num} copies of the file + is created (with rendition variations if they exist). Returned files can be run + through \textsf{Thor's way} to record results, unless \cs{flattenOff} + is specified in the preamble. + \begin{itemize} + \item Analogous to the \opt{usebatch} option. + \item All files are dropped into the folder determined by + \cs{instrPath}. + \item It is up to the instructor to deliver these quizzes to the + class. + \item You can place security on the files using the \textsf{Thor protects} action sequence. + \end{itemize} + + \item \cs{instrPath\darg{\ameta{path}}}, + \cs{classPath\darg{\ameta{path}}}, and + \cs{distrQuizzes\darg{\ameta{args}}}: \ameta{num} copies of the file + is created (with rendition variations if they exist), where + \ameta{num} is the number of folders listed in the argument of + \cs{distrQuizzes}. Returned files can be run through \textsf{Thor's + way} to record results, unless \cs{flattenOff} is specified in the + preamble. + \begin{itemize} + \item This combination of command best model the \opt{usebatch} option. + \item A copy of all quizzes are dropped into the folder determined by + \cs{instrPath}. + \item A copy of all quizzes are dropped into the student folders determined by + \cs{classPath}/\cs{distrQuizzes}. + \item Specifying \cs{distrToStudentsOff} in the preamble, you can + the place security on the files using the \textsf{Thor protects + and distributes} action sequence, which places the security on + the quizzes and distributes them to the student folders. This + would model the \opt{batchdistr} + \end{itemize} + + \item \cs{classPath\darg{\ameta{path}}}, and + \cs{distrQuizzes\darg{\ameta{args}}}: Same as the previous bullet point above. + \begin{itemize} + \item This combination of command best model the \opt{usebatch} option. + \item A copy of all quizzes are dropped into the source folder, + since no \cs{instrPath} is specified. + \item A copy of all quizzes are dropped into the student folders determined by + \cs{classPath}/\cs{distrQuizzes}. + \item Specifying \cs{distrToStudentsOff} in the preamble, you can + the place security on the files using the \textsf{Thor protects + and distributes} action sequence, which places the security on + the quizzes and distributes them to the student folders. This + would model the \opt{batchdistr}. + \end{itemize} + + +\end{itemize} + + +\section{A final note on Thor's workflow} + +There are two computer drives involved in this workflow: (1) a drive on the +instructor's work computer designated as ID (instructor's drive); and (2) a +system drive that students have access to, designated as SD (system drive). +\begin{enumerate} +\item (ID) The development of the quiz occurs on ID, {\heshe} builds the + quizzes (perhaps individualized to the names of the students) and saves + them to the student folders on ID, copies are dumped into the + instructor's folder on ID. +\item (ID $\mapsto$ SD) The system scripts copy the student folders on ID to + SD, preserving folder structure. +\item (SD) The class takes the quiz during the quiz period. +\item (SD $\mapsto$ ID) After the quiz period, system scripts copy the + completed quizzes from the SD student folders to the ID student + folders, and deletes the quizzes from SD. +\item (ID) The instructor grades each quiz, awarding points for the + extended response questions. Graded quizzes are flattened and marked + with a suffix `-g'. +\item (ID $\mapsto$ SD) The system scripts returns the graded quizzes to + the student folders on SD, where are met with great rejoicing or + gnashing of teeth. +\end{enumerate} + +\section{The \tops{\protect\opt{ordinary}}{ordinary} option}\label{ordinary} + +This option was prompted by an \pkg{exerquiz} user who had a unique problem: +He wanted to put password protection on the \uif{Correct} button of an +\pkg{exerquiz} quiz. He wanted to distribute quizzes to his students. The +students would take the quiz, and, on pressing the \uif{End Quiz} button, +would get their score, but the \uif{Correct} button would be denied to them +through a password mechanism. + +Solving this problem necessitated some of the special features of +\pkg{thorshammer}, without the use of \cs{sadQuizzes}. + +To see the solution to this problem, go to the +\texttt{examples/orginary-option} folder. There are three files in that +folder: +\begin{itemize} + \item {\ttfamily quiz-pwd-to-correct-AA.tex}: This file requires the use + of \app{Acrobat} to create the quizzes. The password is dynamically + encoded as the PDF is loaded into \app{Acrobat} for the first time. + \item {\ttfamily quiz-pwd-to-correct-AR.tex}: Again, the \uif{Correct} + button is password protected, only \app{Adobe Reader} is required + to build this file; however, the encrypted password cannot be built + dynamically. It must be first computed and hard-wired placed in the + source document. + \item {\ttfamily get-hash-string.tex}: This is a companion file to the + `AR' version described above. Build this file using any method. + Open it in \app{Adobe Reader} and press the \uif{Push} button. A + response dialog box opens, enter your chosen password (PIN number) + and press \uif{OK}. The hash string of your password appears on the + text field. Copy the password (or PIN) and the hash string to + {\ttfamily quiz-pwd-to-correct\allowbreak-AR.tex}. Comment out the human readable + password in your file and paste the hash string into the value of + the \texttt{\_PinCode} JavaScript variable, then build the file + {\ttfamily quiz-pwd-to\allowbreak-correct-AR.tex}. Now, the \uif{Correct} + button is password (PIN) protected. + +\end{itemize} + +\section{My retirement} + +Now, I simply must get back to it. \dps + +\end{document} + +The only user command is \cs{xbmksetup}: +\bVerb\def\1{\qquad}\takeMeasure{\1docbundle=\darg{\ameta{doc\SUB1},\ameta{doc\SUB2},...,\ameta{doc\SUB{n}}},}% +\begin{dCmd}[commandchars=!()]{\bxSize} +\xbmksetup{% +!1docbundle={!ameta(doc!SUB1),!ameta(doc!SUB2),...,!ameta(doc!SUB(n))}, +!1colors={int=!ameta(color),ext=!ameta(color)}, +!1styles={intbf,extbf,intit,extit} +} +\end{dCmd} +\eVerb + +% This code saves a copy of the PDF with the name of each member of the class +% appended. If you have a network drive, you can copy each PDF to their respective +% folders in the connected drive. Here, drive Z: is connected to my PC, drive Z: is +% actually, the C: drive on my other laptop, which is connected to my PC. +% See if this works for you. +% diff --git a/texmf-dist/doc/latex/thorshammer/thorshammer.pdf b/texmf-dist/doc/latex/thorshammer/thorshammer.pdf new file mode 100644 index 00000000..6e6c6fba Binary files /dev/null and b/texmf-dist/doc/latex/thorshammer/thorshammer.pdf differ diff --git a/texmf-dist/source/latex/thorshammer/thorshammer.dtx b/texmf-dist/source/latex/thorshammer/thorshammer.dtx new file mode 100644 index 00000000..b50d035d --- /dev/null +++ b/texmf-dist/source/latex/thorshammer/thorshammer.dtx @@ -0,0 +1,2398 @@ +% \iffalse +% makeindex -s gglo.ist -o thorshammer.gls thorshammer.glo +% makeindex -s gind.ist -o thorshammer.ind thorshammer.idx +%<*copyright> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% thorshammer.sty package, %% +%% Copyright (C) 2020 D. P. Story %% +%% dpstory@uakron.edu dpstory@acrotex.net %% +%% %% +%% 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. %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +%\NeedsTeXFormat{LaTeX2e} +%\ProvidesPackage{thorshammer} +% [2020/01/13 v1.5.7 Support commands for Thor's way] +%<*driver> +\documentclass{ltxdoc} +\usepackage[colorlinks,hyperindex=false,linktocpage,bookmarksnumbered]{hyperref} +\usepackage{calc} +%\def\texorpdfstring#1#2{#1} +%\pdfstringdefDisableCommands{\let\\\textbackslash} +\OnlyDescription % comment out for implementation details +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\gdef\brpr#1{\texttt{\char123\relax#1\char125\relax}} +\let\darg\brpr +\let\env\texttt +\let\opt\texttt +\let\app\textsf +\let\pkg\textsf +\let\tops\texorpdfstring +\def\EXCL{!} +\def\nmpsep#1{\hskip-\marginparsep\texttt{#1}} +\def\visispace{\symbol{32}} +\def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}} +\def\meta#1{\textsl{\texttt{#1}}} +\def\SUB#1{\ensuremath{{}_{\mbox{\scriptsize\ttfamily#1}}}} +\def\CMD#1{\textbackslash#1} +\InputIfFileExists{aebdocfmt.def}{\PackageWarning{thorshammer}{Inputting aebdocfmt.def}} + {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax + \PackageInfo{thorshammer}{aebdocfmt.def cannot be found}} +\begin{document} +\addtolength{\marginparwidth}{3pt} + \GetFileInfo{thorshammer.sty} + \title{The \textsf{thorshammer} Package} + \author{D. P. Story\footnote{The author acknowledges Thorsten G. (a.k.a., Thor) who proposed this workflow and +who contributed many ideas; J\"{u}rgen G. (a.k.a., Loki) also contributed many good ideas, enthusiasm, +questions, bug detecting, and motivation. High regards and respect to both. D. P. Story (a.k.a., Odon).}\\ + Email: \texttt{dpstory@acrotex.net}} + \date{processed \today} + \maketitle +\setcounter{secnumdepth}{5} +\setcounter{tocdepth}{5} +\bgroup +\value{secnumdepth}=3 +\value{tocdepth}=3 + \tableofcontents +\egroup + \DocInput{thorshammer.dtx} +\IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex}{\paragraph*{Index} The index goes here. Execute + \begin{quote}\texttt{makeindex -s gind.ist -o thorshammer.ind thorshammer.idx}\end{quote} + on the command line and recompile + \texttt{thorshammer.dtx}.} +\IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here. Execute + \begin{quote} + \texttt{makeindex -s gglo.ist -o thorshammer.gls thorshammer.glo} + \end{quote} + on the command line and recompile \texttt{thorshammer.dtx}.} +\end{document} +% +% \fi +% \MakeShortVerb{|} +% \InputIfFileExists{aebdonotindex.def}{\PackageInfo{web}{Inputting aebdonotindex.def}} +% {\PackageInfo{web}{cannot find aebdonotindex.def}} +% \begin{macrocode} +%<*package> +% \end{macrocode} +% \section{Introduction} +% Thorsten G.\ has asked me to assist him in creating a quiz system, based on Acro\negthinspace\TeX, +% to be delivered to his classes. His workflow for this assessment system is a follows:\footnote{As my occassional +% friend J\"{u}rgen says, this workflow is a real \emph{hammer}, so I titled this package `Thors(ten) hammer', or simply +% \pkg{thorshammer}.} +% \begin{enumerate} +% \item The \env{quiz} environment is used to pose the questions, which consist of MC, numerical fill-in +% the blank, and extended response questions. +% \item[] Though the \env{quiz} environment is used, the student does not get his/her score reported +% back immediately upon finishing the quiz. +% \item When the student finishes the exam, taken in AR, he/she presses +% the \textsf{End Quiz} control and saves the document as \texttt{\string\jobname-ID.pdf}, where \texttt{ID} +% is a student identification. I am informed the ID is the student name. +% \item At some point, the instructor's script moves the document to the instructors folder. +% \item The instructor opens the PDF and finishes marking the extended response questions and assigns a grade. +% \end{enumerate} +% This package supports the Thorsten's workflow by providing the necessary form elements and JavaScript +% to carry out his(her) plan. What happens to the quiz after that, I do not know. +% +%\changes{v1.4}{2019/08/11}{Begin major change to this package, leaving v1.3.8 as our best working +% version prior to this update. } +% +% \section{Preliminaries} +% +% \begin{macrocode} +\RequirePackage{xkeyval} +\edef\th@dquoteCat{\the\catcode`\"} +\catcode`\"=12\relax +% \end{macrocode} +% \subsection{Options for this package} +% +% \leavevmode\IndexOpt{nocfg} If this option is taken, \texttt{thorshammer.cfg} is not input. +% \begin{macrocode} +\DeclareOptionX{nocfg}{\let\th@loadCFG\dl@NO} +\let\th@loadCFG\dl@YES +% \end{macrocode} +% \leavevmode\IndexOpt{testmode} If this option is taken, quizzes can be used in the normal way. +% \begin{macrocode} +\newif\ifthtestmode\thtestmodefalse +\DeclareOptionX{testmode}{\thtestmodetrue} +\DeclareOptionX{!testmode}{\thtestmodefalse} +% \end{macrocode} +% \leavevmode\IndexOpt{ordinary} This is an experimental option to see if we can produce +% a regular quiz with selected features of a \pkg{thorshammer} workflow. +% \begin{macrocode} +\newif\ifthordinary \thordinaryfalse +\DeclareOptionX{ordinary}{\thtestmodetrue\thordinarytrue} +% \end{macrocode} +% \leavevmode\IndexOpt{useclass}Use this option to bring in addition code to declare each member of +% the class, to automatically build a quiz for each class member, to distribute these +% quizzes to a designated folder of the instructor, and to distribute the quizzes the +% respective class folder. +% \begin{macrocode} +\newif\ifbasicmethods\basicmethodstrue +\newif\ifuseclassOpt\useclassOptfalse +\def\bUseClass{false} +\DeclareOptionX{useclass}{\useclassOpttrue + \def\bUseClass{true}\basicmethodsfalse +} +% \end{macrocode} +% \leavevmode\IndexOpt{usebatch}This option should be used with the \opt{useclass} option. +% When this option is taken, the no freeze quiz button is created. The batch sequence +% \textsf{Thor's way} does that, and the presence of the freeze button, the instructor +% may press it without thinking. We don't want that to happen. +% \begin{macrocode} +\newif\ifth@allowfreeze \th@allowfreezetrue +\DeclareOptionX{usebatch}{\th@allowfreezefalse + \ExecuteOptionsX{useclass}} +% \end{macrocode} +% \leavevmode\IndexOpt{batchdistr} This option declares the instructor's intention +% of using \app{Acrobat} to apply security using `\textsf{Thor distributes.sequ}' or `\textsf{Thor protects and distributes.sequ}' +% to apply security and to distribute the files to the students's folders. This option simply +% expands \cs{distrToStudentsOff}, and redefines the two commands so the author can't use them. This option +% has no effect on writing quizzes to the instructor's folder. +% \begin{macrocode} +\DeclareOptionX{batchdistr}{\ExecuteOptionsX{usebatch}% + \AtEndOfPackage{\distrToStudentsOff + \let\distrToStudentsOff\relax\let\distrToStudentsOff\relax}} +% \end{macrocode} +% Process the options +% \begin{macrocode} +\ProcessOptionsX +\edef\thOrdQz{\ifthordinary true\else false\fi} +% \end{macrocode} +% \subsection{Required packages} +% \begin{macrocode} +\RequirePackage{insdljs}[2019/08/06] +% \end{macrocode} +% We use the \opt{usealtadobe} option of \pkg{insdljs}, but not directly. If \cs{inputAltAdbFncs} +% is \cs{relax} than the functions have not already been input above \pkg{thorshammer}. +% \changes{v1.3.5}{2019/08/06}{Use \string\cs{usedAdbFuncs} to detect \string\opt{usealtadobe} option} +% \begin{macrocode} +\ifx\usedAdbFuncs\dl@NO + \def\inputAltAdbFncs{\InputIfFileExists{altadbfncs.def}% + {\PackageInfo{insdljs}{Inputting code for usealtadobe option}}% + {\PackageWarning{insdljs}{Cannot find altadbfncs.def.\MessageBreak + Reinstall or refresh your file name database.}}}% + \let\usedAdbFuncs\dl@YES +\else + \let\inputAltAdbFncs\relax +\fi +\inputAltAdbFncs +\RequirePackage{exerquiz}[2019/08/13] +\RequirePackage{eq-save}[2019/08/07] +\let\execjs\dl@YES +\@ifundefined{CommentStream}{\newwrite\CommentStream}{} +\def\csarg#1#2{\expandafter#1\csname#2\endcsname} +\providecommand{\eqSP}{\string\040} +\def\thPageOne{\setcounter{page}{1}} +% \end{macrocode} +% \section{Setting the initial view} +% We require the document to be opened on the first page, but the initial magnification +% is under the control of the document author.\medskip\par +% \noindent +% \DescribeMacro\setInitMag\nmpsep{\darg{fitpage\string|actualsize\string|fitwidth\string|fitheight\string|fitvisible\string|inheritzoom}}\\ +% This command determines the initial magnification. There are a choice of six values for the argument; the default is \texttt{fitpage} +% \begin{macrocode} +\def\setInitMag#1{\setkeys{thim}{mag=#1}} +\define@choicekey+{thim}{mag}[\val\nr]% + {fitpage,actualsize,fitwidth,fitheight,% + fitvisible,inheritzoom}[fitpage]% + {\edef\th@initmag{\@nameuse{dl@\val}}} + {\PackageWarning{thorshammer}{% + Bad choice for initial magnification,\MessageBreak + permissible values are fitpage, actualsize,\MessageBreak + fitwidth, fitheight, fitvisible, and\MessageBreak + inheritzoom. Try again}} +\def\th@initmag{\dl@fitpage} +% \end{macrocode} +% The \cs{addToDocOpen} is a command from \pkg{insdljs}. We turn off calculations as the student +% does not need to see the calculation icon each time s/he enters a response. When the instructor +% presses the \textsf{Mark It} button, calculations are turned on again. In the second line +% below, we set the initial view to page~1 and the magnification set by the \cs{setInitMag} command above. +% \begin{macrocode} +\addToDocOpen{\JS{% + var stmot=app.setTimeOut("this.calculate=false;",100);}} +\addToDocOpen{\GoToD[\Page{1}\th@initmag]} +% \end{macrocode} +% \section{Declaring instructor and class information} +% +% \DescribeMacro\instrPath\nmpsep{*\darg{\ameta{path}}} The path to the +% instructor's folder. It is assumed that this \ameta{path} is an +% absolute path. If the star option is taken, then the path is relative +% to the current folder. The \DescribeMacro\instrPathIsCHTTP\cmd{\instrPathIsCHTTP} +% declaration is available if the path to the instructor is a WebDAV address. This +% info is passed on the a JavaScript method. +% \begin{macrocode} +\def\instrPathIsCHTTP{\def\thInstrFS{CHTTP}} +\let\thInstrFS\@empty +\newcommand\instrPath{\@ifstar + {\gdef\InstrPathFull{false}\instrPath@i} + {\gdef\InstrPathFull{true}\instrPath@i}} +\def\instrPath@i#1{\gdef\InstrPath{"#1"}} +\def\InstrPathFull{true} +%\let\InstrPath\@empty +\def\InstrPath{this.path.replace(reRmFn,"")} +% \end{macrocode} +% \DescribeMacro\classPath\nmpsep{*\darg{\ameta{path}}} The path to the class folder. +% It is assumed that this \ameta{path} is an absolute path. If +% the star option is taken, then the path is relative to the current folder. +% The \DescribeMacro\classPathIsCHTTP\cmd{\instrPathIsCHTTP} +% declaration is available if the path to the class folders is a WebDAV address. This +% info is passed on the a JavaScript method. +% \begin{macrocode} +\def\classPathIsCHTTP{\def\thClassFS{CHTTP}} +\let\thClassFS\@empty +\newcommand\classPath{\@ifstar + {\gdef\ClassPathFull{false}\classPath@i} + {\gdef\ClassPathFull{true}\classPath@i}} +\def\classPath@i#1{\gdef\ClassPath{"#1"}} +\def\ClassPath{this.path.replace(reRmFn,"")} +\def\ClassPathFull{true} +% \end{macrocode} +% +% \section{Running headers} +% The scheme used here assumes no other {\LaTeX} package has been used to take over the running +% headers (and footers). If that is the case, use the values of the commands below to design +% your own. +% \DescribeMacro\thQzHeaderL\nmpsep{\darg{\ameta{text}}} This is inserted into the left running header +% for the quiz pages. +% \begin{macrocode} +\def\thQzHeaderL#1{\def\th@QzHeaderLQ{\makebox[0pt][l]{#1}}} +\def\th@QzHeaderL{\th@QzHeaderLQ} +\thQzHeaderL{Thor's Class} +\def\th@QzHeaderLS{\th@HeaderOffset\th@QzHeaderLQ} +% \end{macrocode} +% \DescribeMacro\thQzHeaderCQ\nmpsep{\darg{\ameta{text}}} This is inserted into the center running header +% for the \emph{quiz} pages. +% \begin{macrocode} +\def\thQzHeaderCQ#1{\def\th@QzHeaderCQ{\makebox[0pt][c]{#1}}} +\thQzHeaderCQ{Quiz \thQuizName} +\def\th@QzHeaderC{\th@QzHeaderCQ} +% \end{macrocode} +% \DescribeMacro\thQzHeaderCS\nmpsep{\darg{\ameta{text}}} This is inserted into the center running header +% for the \emph{solution} pages. +% \begin{macrocode} +\def\thQzHeaderCS#1{\def\th@QzHeaderCS{\makebox[0pt][c]{#1}}} +\thQzHeaderCS{Solutions: \thQuizName} +% \end{macrocode} +% \DescribeMacro\thQzHeaderR\nmpsep{\darg{\ameta{text}}} This is inserted into the right running header +% for the solution pages. +% \begin{macrocode} +\def\thQzHeaderR#1{\def\t@hQzHeaderR{\makebox[0pt][r]{#1}}} +\thQzHeaderR{\thepage} +% \end{macrocode} +% We apply the running headings, depending on whether \pkg{web} loaded by testing for the +% \texttt{webheadings} page style. +% \begin{macrocode} +\@ifundefined{ps@webheadings}{% + \def\th@setHeaders{% + \renewcommand{\@oddhead}{\th@QzHeaderL\hfil\th@QzHeaderC\hfil + \t@hQzHeaderR}\renewcommand{\@evenhead}{\@oddhead}}% +}{% + \def\th@setHeaders{% + \lheader{\th@QzHeaderL}% + \cheader{\th@QzHeaderC}% + \rheader{\t@hQzHeaderR}}% +} +% \end{macrocode} +% Change the header for the solution section +% \begin{macrocode} +\def\eq@normallheader{% + \@ifundefined{ps@webheadings}{% + \def\th@QzHeaderL{\th@QzHeaderLS}% + \def\th@QzHeaderC{\th@QzHeaderCS}% + }{% + \lheader{\th@QzHeaderLS}% + \cheader{\th@QzHeaderCS}% + } +} +% \end{macrocode} +% \DescribeMacro\rhPgNumsOnly Originally, this package only exhibited page numbers +% in the running header, expanding \cs{rhPgNumsOnly} in the preamble restores that +% original experience. +% \begin{macrocode} +\def\rhPgNumsOnly{\thQzHeaderL{}\thQzHeaderCQ{}\thQzHeaderCS{}} +\AtBeginDocument{\th@setHeaders} +% \end{macrocode} +% \section{Declaring a cover page} +% \DescribeMacro\DeclareCoverPage\nmpsep{\darg{\ameta{pgNum}}} +% A cover page, if declared, is appended to the beginning of the quiz. The page +% specified by \ameta{pgNum} is the cover page. The cover page is a single page +% and must occur prior to any quiz. Valid in the \emph{preamble only}. +% \changes{v1.4.1}{2019/08/16}{Implement the concept of a cover page.} +% \begin{macrocode} +\newif\ifthCoverPage \thCoverPagefalse +\newcommand{\DeclareCoverPage}[1]{\thCoverPagetrue + \def\thIsCP{true}\def\thCvrPg{#1}} +\def\thIsCP{false}\def\thCvrPg{0} +\@onlypreamble\DeclareCoverPage +% \end{macrocode} +% \section{Basic methods} +% +% Thor is tormenting me with the basic methods option. The basic methods option is +% no options other than perhaps \opt{nocfgs}. As a consequence, the student names are +% not pre-filled into the name fields. When multiple quizzes are produced, they are named +% differently, \cs{jobname-1.pdf}, \cs{jobname-2.pdf}, and so on. A lot of work has gone +% in to the basic methods so it works link the non-basic methods (option \opt{useclass} or higher). +% The commands \cs{instrPath} and \cs{classPath} are supported; to use the \cs{classMember} +% command, use \opt{useclass} or higher. In addition to \cs{instrPath} and \cs{classPath}, we +% define special basic method commands, as describe in the next section. +% +% \subsection{Configuring the basic methods experience} +% +% \DescribeMacro\useNameToCustomize\nmpsep{ \normalfont(Basic methods)} +% \cs{useNameToCustomize} +% can be used to modify the file name of the quiz to include student name; the default is to +% use the original quiz file name. This command is implemented through the \textsf{Freeze Quiz} button. +% This command has no effect in the non-basic setting. +% \changes{v1.3.6}{2019/08/07}{freezeQuizMU: Cannot freeze unless grade given and added suffix +% \string\texttt{"-g"} to document name on saving.} +% \changes{v1.4.8}{2019/09/05}{Added \string\cs{useNameToCustomize}} +% \begin{macrocode} +\def\useNameToCustomize{\def\thUseNameToCustomize{true}} +\def\thUseNameToCustomize{false} +% \end{macrocode} +% \DescribeMacro\enumQuizzes\nmpsep{\darg{\ameta{num}}} (Basic methods) This file specifies that +% the quizzes should be replicated \ameta{num} times and named \cs{jobname-1}, +% \cs{jobname-2}, ..., \cs{jobname-\ameta{num}}. The default is not to enumerate. +% \changes{v1.4.8}{2019/09/05}{Added \string\cs{enumQuizzes}} +% \begin{macrocode} +\def\enumQuizzes#1{\def\bUseClass{true}\basicmethodsfalse + \ClassEntriestrue\def\ClassPathFull{true}\def\InstrPathFull{true}% + \def\ClassPath{this.path.replace(reRmFn,"")}% + \def\InstrPath{this.path.replace(reRmFn,"")}% + \bgroup\@tempcnta#1\relax + \@whilenum\@tempcnta>\z@\do{\classMember{}{}{}% + \advance\@tempcnta\m@ne}\egroup + \def\thEnumQuizzes{#1}\def\bEnumQuizzes{true}} +\def\thEnumQuizzes{0}\def\bEnumQuizzes{false} +% \end{macrocode} +% \DescribeMacro\distrQuizzes\nmpsep{\darg{\darg{\ameta{folder\SUB1}}\darg{\ameta{folder\SUB2}}...\darg{\ameta{folder\SUB{n}}}}} +% (Basic methods) If \cs{distrQuizzes} is used, \cs{enumQuizzes} command is ignored. The quizzes are enumerated, +% as described above, but the number of quizzes created is the number of folders declared. The script +% |\sadQuizzes| also distributes the individual quizzes to the appropriate folder, on the path +% determined by the |\classPath| command. +% \changes{v1.4.8}{2019/09/05}{Added \string\cs{distrQuizzes}} +% \changes{v1.5.4}{2019/11/30}{Reworked \string\cs{distrQuizzes} to account for +% second star option of \string\cs{classMember}} +% \begin{macrocode} +\newcommand{\distrQuizzes}{% + \ifuseclassOpt + \def\th@next{\PackageWarning{thorshammer} + {Use have specified the useclass option or higher\MessageBreak + yet you employ \string\distrQuizzes, these are\MessageBreak + incompatible. Assuming the specified package option}}% + \else + \let\th@next\th@distrQuizzes + \fi\th@next +} +\def\th@distrQuizzes{\def\bUseClass{true}\basicmethodsfalse + \ClassEntriestrue\bgroup\@makeother\_\th@distrQuizzes@i} +\def\rmSTAR#1*\@nil{\def\@folder{#1}} +%\def\tstForSTAR#1{\tstForSTAR@i#1**\@nil} +\def\tstForSTAR#1*#2*\@nil{\def\@rgi{#1}\ifx\@rgi\@empty + \def\ISSTAR{*}\rmSTAR#2\@nil\else\let\ISSTAR\@empty\fi}% +\def\th@distrQuizzes@i#1{\@tempcnta\z@ + \@tfor\@folder:=#1\do{\advance\@tempcnta\@ne +% \end{macrocode} +% Determine if \cs{@folder} begin with \texttt*, remove it and return +% the path as \cs{@folder} +% \begin{macrocode} + \expandafter\tstForSTAR\@folder**\@nil + \edef\x{\noexpand\classMember{}{}\ISSTAR{\@folder}}\x + }\xdef\enumQuizzes{\the\@tempcnta}% + \gdef\bDistrQuizzes{true}\egroup +} +\def\bDistrQuizzes{false} +% \end{macrocode} +% +% \paragraph*{Just auto-save the document - not recommended} +% The \cs{executeSave()} command previously figured in importantly, +% as this package developed, use of \cs{executeSave()} cannot be +% recommended. This command was implemented early in the development process +% \begin{macrocode} +\@ifundefined{executeSave} + {\def\executeSave(){% + console.println("automatically saving this file...");^^J% + var retn=aebTrustedFunctions(this,aebDocSaveAs,% + {cPath:this.path,bCopy:false})}}{} +% \end{macrocode} +% The \DescribeEnv{docassembly}\env{docassembly} environment was created early +% in development and was meant to be used with \cs{executSave()}. The environment +% definition was updated to be equivalent to the \env{makeClassFiles} environment. +% An environment by the same name, and the same functionality, is defined in \pkg{aeb\_pro}. +% \changes{v1.4.14}{2019/09/13}{Inserted \string\cs{mkClFlsSpcls} as optional +% argument of \string\env{docassembly}} +% \begin{macrocode} +\@ifundefined{docassembly} + {\newenvironment{docassembly}{% + \execJS[\mkClFlsSpcls]{docassembly}}{\endexecJS}} + {\renewenvironment{docassembly}{% + \execJS[\mkClFlsSpcls]{docassembly}}{\endexecJS}} +% \end{macrocode} +% +% \subsection{Post creation document assembly} +% The \DescribeMacro\rasSolns\cmd\sadQuizzes{} command is placed within the +% \env{docassembly} or \env{makeClassFiles} environment, +% \cs{sadQuizzes} in the body of the environment. +%\begin{verbatim} +%\begin{docassembly} +%\sadQuizzes +%\end{docassembly} +%\begin{document} +%\end{verbatim} +%Originally, we defined a command \cs{rasSolns}, this command has been \cs{let} to +%\cs{sadQuizzes}, which now performs its duties. +% \begin{macrocode} +% \end{macrocode} +% +% \section{Form field commands} +% +% We define two types of controls: (1) those placed outside the quiz; (2) those placed within the quiz. +% +% \subsection{Controls above the \tops{\protect\env{quiz}}{quiz} environment} +% +% \paragraph*{Commands that occur above the \tops{\protect\env{quiz}}{quiz} environment}\leavevmode\par\medskip\noindent +% The student needs to sign in with his/her first and last name. The commands +% \DescribeMacro\FirstName\cmd\FirstName{} and \DescribeMacro\LastName\cmd\LastName{} are +% defined for that purpose. +% \begin{macrocode} +\ifbasicmethods\let\th@namePresets\@empty\else +% \end{macrocode} +% If the option \opt{useclass}, or higher, is taken, we make these fields read only and the +% JavaScript code of \cs{sadQuizzes} will fill name field in for the student. +% \begin{macrocode} +\def\th@namePresets{\Ff\FfReadOnly\BC{}}\fi +\newcommand\FirstName[3][]{\th@bMrkQz\textField[% + \presets{\th@namePresets}#1]{Name.first}{#2}{#3}} +\newcommand\LastName[3][]{\textField[% + \presets{\th@namePresets}#1]{Name.last}{#2}{#3}} +% \end{macrocode} +% The \cs{sadQuizzes} command uses the name fields to identify on which page a quiz begins. This worries +% me a little if a document designer places more than one name field for a quiz. We attempt to make +% the first use of the name field per quiz. We define \cs{th@bMrkQz}. These fields are place exactly once +% for each quiz and is attached to the name fields. +% \changes{v1.4.7}{2019/08/27}{Added marker field attached to name field} +% \begin{macrocode} +\def\th@bMrkQz{\@ifundefined{bMrkQz\currQuiz} + {\rlap{\textField[\Ff\FfReadOnly\BC{}\BG{}]{bMrkQz}{0pt}{0pt}}% + \@namedef{bMrkQz\currQuiz}{}}{}} +% \end{macrocode} +% \DescribeMacro{\FullName}\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} The first and +% last name fields are required; however, when \opt{useclass} or higher is used, they are automatically +% filled in. The \cs{FullName} field uses the calculate event to extract the first and last names +% and displays them together in one field. The format for the this name field can be changed +% through the declaration \DescribeMacro\thfullnameFmt\cmd{\thfullnameFmt}. +% \begin{macrocode} +\def\th@fullnamePresets{\Ff\FfReadOnly\BG{}\BC{}} +\def\thfullnameFmt#1{\def\th@fullnameFmt##1##2{#1}} +\thfullnameFmt{#1+" "+#2} +\newcommand{\FullName}[3][]{\textField[% + \presets{\th@fullnamePresets}#1\AAcalculate{% + var fName=this.getField("Name.first").value;\r + var lName=this.getField("Name.last").value;\r + event.value=\th@fullnameFmt{fName}{lName};}]{FullName}{#2}{#3}} +% \end{macrocode} +% \leavevmode\DescribeMacro\pwdInstrFld\nmpsep{[\ameta{options}]\darg{\ameta{pwd}}\darg{\ameta{wd}}\darg{\ameta{ht}}} +% In this workflow, when the instructor opens a quiz file, he/she enters a password. On success, the +% non-extended response questions of the student's quiz is marked, and various hidden form elements are +% made visible. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\pwdInstrFldTU\nmpsep{\darg{\ameta{pdfstr}}} +% can be redefined to provide a tool tip +% for this field. +% \begin{macrocode} +\def\pwdInstrFldTU#1{\def\pwdInstrFld@TU{#1}} +\pwdInstrFldTU{Enter password to mark this quiz} +% \end{macrocode} +% The definition of \cmd\pwdInstrFld +% \begin{macrocode} +\newcommand{\pwdInstrFld}[4][]{% opts, pwd, wd, ht + \@ifundefined{\currQuiz-nQs}{\def\nQs{0}} + {\edef\nQs{\@nameuse{\currQuiz-nQs}}}% + \textField[\cmd{\bParams{\currQuiz}{\nQs}{"#2"}\eParams} + \Ff\FfPassword\AAkeystroke{\pwdKeyJS} + \protect\AA\protect\Ff\TU{\pwdInstrFld@TU}#1% +]{pwdtxt}{#3}{#4}} +% \end{macrocode} +% \DescribeMacro\markQz\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} Loki +% suggested another idea to have the password field hidden until the instructor opens the file. +% Well if you are doing that, why have a password field? Instead, a push button is provided. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\markQzFldCA\nmpsep{\ameta{jsstr}} The caption for this button +% \begin{macrocode} +\def\markQzFldCA#1{\def\markQzFld@CA{#1}} +\markQzFldCA{Mark It} +% \end{macrocode} +% \DescribeMacro\markQzFldTU\nmpsep{\ameta{jsstr}} The tool tip for this button +% \begin{macrocode} +\def\markQzFldTU#1{\def\markQzFld@TU{#1}} +\markQzFldTU{Press to mark this quiz} +% \end{macrocode} +% The code for \cmd\markQz. \textbf{Important!}\marginpar{\raggedleft\textbf{Important!}} For obvious +% reasons, we don't want the push button to be seen by the students. As a result, it is initially hidden. +% The key to having the push button visible when the instructor is the private JavaScript variable +% \texttt{\_thorshammer}\marginpar{\raggedleft\texttt{\_thorshammer}} (this can be changed). The following +% code is placed in the \texttt{config.js}\marginpar{\raggedleft\texttt{config.js}} file of the instructor's \app{Acrobat} installation: +% \begin{quote}\ttfamily +% var \_thorshammer=true; +% \end{quote} +% \app{Acrobat} reads this file only once when it's opened. +% When the instructor opens the student's quiz PDF in \app{Acrobat}\marginpar{\raggedleft\app{Acrobat}}, +% some underlying JavaScript code tests whether the \texttt{\_thorshammer} variable is defined and is +% \texttt{true}. If these conditions are met, JavaScript makes the \cs{markQuizFld} and +% \cs{freezeQz} fields visible. +% \begin{macrocode} +\newcommand{\markQz}[3][]{% + \@ifundefined{\currQuiz-nQs}{\def\nQs{0}}% + {\edef\nQs{\@nameuse{\currQuiz-nQs}}}% +% \end{macrocode} +% This text field is placed underneath the push button. It is the one that +% causes the \cs{markQz} field to be visible. +% \begin{macrocode} + \makebox[0pt][l]{\textField[\BC{}\BG{}\H{S}\AAformat{% + var f=this.getField("MarkIt");\r + var g=this.getField("freezeQz");\r + if(typeof _thorshammer!="undefined" && _thorshammer){\r\t + if(f!=null)f.display=display.visible;\r\t +} else{\r\t + if(f!=null)f.display=display.hidden;\r\t + if(g!=null)g.display=display.hidden;\r +}}]{hideTxtFldMI}{0pt}{0pt}}% +% \end{macrocode} +% The push button seen by the instructor to mark the quiz. +% \begin{macrocode} + \pushButton[\cmd{\bParams{\currQuiz}{\nQs}\eParams}\F\FHidden + \AAmouseup{\commonPassKey}\CA{\markQzFld@CA} + \TU{\markQzFld@TU}\protect\AA\protect\F#1% + ]{MarkIt}{#2}{#3}} +% \end{macrocode} +% \DescribeMacro\freezeQuiz\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% The \cs{freezeQuiz} makes all form fields readonly. After the instructor finishes marking +% the quiz, he/she presses the freeze quiz button before he moves it to the student's folder +% for review. This is done so the student cannot modify the quiz in any case and beg for more +% points. (They never beg for fewer points). The freeze quiz button makes itself hidden as well. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\freezeQuizFldTU\nmpsep{\darg{\ameta{pdfstr}}} +% can be redefined to provide a tool tip for this field. +% \begin{macrocode} +\def\freezeQuizFldTU#1{\def\freezeQuizFld@TU{#1}} +\freezeQuizFldTU{Make all fields readonly, cannot be undone} +% \end{macrocode} +% \DescribeMacro\freezeQuizFldCA\nmpsep{\darg{\ameta{pdfstr}}} +% can be redefined to provide a button caption for this field. +% \begin{macrocode} +\def\freezeQuizFldCA#1{\def\freezeQuizFld@CA{#1}} +\freezeQuizFldCA{Freeze Quiz} +% \end{macrocode} +% The definition of \cmd\freezeQuiz. If the \opt{usebatch} option is taken, +% we do not create the push button. +% \begin{macrocode} +\newcommand\freezeQuiz[3][]{\pushButton[\cmd{\let\%\defjsLB} + \CA{\freezeQuizFld@CA}\F\FHidden + \TU{\freezeQuizFld@TU}\AAmouseup{freezeQuizMU()} + \protect\AA\protect\F + #1]{freezeQz}{}{11bp}} +% \end{macrocode} +% \DescribeMacro\instrSave\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% A companion macro to \cs{freezeQuiz}. This macro is substituted for \cs{freezeQuiz} +% when the \opt{usebatch} option is taken. The \cs{instrSave} and \cs{freezeQuiz} +% should not appear in the same document; we give them the same field name +% so the JavaScript treats them them the same, in terms of making them hidden +% and visible. |\ifth@allowfreeze| +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\instrSaveFldTU\nmpsep{\darg{\ameta{pdfstr}}} +% can be redefined to provide a tool tip for this field. +% \begin{macrocode} +\def\instrSaveFldTU#1{\def\instrSaveFld@TU{#1}} +\instrSaveFldTU{Save and close this file to the current folder} +% \end{macrocode} +% \DescribeMacro\instrSaveFldCA\nmpsep{\darg{\ameta{pdfstr}}} +% can be redefined to provide a button caption for this field. +% \begin{macrocode} +\def\instrSaveFldCA#1{\def\instrSaveFld@CA{#1}} +\instrSaveFldCA{Save \string& Close} +% \end{macrocode} +% The definition of \cmd\instrSave. If the \opt{usebatch} option is taken, +% we do not create the push button. +% \begin{macrocode} +\newcommand\instrSave[3][]{\pushButton[% + \CA{\instrSaveFld@CA}\F\FHidden + \TU{\instrSaveFld@TU}\AAmouseup{% + var f=this.getField("studentenGrade");\r + var str=""+f.value;\r + str=str.replace(/\string\s/g,"");\r + if (str=="")\r\t + app.alert("You did not award the student a final mark." + +"\\n\\nAward the mark and then save.");\r + else {\r\t + aebTrustedFunctions(this,aebSaveAs);\r\t + this.closeDoc(true);\r + }}\protect\AA\protect\F + #1]{freezeQz}{}{11bp}} +% \end{macrocode} +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\freezeOrSave\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% is the recommended way of inserting \cs{freezeQuiz} or \cs{instrSave}. If \opt{usebatch} +% is taken, \c{freezeOrSave} expands to \cs{instrSave}; otherwise it expands to \cs{freezeQuiz}. +%\changes{v1.2}{2019/07/16}{Added \string\cs{freezeOrSave}} +% \begin{macrocode} +\AtEndOfPackage{\ifth@allowfreeze\let\freezeOrSave\freezeQuiz + \else\let\freezeOrSave\instrSave\fi} +% \end{macrocode} +% \DescribeMacro\studentReport\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} In Thor's +% way of things, a summary report is placed at the top of the document. This readonly field +% shows the number of points awarded and the total points. +% \changes{v1.1.8}{2019/07/08}{make studentenReport initially hidden} +% \begin{macrocode} +\newcommand{\studentReport}[3][]{% + \textField[\BC{}\BG{}\F\FHidden\Ff\FfReadOnly\protect\Ff#1% + ]{studentenReport}{#2}{#3}} +% \end{macrocode} +% \DescribeMacro\studentGrade\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% Again, in Thor's way of things, a text field is available to assign grade. This field +% is initially hidden, but becomes visible when instructor signs in. +% \begin{macrocode} +\newcommand{\studentGrade}[3][]{\textField[\F\FHidden\protect\F + \BC{red}\BG{}\Q1\textSize{12}\textColor{blue} + \AAkeystroke{event.change=event.change.toUpperCase()}#1% + ]{studentenGrade}{#2}{#3}} +% \end{macrocode} +% \DescribeMacro\thQHFirstName\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% The first name of the student +% \begin{macrocode} +\def\thQHFirstName#1{\def\th@QHFirstName{\textbf{#1}\space}} +\thQHFirstName{First name:} +% \end{macrocode} +% \DescribeMacro\thQHLastName\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% The last name of the student +% \begin{macrocode} +\def\thQHLastName#1{\def\th@QHLastName{\textbf{#1}\space}} +\thQHLastName{Last name:} +% \end{macrocode} +% \DescribeMacro\thQHPoints\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% Number of points, displayed in the form `10 / 20'. +% \begin{macrocode} +\def\thQHPoints#1{\def\th@QHPoints{\textbf{#1}\space}} +\thQHPoints{Points:} +% \end{macrocode} +% \DescribeMacro\thQHGrade\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% Some grade mark (A, B, C, etc., or 1, 2, 3, etc.) +% \begin{macrocode} +\def\thQHGrade#1{\def\th@QHGrade{\textbf{#1}\space}} +\thQHGrade{Grade:} +% \end{macrocode} +% \DescribeMacro\thQuizHeader\nmpsep{*} +% The above commands typically appear above the quiz and placed in some beautiful way. +% We bundle these commands into a single one, according to my own happiness, but you may +% seek happiness some other way by redefining \cs{thQuizHeaderLayout}. +% (The command \cs{thQuizHeader} just picks up on the \texttt*-option, then expands \cs{thQuizHeaderLayout}.) +% The command is placed beneath the \cs{DeclareQuiz} command and above the \env{quiz} +% environment. The command automatically emits a \cs{newpage}, unless the \texttt*-option is taken.\par\medskip\noindent +%\begin{minipage}[t]{\widthof{\cs{DeclareQuiz\darg{\ameta{qz-name}}}}} +%\begin{flushleft} +%\textbf{Preferred Placement}\\[3pt] +%\ttfamily +%\cs{DeclareQuiz\darg{\ameta{qz-name}}}\\ +%...\\ +%\string\begin\darg{document}\\ +%...\\ +%\cs{thQuizHeader}\\ +%...\\ +%\ameta{\textsf{quiz-begins}} +%\end{flushleft} +%\end{minipage}\qquad +%\begin{minipage}[t]{\widthof{\cs{DeclareQuiz\darg{\ameta{qz-name}}}}} +%\begin{flushleft} +%\textbf{Alternate Placement}\\[3pt] +%\ttfamily +%\string\begin\darg{document}\\ +%\cs{DeclareQuiz\darg{\ameta{qz-name}}}\\ +%\cs{thQuizHeader}\\ +%...\\ +%\ameta{\textsf{quiz-begins}} +%\end{flushleft} +%\changes{v1.4.3}{2019/08/22}{let \string\cs{Hy@EveryPageAnchor} to \string\cs{relax}} +%\end{minipage}\medskip +% \begin{macrocode} +\newcommand{\thQuizHeader}{\let\Hy@EveryPageAnchor\relax + \@ifstar{\thPageOne\thQuizHeaderLayout} + {\newpage\thPageOne\thQuizHeaderLayout}% +} +% \end{macrocode} +% \DescribeMacro\thQuizHeaderLayout The body of this command contains the arraignment of +% the above defined commands. It is this command that may be redefined. +% \begin{macrocode} +\newcommand\thQuizHeaderLayout{\noindent + \th@QHFirstName\FirstName{1.5in}{13bp}\vcgBdry[3pt] + \th@QHLastName\LastName{1.5in}{13bp}\vcgBdry[6pt] + \begin{minipage}[t]{1.2in}\kern0pt + \makebox[0pt][r]{\raggedleft\markQz{}{11bp}% + \hspace{\marginparsep}}% + \th@QHPoints\studentReport{\widthof{000/000}}{11bp}\vcgBdry[6pt] + \makebox[0pt][r]{\raggedleft\freezeOrSave{}{11bp}% + \hspace{\marginparsep}}% + \th@QHGrade\studentGrade{14bp}{14bp}\vcgBdry[6pt] + \end{minipage}\hfill + \begin{minipage}[t]{\linewidth-1em-1.2in}\kern0pt + \begin{sumryTblAux}{\currQuiz} + \displaySumryTbl[ntables=1,showmarkup]{\currQuiz} + \end{sumryTblAux} + \end{minipage}} +% \end{macrocode} +% This assumes the English language and the \opt{usesumrytbls} option of \pkg{exerquiz}. +% \subsection{Commands that usually follow the quiz} %\leavevmode\par\medskip\noindent +% \DescribeMacro\completeMsgFldV\nmpsep{\darg{\ameta{pdfstr}}} is the message +% that is displayed in this multi-line text field. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\completeMsgFld\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% When the student completes the quiz, a hidden text field appears and reminds +% the student to save the document. +% \begin{macrocode} +\def\completeMsgFldV#1{\def\completeMsgFld@V{#1}} +\completeMsgFldV{Congratulations, you have completed the quiz, + before doing anything else, you need to save this document.} +% \end{macrocode} +% The definition of \cmd\completeMsgFld +% \begin{macrocode} +\newcommand{\completeMsgFld}[3][]{\textField[\F\FHidden\Ff\FfMultiline + \Ff\FfReadOnly\V{\completeMsgFld@V} + \DV{\completeMsgFld@V}]{postQzMsg}{#2}{#3}} +% \end{macrocode} +% \DescribeMacro\ShrtPtsFld\nmpsep{\darg{\ameta{options}}\darg{\ameta{quiz-name}}} +% This is \pkg{exerquiz}s \cs{PointsField}, but with special format script. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\ShrtPtsFldFmt\nmpsep{\darg{\ameta{js-str}}} is the formatting string +% used; \ameta{js-str} should incorporate the event property \texttt{event.value} +% in its definition. See default definition below. +% \changes{v1.4.17}{2019/10/03}{Rewrote \string\cs{ShrtPtsFldFmt} to produce pdf spaces} +% \begin{macrocode} +\def\ShrtPtsFldFmt{\bgroup\obeyspaces\ShrtPtsFldFmt@i} +\def\ShrtPtsFldFmt@i#1{\egroup\flJSStr[noquotes]{\ShrtPtsFld@Fmt}{#1}} +\ShrtPtsFldFmt{"Short Pts: "+event.value} +% \end{macrocode} +% The definition of \cmd\ShrtPtsFld +% \begin{macrocode} +\newcommand{\ShrtPtsFld}[2][]{% + \PointsField[\AAformat{if(event.value!="") + event.value=\ShrtPtsFld@Fmt}\F\FHidden\protect\AA + \protect\F#1]{#2}} +% \end{macrocode} +% \DescribeMacro\LngPtsFld\nmpsep{\darg{\ameta{options}}\darg{\ameta{quiz-name}}} +% This field will hold the total points for the essay or extended response +% questions. It is modeled after \cs{PointsField}, having the same defaults +% and width and height. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\LngPtsFldFmt\nmpsep{\darg{\ameta{js-str}}} is the formatting string +% used; \ameta{js-str} should incorporate the event property \texttt{event.value} +% in its definition. See default definition below. +% \changes{v1.4.17}{2019/10/03}{Rewrote \string\cs{LngPtsFldFmt} to produce pdf spaces} +% \begin{macrocode} +\def\LngPtsFldFmt{\bgroup\obeyspaces\LngPtsFldFmt@i} +\def\LngPtsFldFmt@i#1{\egroup\flJSStr[noquotes]{\LngPtsFld@Fmt}{#1}} +\LngPtsFldFmt{"Long Pts: "+event.value} +% \end{macrocode} +% The definition of \cmd\LngPtsFld +% \changes{v1.1.3}{2019/07/03}{Make \string\cs{LngPtsFld} a calculation field} +% \changes{v1.4.10}{2019/09/11}{Fixed a bug in calculation when there are no +% essay questions} +% \begin{macrocode} +\newcommand{\LngPtsFld}[2][]{% + \textField[\presets{\PointsFieldDefaults}\F\FHidden + \AAformat{if(event.value!="") event.value=\LngPtsFld@Fmt} + \AAcalculate{var f=this.getField("essayMrkUp");\r + if(f!=null)EFSimple_Calculate("SUM",% +new Array("essayMrkUp.\currQuiz"));} + ]{EssayField.\currQuiz}{\PtFW}{\DefaultHeightOfWidget}} +% \end{macrocode} +% \DescribeMacro\TotalsFld\nmpsep{\darg{\ameta{options}}\darg{\ameta{quiz-name}}} +% This is modeled after \pkg{exerquiz}s \cs{PointsField}, but with special format script. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\TotalsFldFmt\nmpsep{\darg{\ameta{js-str}}} is the formatting string +% used; \ameta{js-str} should incorporate the event property \texttt{event.value} +% in its definition. See default definition below. +% \changes{v1.4.17}{2019/10/03}{Rewrote \string\cs{TotalsFldFmt} to produce pdf spaces} +% \begin{macrocode} +\def\TotalsFldFmt{\bgroup\obeyspaces\TotalsFldFmt@i} +\def\TotalsFldFmt@i#1{\egroup\flJSStr[noquotes]{\TotalsFld@Fmt}{#1}} +\TotalsFldFmt{"Total: "+event.value+"\space\eqOutOf\space"% ++NPointTotal} +% \end{macrocode} +% The definition of \cmd\TotalsFld +% \changes{v1.1.2}{2019/07/02}{Added try/catch in \string\cs{AAformat} to avoid +% exceptions thrown in the case of distiller; added pdf space in the \string\cs{TotalsFld} +% JS to avoid unexpected wraps in the case of dvips/distiller worflow.} +% \begin{macrocode} +\newcommand{\TotalsFld}[2][]{% + \textField[\presets{\PointsFieldDefaults}\F\FHidden + \AAformat{try{event.value=(\TotalsFld@Fmt)}catch(e){}} + \AAcalculate{EFSimple_Calculate("SUM",% +new Array("PointsField.\currQuiz","EssayField.\currQuiz"));\r + var\eqSP f=this.getField("studentenReport");\r + f.value=(1*event.value)+"\eqSP/\eqSP"+\theeqpointvalue; + }]{TotalsField.\currQuiz}{\PtFW}{\DefaultHeightOfWidget}} +% \end{macrocode} +% \leavevmode\DescribeMacro\thQuizTrailer +% The above commands can be arranged in some way following the quiz; one such arrangement +% is found in the command \cmd\thQuizTrailer. +% \begin{macrocode} +\newcommand{\thQuizTrailer}{\raisebox{\baselineskip-\fboxsep}% + {\makebox[0pt][l]{\parbox[t]{3in}{\kern0pt + \completeMsgFld{3in}{3\baselineskip}}}}% + \makebox[0pt][l]{\hspace{3in}\quad + \ifthtestmode\CorrButton{\currQuiz}\else + \stuSaveBtn{}{11bp}\fi}\parbox[t]{3in} + {\ShrtPtsFld{\currQuiz}\vcgBdry[6pt] + \LngPtsFld{\currQuiz}\vcgBdry[6pt] + \TotalsFld{\currQuiz}}} +% \end{macrocode} +% +% \subsection{Controls inside the \tops{\protect\env{quiz}}{quiz} environment} +% +% \DescribeMacro{\essayQ}\nmpsep{\darg{\ameta{nPts}}} +% When we have an essay type question we need to mark it prior to the \cs{item}. +% In order to test whether the instructor has put in more credit than specified +% by the \cs{PTs} command, we need to pass the number of points for this question. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\essayQFldTU\nmpsep{\darg{\ameta{pdfstr}}} is the tool tip +% for this field. +% \begin{macrocode} +\def\essayQFldTU#1{\def\essayQFld@TU{#1}} +\essayQFldTU{Assign points to extended responses} +% \end{macrocode} +% We fix the width \DescribeMacro\EsW\cmd\EsW{} and the height \DescribeMacro\EsH\cmd\EsH{} +% of \cs{essayQ} using commands, these can be redefined. +% \begin{macrocode} +\def\EsW{33bp}\def\EsH{14bp} +% \end{macrocode} +% Now for the definition of \cmd\essayQ +% \begin{macrocode} +\def\essayQ#1{\let\qMark@HookSave\qMark@Hook + \def\qMark@Hook{\makebox[0pt][r]{\smash + {\raisebox{-7bp+\fboxsep}{\stepcounter{questionno}\textField[% + \cmd{\bParams{#1}\eParams}\F\FHidden\Q{1} + \AAkeystroke{\essayQKey} +% \AAonfocus{var essayPtsAssigned=(1*event.value);} + \AAformat{if(event.value!="") event.value=event.value + +((event.value==1)?" \eqptLabel":" \eqptsLabel")} + \TU{\essayQFld@TU} + ]{essayMrkUp.\currQuiz.\thequestionno}{\EsW}{\EsH}% + \addtocounter{questionno}{-1}}}}\global + \let\qMark@Hook\qMark@HookSave}} +% \end{macrocode} +% The way you pose an essay question is as follows: +%\begin{verbatim} +% \essayQ{5} +% \item\PTs{5} The question ...\\[3pt] +% \RespBoxEssay{4in}{4\baselineskip} +%\end{verbatim} +%\leavevmode\DescribeMacro\essayitem\nmpsep{\darg{\ameta{num}}} +% We simply this workflow a little, define \cs{essayitem}: +% \begin{macrocode} +\def\essayitem#1{\essayQ{#1}\item\PTs{#1}} +% \end{macrocode} +%Thus, we can now type, +%\begin{verbatim} +% \essayitem{5} The question ...\\[3pt] +% \RespBoxEssay{4in}{4\baselineskip} +%\end{verbatim} +% +% \section{Field level JavaScript for form field commands} +% +% JS\DescribeMacro\pwdInstrFld{} Keystroke action for \cmd\pwdInstrFld. This script +% uses three parameters passed to it through {\cmd\pwdInstrFld}: \texttt{@p(1)} is the quiz +% name (\cmd\currQuiz); \texttt{@p(2)} is the number of questions; and \texttt{@p(3)} is +% the password. +% \begin{macrocode} +\begin{defineJS}[\catcode`\@=0\relax]{\pwdKeyJS} +if (event.willCommit) { + if (event.value==@p(3)) { + @commonPassKey + } +} +\end{defineJS} +\begin{defineJS}[\catcode`\@=0\relax]{\commonPassKey} +% \end{macrocode} +% Added code from \cs{qz@IDTxtField} to avoid the dreaded `q1 is undefined' +% JavaScript error message. This happends when the \textsf{Mark It} control +% and the \textsf{Begin Quiz} controls are on different pages. When \textsf{Mark It} +% is pressed, `q1' has not been defined yet, not until the next page. +% \changes{v1.4.7}{2019/08/27}{Added format code from \string\cs{qz@IDTxtField}} +% \begin{macrocode} +if(typeof aQuizzesInDoc=="undefined") + var aQuizzesInDoc=new Array(); +if (aQuizzesInDoc.indexOf("@oField")) + aQuizzesInDoc.push("@oField"); +if (typeof @oField=="undefined") + var @oField=new Object; +restoreQuizData(); +this.calculate=true; +var f=this.getField("postQzMsg"); +if (f!=null) f.display=display.hidden; +var f=this.getField("pbStuSvCl"); +if (f!=null) f.display=display.hidden; +var f=this.getField("ScoreField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("PointsField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("EssayField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("TotalsField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("essayMrkUp"); +if (f!=null) f.display=display.visible; +correctQuiz("@p(1)",@p(2)); +var f=this.getField("qzreset"); +if (f!=null) f.display=display.visible; +var f=this.getField("freezeQz"); +if (f!=null) f.display=display.visible; +var f=this.getField("studentenReport"); +if (f!=null) f.display=display.visible; +var f=this.getField("studentenGrade"); +if (f!=null) f.display=display.visible; +if (typeof correctSumryTbl == "function") + correctSumryTbl("@p(1)",@p(2)); +\end{defineJS} +% \end{macrocode} +% Keystroke JS\DescribeMacro\essayQKey{} action for \cmd\essayQ. The +% \texttt{@p(1)} parameter is the weight of this essay question, it is passed to +% this script by \cmd\essayQ. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\NoNumEnteredMsg\nmpsep{\darg{\ameta{jsstr}}} When you enter a non-number, +% and an alert box pops up with this as its message. +% \begin{macrocode} +\def\NoNumEnteredMsg#1{\flJSStr*[noquotes]{\cNoNumEnteredMsg}{#1}} +\NoNumEnteredMsg{"You did not enter a number, % +enter a nonnegative number only"} +% \end{macrocode} +% \DescribeMacro\TooMuchCreditMsg\nmpsep{\darg{\ameta{jsstr}}} When you assign too +% much credit for the problem, an alert box appears containing this message. +% \begin{macrocode} +\def\TooMuchCreditMsg#1{\flJSStr*[noquotes]{\cTooMuchCredit}{#1}} +\TooMuchCreditMsg{"You've assigned too much credit for this % +problem, assigning the maximum instead"} +% \end{macrocode} +% Now the definition of \cmd\essayQKey +% \changes{v1.1.1}{2019/06/30}{Corrected a bug in \string\cs{essayQKey} that caused +% a miscalculation.} +% \changes{v1.1.3}{2019/07/03}{Remove lines not needed since \string\cs{LngPtsFld} became +% a calculation field} +% \begin{macrocode} +\begin{defineJS}[\makeesc\@\catcode`\%=14\relax]{\essayQKey} +if (event.willCommit) { + var qpts=(1*event.value); + if (isNaN(qpts)) { + app.alert(@cNoNumEnteredMsg); + event.rc=false; + } else if (qpts<0) { + event.value=-1*event.value; + qpts=1*event.value; + } + if (event.rc) { + if (qpts > @p(1) ) { + app.alert(@cTooMuchCredit); + qpts=@p(1); + } + // update ProbDist array + ProbDist[@thequestionno]=qpts; + // see if table is present + if (typeof correctSumryTbl == "function") { + f=this.getField("% +@dlcombine(@currQuiz)(SanityCheckPts).@thequestionno"); + var thesePts= qpts + (( qpts == 1 )?% +" @eqptLabel":" @eqptsLabel"); + f.value=thesePts; + // add color + var cb=this.getField("% +@dlcombine(@currQuiz)(SanityCheck).@thequestionno"); + if (qpts==@p(1)) cb.strokeColor=@rghtColorJS; + else if (qpts>0) cb.strokeColor=@partialColorJS; + else cb.strokeColor=@wrngColorJS; + } + event.value=qpts; + } +} +\end{defineJS} +% \end{macrocode} +% \DescribeMacro\instrAutoSaveOn When the instructor presses the freeze quiz control, there is an option +% to automatically save the document or not. \cmd\instrAutoSaveOn{} saves the document; however, if +% \DescribeMacro\instrAutoSaveOff\cmd{\instrAutoSaveOff} is expanded in the preamble, no automatic +% save is performed. The default is \cmd\instrAutoSaveOn. +% \begin{macrocode} +\def\instrAutoSaveOn{\def\instrAutoSave{true}} +\def\instrAutoSaveOff{\def\instrAutoSave{false}} +\instrAutoSaveOn +% \end{macrocode} +% \DescribeMacro\instrAutoCloseOn When the instructor presses the freeze quiz control, there is an option +% to silently close the document or not. \cmd\instrAutoCloseOn{} closes the document; however, if +% \DescribeMacro\instrAutoCloseOff\cmd{\instrAutoCloseOff} is expanded in the preamble, no automatic +% closing occurs. The default is \cmd{\instrAutoCloseOn}. +% \begin{macrocode} +\def\instrAutoCloseOn{\def\instrAutoClose{true}} +\instrAutoCloseOn +\def\instrAutoCloseOff{\def\instrAutoClose{false}} +% \end{macrocode} +% The mouse up\IndexJS{freezeQuizMU()}{} JavaScript for \texttt{freezeQuiz()}. It makes all form fields +% \emph{in the entire document} readonly. \emph{Use only} after all markups are finished and document is ready +% to be moved into the student's folder. +% \changes{v1.4.12}{2019/09/11}{Correction a problem with \string\cs{MarkWarningMsg} +% in the dvips/distiller workflow} +% \begin{macrocode} +\def\MarkWarningMsg#1{\dlJSStr*[noquotes]{\MarkWarning@Msg}{#1}} +\MarkWarningMsg{"You did not award the student a final mark.\ + \\n\\nAward the mark and then save."} +% \end{macrocode} +% The \DescribeMacro\flattenOn\cs{flattenOn} turns on flattening, while +% \DescribeMacro\flattenOff\cs{flattenOff} turns flattening off. The reason +% you would turn flattening off is to use \textsf{Thor's way} for basic methods +% and for the \opt{useclass} option. The default is \cs{flattenOff} for basic methods +% and \cs{flattenOn} for \opt{usebatch}. Applies only when the \texttt{Freeze Quiz} +% button is present. +% \changes{v1.4.13}{2019/09/12}{Added \string\cs{flattenOn} and \string\cs{flattenOff}} +% \begin{macrocode} +\def\flattenOn{\def\bFlattenState{false}} +\def\flattenOff{\def\bFlattenState{true}} +\ifbasicmethods\flattenOff\else\flattenOn\fi +% \end{macrocode} +% The definition of \texttt{freezeMU()}. +% \begin{macrocode} +\begin{insDLJS}{jsforthor}{thorshammer: Freeze/Save Doc} +var sndSaveWarning=\SecondSave@Msg; +var isthereCvrPg=\thIsCP; +var cvrPgNum="\thCvrPg"; +function freezeQuizMU() { +var f, fname; +var bOK=true; +var f=this.getField("studentenGrade"); +var str=""+f.value; +str=str.replace(/\s/g,""); +if (str=="") { + app.alert(\MarkWarning@Msg); + bOK=false; +} +% \end{macrocode} +% Determine if there are solution pages, and if so, re-insert them. +% \changes{v1.4.8}{2019/09/05}{Append solution pages if there is one} +% \begin{macrocode} +var SolnSet=this.info.SolnSet; +if (bOK&&SolnSet!=""){ + var SolnPath=this.info.SolnPath; +// var SolnSet=this.info.SolnSet; + var qzbasename=this.info.qzBaseName; + aebTrustedFunctions(this,aebInsertPages,{ + nPage: (this.numPages-1), + cPath: SolnPath+"/"+qzbasename+"-"+SolnSet+".pdf" + }) +}; +% \end{macrocode} +% If \cs{thUseNameToCustomize} is true, we use the current file name; otherwise +% we use the original file name (\cs{jobname}) +% \begin{macrocode} +if(\instrAutoSave&&bOK) { +// var cSave="\jobname"; + var docFN=this.documentFileName; + docFN=docFN.substring(0,docFN.length-4); + var cSave=(\thUseNameToCustomize)?"\jobname":docFN; +% \end{macrocode} +% If \cs{thUseNameToCustomize} is true, we append student and \texttt{"-g"} +% to signal that this file has been graded. +% \begin{macrocode} + if(\thUseNameToCustomize) { + var f=this.getField("Name.first"); + if(f!=null)cSave+=("-"+f.value+"_"); + f=this.getField("Name.last"); + if(f!=null)cSave+=(f.value); + cSave+=("-g"); + } + var oRetn=aebTrustedFunctions(this,aebBrowseForDoc,{bSave:true,% +cFilenameInit: cSave }); + bOK=(typeof oRetn=="object"); + if(bOK) { +% \end{macrocode} +% If the file name and path are chosen, we make all files readonly +% \begin{macrocode} + for (var i=0; i"}. The fact that the \texttt{Responses} array +% is nonempty for this question will cause a check mark to appear +% in the summary table. +% \begin{macrocode} + var stripResp=stripWhiteSpace(event.value);\jsR\jsT + if(stripResp=="")Responses[\thequestionno]=undefined;\jsR\jsT + else Responses[\thequestionno]="";\jsR\jsT + if ( typeof fieldPopTbl == "function" ) fieldPopTbl("\currQuiz"); + }\jsR + if (!isQuizInitialized("\curr@quiz")) {\jsR\jsT + \eqObjAlert\space eqAppAlert(% + InitMsg("\bqlabelISO"),3);\jsR\jsT + event.rc = false;\jsR + }% + }% + \fi + } +} +% \end{macrocode} +% We redefine \cs{@initQuiz} from \pkg{exerquiz} to first test whether +% name fields have been entered. +% \changes{v1.1.6}{2019/07/06}{Check on name fields} +% \begin{macrocode} +\def\InitQzMsg#1{\flJSStr*[noquotes]{\InitQzMsg@Msg}{#1}} +\InitQzMsg{"You cannot begin the quiz before entering + your first and last names in the fields provided.\n\n + Enter the name as you are known in the class; otherwise, + you will receive no credit for your work."} +\def\IfbQzChkSnippet{% +this.calculate=false;\jsR +if(\thOrdQz) bOk=true\jsR +else {\jsR\jsT + var f=this.getField("Name.first");\jsR\jsT + var str1=stripWhiteSpace(f.value);\jsR\jsT + var f=this.getField("Name.last");\jsR\jsT + var str2=stripWhiteSpace(f.value);\jsR\jsT + bOk=(str1!=""&&str2!="");\jsR +} +if(bOk)} +\expandafter\def\expandafter\@initQuiz\expandafter + {\expandafter\IfbQzChkSnippet\expandafter{\@initQuiz} + else app.alert({cMsg:\InitQzMsg@Msg,cTitle:\ThorsAlert@Title}); +} +% \end{macrocode} +% Modify \DescribeMacro\postSubmitQuiz\cmd\postSubmitQuiz. +% When the \textsf{End Quiz} control is pressed, we make visible the post +% quiz message, placed in the document by the \cmd\completeMsgFld{} command. +% \begin{macrocode} +\toks@=\expandafter{\postSubmitQuiz\t\t + oRecordOfQuizData["ProbDist.\oField"]=ProbDist;\r\t\t + oRecordOfQuizData["RightWrong.\oField"]=RightWrong;\r\t\t + var f=this.getField("postQzMsg");\r\t\t + if (f!=null) f.display=display.visible;\r\t\t + var f=this.getField("pbStuSvCl");\r\t\t + if (\stuAutoSave&&f!=null)f.display=display.visible;} %\r\t\t +\edef\postSubmitQuiz{\the\toks@} +% \end{macrocode} +% The action for the End Quiz button, we modify it to give the student a chance to reconsider +% his decision to end the quiz. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\EndQzWarningMsg\nmpsep{\darg{\ameta{jsstr}}} The message that appears +% on the alert box asking to student to verify ending the quiz. +% \changes{v1.1.6}{2019/07/06}{Added end quiz warning} +% \begin{macrocode} +\def\EndQzWarningMsg#1{\flJSStr*[noquotes]{\EndQzWarning@Msg}{#1}} +\EndQzWarningMsg{"When you end the quiz, you cannot change +any of your answers without starting the quiz over from the +beginning.\n\n Press \\"Yes\\" to end the quiz."} +\def\ThorsAlertTitle#1{\flJSStr*[noquotes]{\ThorsAlert@Title}{#1}} +\ThorsAlertTitle{"Thor's Hammer"} +% \end{macrocode} +% \DescribeMacro\eq@EndQzBtnScript The modified script for the end of the +% quiz button. We rework the script of \cs{eq@@EndQuizButtonActions}, taken from \pkg{exerquiz}. +% \begin{macrocode} +\begin{defineJS}[\makeesc\*\catcode`\%=14\relax]{\eq@EndQzBtnScript} +if (!isQuizInitialized("*currQuiz")) + eqAppAlert(InitMsg("*bqlabelISO"),3); +else { + var retn=app.alert({cMsg: *EndQzWarning@Msg,% +cTitle: *ThorsAlert@Title, nIcon: 2, nType: 2}); + if (retn==4) { + if (*minQuizResp(*thequestionno)&&_ModalNotOn){ + *currQuiz.PtValues=(new % +Array(*pointValuesArray)); + ProbType=[*ptypeArray]; +*if@inclkey% + *currQuiz.CorrAns=(new % +Array(*corrAnsArray)); +*fi% + DisplayQuizResults("*currQuiz",*theeqpointvalue,% +*thequestionno); + var h=this.getField("ScoreData.*currQuiz"); + h.value=Score+";"+NQuestions+";"% ++ptScore+";"+NPointTotal; +% *eq@submitURL + *postSubmitQuiz + resetQuiz("*currQuiz"); + } + } +} +\end{defineJS} +% \end{macrocode} +% Now, we redefine \cs{eq@@EndQuizButtonActions} of \pkg{exerquiz}. +% \begin{macrocode} +\def\eq@@EndQuizButtonActions{\A{\JS{\eq@EndQzBtnScript}}} +% \end{macrocode} +% Add a \textsf{SaveAs} menu item to end of the quiz +% \changes{v1.1.4}{2019/07/04}{Add a SaveAs menu item to end of the quiz} +% \changes{v1.1.5}{2019/07/06}{If document is dirty, do not save} +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\stuAutoSaveOn When expanded in the preamble, a save button will appear (\cmd\stuSaveBtn) +% when the \textsf{End Quiz} control is pressed. A dialog appears to save the file, the student can choose +% the file location and the file name at that time. When \DescribeMacro\stuAutoSaveOff\cmd\stuAutoSaveOff{} +% is in effect, the save button does not appear, and the student must press the save button the on +% \app{Adobe Reader} toolbar. The default is \cmd\stuAutoSaveOn. +% \begin{macrocode} +\let\stuASOn\ef@YES +\def\stuAutoSaveOn{\let\stuASOn\ef@YES + \def\stuAutoSaveScript{\t app.execMenuItem("SaveAs");\r}% + \def\stuAutoSave{true}} +\def\stuAutoSaveOff{\let\stuASOn\ef@NO + \let\stuAutoSaveScript\@empty + \def\stuAutoSave{false}} +\stuAutoSaveOn +% \end{macrocode} +% \DescribeMacro\stuAutoCloseOn This command is obeyed only if \cmd{\stuAutoSaveOn} +% is in effect. After the student presses the save button (\cmd\stuSaveBtn), the +% document is closed after the student save the document. Note that if the student +% cancels saving the document and if the document still needs saving, the document +% is not closed. The default is \cmd\stuAutoCloseOn. +% \begin{macrocode} +\def\stuAutoCloseOn{\def\stuAutoCloseScript{\t + if(!this.dirty)this.closeDoc(true);\r}% + \def\stuAutoClose{true}} +\stuAutoCloseOn +\def\stuAutoCloseOff{\let\stuAutoCloseScript\@empty + \def\stuAutoClose{false}} +% \end{macrocode} +% \DescribeMacro\stuSaveBtnCA\nmpsep{\darg{\ameta{jsstr}}} The caption for this button +% \begin{macrocode} +\def\stuSaveBtnCA#1{\def\stuSaveBtn@CA{#1}} +\stuSaveBtnCA{Save} +% \end{macrocode} +% \DescribeMacro\stuSaveBtnTU\nmpsep{\darg{\ameta{jsstr}}} The tool tip for this button +% \begin{macrocode} +\def\stuSaveBtnTU#1{\def\stuSaveBtn@TU{#1}} +\stuSaveBtnTU{Press to save and close the document} +% \end{macrocode} +% \DescribeMacro\stuSaveBtn\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} +% This button is initially hidden and becomes visible within the student presses +% the \textsf{End Quiz} control; provided \cs{stuAutoSaveOn} is in effect. The button +% saves and optionally closes the document. +% \begin{macrocode} +% \end{macrocode} +% \leavevmode\DescribeMacro\autoSaveStuJS is a revised version of the JavaScript action +% for \cs{stuSaveBtn}. If the JavaScript method \texttt{aebTrustedFunctions} is undefined, we use the old code; +% otherwise, we use the new code. +% \changes{v1.5.5}{2019/12/08}{Use \string\texttt{aebTrustedFunctions} if present} +% +% \medskip\noindent\DescribeMacro\SecondSaveMsg\nmpsep{\darg{\ameta{msg}}} is an alert dialog message stating +% the the document was not saved. This declaration mush occur on the preamble of in the CFG file, or is has no effect. +% \begin{macrocode} +\def\SecondSaveMsg#1{\dlJSStr*[noquotes]{\SecondSave@Msg}{#1}} +\SecondSaveMsg{"Alert! This document has not been saved, do not + exit before saving!"} +% \end{macrocode} +% When \texttt{aebTrustedFunctions} is defined for \app{AR}, we offer two methods for the student +% to save the document: (1) \DescribeMacro\useStuSaveAsDialogOff\cs{useStuSaveAsDialogOff} (the default) +% is the most seamless method, no save-as dialog is offered, the student asked to confirm the save; (2) +% \DescribeMacro\useStuSaveAsDialogOn\cs{useStuSaveAsDialogOn} offers the save-as dialog (but streamlined). +% These two commands must appear on the preamble or CFG file, or they have no effect. +% \begin{macrocode} +\newif\ifUseStuSaveAsDialog\UseStuSaveAsDialogfalse +\def\useStuSaveAsDialogOn{\UseStuSaveAsDialogtrue} +\def\useStuSaveAsDialogOff{\UseStuSaveAsDialogfalse} +\begin{defineJS}[\makeesc\*\catcode`\%=14\relax]{\autoSaveStuJS} + var bOK=true; + global.bOkClose=true; + var _path=this.path; + var pos=_path.lastIndexOf("/"); + var currentFolder=_path.substring(0,pos+1); + var docFN=this.documentFileName; + docFN=docFN.substring(0,docFN.length-4); + var cSave=(*thUseNameToCustomize)?"*jobname":docFN; + currentFolder=currentFolder+cSave+".pdf"; + if (typeof aebTrustedFunctions=="undefined") + app.execMenuItem("SaveAs"); + else { +% \end{macrocode} +% In this controlled environment of taking PDF quizzes at an institution, +% the AeB special function \texttt{aebTrustedFunctions} is defined, +% along with supporting functions. +% \begin{macrocode} +*ifUseStuSaveAsDialog% + var oRetn=aebTrustedFunctions(this,aebBrowseForDoc,% +{bSave:true,cFilenameInit: cSave }); + bOK=(typeof oRetn=="object"); +*fi% +% \end{macrocode} +% If the user dismisses the browse-for-doc dialog, the return value (\texttt{oRetn}) is undefined; +% in this case, we do not save or close the document. The user must initiate the action +% again. +% \changes{v1.5.7}{2020/01/13}{Added delete global.bOkClose} +% \begin{macrocode} + aebDocSaveAs.msg=""; + aebDocSaveAs.action=% +'global.bOkClose=false;app.alert("'+sndSaveWarning+'")'; + if (bOK) var retn=aebTrustedFunctions(this,aebDocSaveAs,% +{cPath:*ifUseStuSaveAsDialog oRetn.cPath*else currentFolder*fi }); + else app.alert(sndSaveWarning); + } + if(*stuAutoClose&&bOK&&global.bOkClose&&!this.dirty) + delete global.bOkClose; + this.closeDoc(true); +\end{defineJS} +% \end{macrocode} +% We finally reach the definition of \cs{stuSaveBtn} +% \begin{macrocode} +\newcommand\stuSaveBtn[3][]{\pushButton[\F\FHidden + \CA{\stuSaveBtn@CA}\TU{\stuSaveBtn@TU} +% \end{macrocode} +% Here, we leverage the new \cs{cmd} command to test if auto save is on, if not +% we gobble the \cs{AAmouseup} action. +% \begin{macrocode} + \cmd{\ifx\stuASOn\ef@NO\let\@eqAAmouseup\@gobble\fi} + \AAmouseup{if(\stuAutoSave){\r + \autoSaveStuJS +% \stuAutoSaveScript\stuAutoCloseScript + }}\protect\AA\protect\F#1 +]{pbStuSvCl}{#2}{#3}} +% \end{macrocode} +% \DescribeMacro\DeclareQuiz\nmpsep{\darg{\ameta{qz-name}}} +% We modify the \cs{DeclareQuiz} command of \pkg{exerquiz}, by appending +% some code that defines \cs{eq@prior@endQuiz} to write the number of questions +% and the number of points to the AUX file. +% This command \emph{must appear}\marginpar{\raggedleft Required in preamble or at top of file} at the top of the source file, just after +% \verb|\begin{document}| or in the \emph{preamble}, it defines \cs{currQuiz} for the rest of the document, +% and write to AUX file. When using multi-quizzes in one source file, this package redefines the \cs{currQuiz}; for example, +% if originally, you declared \cs{DeclareQuiz\darg{Quiz1}}, the first renditions uses the quiz name +% \texttt{Quiz1a}, the second \texttt{Quiz1b}, and so on. (Limit of 26 renditions). To preserve the original +% quiz name, we define \DescribeMacro\thQuizName\cs{thQuizName}, this command expands to \cs{Quiz1} within all +% renditions; consequently, can be used in the running head to consistently display the quiz name. +% \begin{macrocode} +\let\DeclareQuizSAVE\DeclareQuiz +\def\DeclareQuiz#1{\def\thQuizName{#1}\th@DeclareQuiz{#1}} +\def\th@DeclareQuiz#1{\DeclareQuizSAVE{#1}% + \expandafter\gdef\expandafter + \eq@prior@endQuiz\expandafter{\eq@prior@endQuiz\wrtQzInfo}} +% \end{macrocode} +% \DescribeMacro\thQzName\nmpsep{\darg{\ameta{friendly-qz-name}}} This is the friendly (human readable) +% quiz name, suitable for use in the running header and elsewhere. +% \begin{macrocode} +\def\thQzName#1{\def\thqzname{#1}} +\thQzName{\thQuizName} +% \end{macrocode} +% \begin{macrocode} +\def\wrtQzInfo{\eq@IWAuxOut{\string + \csarg\string\gdef{\currQuiz-nQs}{\thequestionno}^^J\string + \csarg\string\gdef{\currQuiz-nPts}{\theeqpointvalue}}} +% \end{macrocode} +% We modify \DescribeMacro\eqQuizPointsMsg\cmd\eqQuizPointsMsg{}, its default definition +% is the string \begin{quote}\ttfamily"\string\eqptScore\string\space"+ptScore+" +% \string\eqOutOf\string\space"+nPointTotal\end{quote}but for Thor's way, we simplify to \texttt{ptScore}. +% \begin{macrocode} +\renewcommand\eqQuizPointsMsg{ptScore} +% \end{macrocode} +% \subsection{Modify margin points markup} +% Make the markup boxes in the margins larger. +% \begin{macrocode} +\renewcommand{\aeb@creditmarkup}{\bgroup + \edef\markupWidth{\EsW}\edef\markupHeight{\EsH}% + \textField[\Ff\FfReadOnly\BC{}\F\FHidden + \textColor{\pcMarkupColor}\textSize{\markupTextSize}\autoCenter{y}% + \DV{0 \eqptsLabel}\V{0 \eqptsLabel}]% + {qMark.\currQuiz.\thequestionno.\arabic{qMarkCnt}}% + {\markupWidth}{\markupHeight}\egroup} +% \end{macrocode} +% +% \subsection{Modifications to the summary table} +% We modify the summary table to make the markup points larger and +% left align the second column. Thor may come down on me with his mighty hammer, but +% I'll take the chance. +% \begin{macrocode} +\def\eq@begintab{% second column left aligned + \begin{tabular}[t]{llc}\sumryTblQ&\sumryTblR&\sumryTblP\\\sthline + {\Large\strut}}% +\let\st@scndclmnSAVE\st@scndclmn +% \end{macrocode} +% Offset the check boxes by 2bp to better align with the heading +% \begin{macrocode} +\def\st@scndclmn{\kern2bp\st@scndclmnSAVE} +% \end{macrocode} +% Increase the width of the markup boxes (from 12bp to 20bp, and change to a fixed text size +% \begin{macrocode} +\def\stmarkupWidth{20bp} % normally 12bp +\def\stmarkupHeight{9bp} % unchanged +\def\stmarkupTextSize{8} % normally 0pt +% \end{macrocode} +% Offset the check boxes by 2bp to better align with the heading +% \begin{macrocode} +\def\stmarkupbox{\mbox} % normally {\makebox[0pt][l]} +%\def\sumrytbllinkHook#1{\the\value{page}} +\def\st@thrdclmn#1{\setLink[\linktxtcolor{black} + \A{\JS{this.pageNum=(this.pageNum+#1-1)}}]{\sumrytbllinkHook{#1}}} +% \end{macrocode} +% +% \subsection{Boom! Thor's thunders: ``Thor needs solutions!''} +% +% The package was complete, then it wasn't. \cs{RespBoxEssay} never supported +% solutions, so that needed to be fixed, now requiring \pkg{exerquiz} dated +% 2019/08/13 or later.\par\medskip +% +% The first issue addressed here is the labeling of the solutions to the quiz. +% We try a simple enumeration of the solutions. For that, the \cs{fancyQuizHeaders} +% is used from \pkg{exerquiz}. +% \begin{macrocode} +\fancyQuizHeaders +\setsolnspace{} +\let\FncyHdrsFmtNoTitleQuiz\@empty +% \end{macrocode} +% The question numbers protrude into the left margin, to disguise this, wes +% shift the running header over a little +% \changes{v1.4.5}{2019/08/25}{Added command to remove shift for solns headers} +% \begin{macrocode} +\setlength{\eflength}{\widthof{\textbf{00.}\space}} +\edef\th@leftShiftHdr{\the\eflength} +\def\th@HeaderOffset{\hskip-\th@leftShiftHdr\relax} +\def\doNotShirtSonsHdrs{\let\th@HeaderOffset\relax} +% \end{macrocode} +% \DescribeMacro\thQzSolnMrkr\cmd{\thQzSolnMrkr} is a small text field that is inserted under the +% section title. This is used to identify on what page the solutions begin. +% Later used by \cs{sadQuizzes}. +% \begin{macrocode} +\def\thQzSolnMrkr{\textField[\BC{}]{thsolns4.\currQuiz}{1bp}{1bp}} +% \end{macrocode} +% The quiz numbers will go in the left margin, so we'll shift +% the section title over a little to disguise this. +% \begin{macrocode} +\def\quizSolnsHeadnToc{\section* + {\makebox[0pt][l]{\th@HeaderOffset + \thQzSolnMrkr\sqslsectitle}}% + \addcontentsline{toc}{section}{% + \@ifundefined{web@latextoc}{}{% + \ifx\web@latextoc\eq@YES\else + \protect\numberline{}\fi}\sqslsectitle}} +\renewcommand\eq@sqslsectitle{Solutions to the Quiz} +% \end{macrocode} +% \DescribeMacro\myFQHFmt describes the numbering scheme +% for the solutions. +% \begin{macrocode} +\newcommand\myFQHFmt{% + \string\bfseries\string\color{\fncyQHdrsColor}% + \ifx\aebTitleQuiz\@empty + \ifnum\@eqquestiondepth>0\relax + \FncyHdrsFmtNoTitleQuiz\fi\else + \aebTitleQuiz\protect\ + \ifnum\@eqquestiondepth=0\else\\\relax + \FncyHdrsFmtQuestion\fi + \fi %\space + \ifcase\@eqquestiondepth + \ifx\aebTitleQuiz\@empty\FncyHdrsFmtNoTitleQuiz\fi + \or + \string\llap{\arabic{eqquestionnoi}.\space}% + \or + \string\llap{\arabic{eqquestionnoi}.\space}% + (\alph{eqquestionnoii})\space + \or + \string\llap{\arabic{eqquestionnoi}.\space}% + (\alph{eqquestionnoii})% + (\roman{eqquestionnoiii})\space + \fi +} +\dclrFncyQzHdrsFmt{\myFQHFmt} +% \end{macrocode} +% No return symbol or link to the question. +% \begin{macrocode} +\let\ReturnTo\@gobbletwo +% \end{macrocode} +% +% \subsection{Modifications to the \texorpdfstring{\protect\pkg{web}}{web} package} +% +% The TEX template file (\texttt{tex-template.tex}, generated by \texttt{thmclass.ps1}) +% specifies the \pkg{web} package +% and uses many command particular to that package. Here, we create a special command +% to input customization commands that are specified in the \texttt{web.cfg} file. Place +% \DescribeMacro\inputWebCfg\cs{inputWebCfg} in the preamble to input the \texttt{web.cfg}; +% any \cs{ExecuteOptions} commands are ignored. Customization commands are placed between +% the two marks \cs{bWebCustomize} and \cs{eWebCustomize}. +% \changes{v1.5.1}{2019/10/23}{Allow \string\texttt{web.cfg} to be imported in the preamble.} +% +% \begin{macrocode} +\let\bWebCustomize\endinput +\let\eWebCustomize\relax +\providecommand{\inputWebCfg}{% + \let\bWebCustomize\relax + \let\eWebCustomize\endinput + \let\ExecuteOptions@SAVE\ExecuteOptions + \let\ExecuteOptions\@gobble + \makeatletter + \InputIfFileExists{web.cfg}{}{}\makeatother + \let\ExecuteOptions\ExecuteOptions@SAVE + \let\bWebCustomize\endinput + \let\eWebCustomize\relax +} +% \end{macrocode} +% +% \section{The \texttt{useclass} option and above} +% +% These options (\opt{useclass}, \opt{usebatch}, and \opt{batchdistr}) are designed for the mass production of the quizzes, one for each student +% in the class. The quiz is built and saved (for each student), saved to the instructor's +% designated folder, as declared by \cs{instrPath}, and to the student's personal folder +% as declared within the \cs{classMember} entry and \cs{classEntries} array. +% +% \subsection{Declaring class members}\label{s:ICInfo} +% In conjunction with \cs{instrPath} and \cs{classPath}, use \cs{classMember} to declare +% the identity of each member of the class. +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\classMember\nmpsep{*\darg{\ameta{first-name}}\darg{\ameta{last-name}}*\darg{\ameta{folder{\upshape\string|}path}}} +% Enter the first name, last name, and folder name of each student in the class. When the star +% form is used, \ameta{first-name} and \ameta{last-name} are first passed through +% \cs{pdfstringdef}. If the second star-open is specified between the second and third arguments, the third argument +% should be the absolute path to the (exceptional) student.\medskip +% +% \noindent There are several ways of producing characters in the Latin-1 character set: +%\begin{itemize} +% \item unicode method\DescribeMacro\u: |\classMember{J\u00FCrgen}{Loki}{B}| +% +% \item using \cs{pdfstringdef}\DescribeMacro{\classMember*}, in this case use the star version of \cs{classMember} +% |\classMember*{J\"{u}rgen}{Loki}{B}| +% +% \item octal method\DescribeMacro\oct: |\classMember{J\oct374rgen}{Loki}{B}| or\\ +% \phantom{octal method:} |\classMember{J\string\374rgen}{Loki}{B}| +%\end{itemize} +% \begin{macrocode} +\def\classEntriesDef{["","","",false]} +\newif\ifClassEntries\ClassEntriesfalse +\let\classEntries\@gobble +\def\classMember{\ClassEntriestrue\@ifstar + {\let\th@star\ef@YES\classMember@i} + {\let\th@star\ef@NO\classMember@i}} +\newcommand\classMember@i[2]{% + \@ifstar{\let\th@exstar\ef@YES\classMember@ii{#1}{#2}} + {\let\th@exstar\ef@NO\classMember@ii{#1}{#2}}} +\newcommand\classMember@ii[3]{% + \ifx\th@exstar\ef@YES\def\AbsPth{true}\else + \def\AbsPth{false}\fi + \ifx\th@star\ef@NO + \ifx\th@exstar\ef@YES + \g@addto@macro\classEntries{,["#1","#2","#3",true]}\else + \g@addto@macro\classEntries{,["#1","#2","#3",false]}\fi + \else + \g@addto@macro\classEntries{,["}% + \pdfstringdef\x{#1}\expandafter + \g@addto@macro\expandafter\classEntries\expandafter{\x}% + \g@addto@macro\classEntries{","}% + \pdfstringdef\x{#2}\expandafter + \g@addto@macro\expandafter\classEntries\expandafter{\x}% + \g@addto@macro\classEntries{","}% + \pdfstringdef\x{#3}\expandafter + \g@addto@macro\expandafter\classEntries\expandafter{\x}% + \ifx\th@exstar\ef@YES + \g@addto@macro\classEntries{",true]}\else + \g@addto@macro\classEntries{",false]}\fi + \fi} +% \end{macrocode} +% +% \subsection{Some process controls} +% +% During document development, you don't want to copy the files each time you build and review the document. +% Set \DescribeMacro\autoCopyOff\cs{autoCopyOff} during quiz development, and declare +% \DescribeMacro\autoCopyOn\cs{autoCopyOn}. The default is \cs{autoCopyOn}. +% \begin{macrocode} +\def\autoCopyOn{\def\autoCopy{true}} +\def\autoCopyOff{\def\autoCopy{false}} +\autoCopyOn +% \end{macrocode} +% \DescribeMacro\cFS\nmpsep{\darg{empty\string|CHTTP}} (This command is obsolete, and should be removed. Its functionality +% is accessed through the optional arguments of \cs{instrPath} and \cs{classPath}.) +% The \texttt{Doc.saveAs()} method has a +% \texttt{cFS} key for determining the file system, the value of the key is either empty +% or the string \texttt{CHTTP}. We offer this option. This key is recognized for the \cs{classPath}, we +% assume the \cs{instrPath} is in his local file system; however, it is easy to incorporate the \texttt{cFS} +% key here as well. +% \begin{macrocode} +\newcommand{\cFS}[1]{\def\@rgi{#1}\ifx\@rgi\@empty + \let\cFSth\@empty\else\def\cFSth{CHTTP}\fi} +\let\cFSth\@empty +% \end{macrocode} +% \DescribeMacro\distrToStudentsOff +% Allow the instructor to turn off the distribution of the quizzes to the students' +% folders using \cs{distrToStudentsOff}, the default +% is \DescribeMacro\distrToStudentsOn\cs{distrToStudentsOn}. +% \begin{macrocode} +\def\distrToStudentsOn{\def\distrToStudents{true}}\distrToStudentsOn +\def\distrToStudentsOff{\def\distrToStudents{false}} +% \end{macrocode} +% \DescribeMacro\distrToInstrOff +% Allow the instructor to turn off the distribution of the quizzes to himself +% by using \cs{distrToInstrOff}, the default +% is \DescribeMacro\distrToStudentsOn\cs{distrToInstrOn}. +% \begin{macrocode} +\def\distrToInstrOn{\def\distrToInstr{true}}\distrToInstrOn +\def\distrToInstrOff{\def\distrToInstr{false}} +% \end{macrocode} +% (2019/08/26) Combined \cs{sadMultQuizzes} with \cs{sadQuizzes} +% \changes{v1.4.6}{2019/08/26}{Combined \string\cs{sadMultQuizzes} with +% \string\cs{sadQuizzes}} +% \begin{macrocode} +% \end{macrocode} +% \subsection{Working with multiple quizzes in one source} +% This section we develop some ideas of creating a single source file with multiple quizzes, +% these quizzes should be roughly equivalent. One such approach is to have a single quiz, +% and randomly permute the questions as well as randomly permute any MC or MS choice fields. +% \changes{v1.3}{2019/07/20}{Added multiple quizzes in one source} +% \begin{macrocode} +% \end{macrocode} +% \DescribeMacro\declareQuizBody\nmpsep{\darg{\ameta{name}}} This macro defines a +% verbatim environment with \ameta{name}. Such an environment cuts and saves its contents +% under the name of \texttt{\ameta{name}.cut}. It typically is designed to enclose +% the `body of a quiz,' the `quiz body' can then be input later using \cs{InputQuizBody}, define +% below. Associated with the declaration is a version number, \DescribeMacro\QzVer\cs{QzVer}, which +% may be used in the titles, refer to \texttt{thexrt.tex} in the \texttt{examples/misc} folder. +% \changes{v1.4.7}{2019/08/27}{Added version support for quiz bodies} +% \begin{macrocode} +\def\th@QzVer{0} +\def\QzVer{1} +\newcommand{\declareQuizBody}[1]{% + \bgroup\@tempcnta\th@QzVer\relax + \advance\@tempcnta\@ne + \edef\th@qbCnt{\the\@tempcnta}% + \csarg\xdef{#1-QzVer}{\th@qbCnt}\egroup + \csarg\def{#1}{\immediate\openout\CommentStream #1.cut + \let\verbatim@out\CommentStream + \immediate\write\verbatim@out{\string + \def\string\QzVer{\@nameuse{#1-QzVer}}}% + \verbatimwrite}% + \csarg\def{end#1}{\endverbatimwrite + \immediate\closeout\CommentStream}} +% \end{macrocode} +% \DescribeMacro\InputQuizBody\nmpsep{\darg{\ameta{name}}} +% We input a `quiz body' that has been earlier CUT and saved +% under the name of \texttt{\ameta{name}.cut}. +% \changes{v1.4}{2019/08/11}{Changes to \string\cs{InputBodyQuiz} +% to support solution sets} +% \begin{macrocode} +\newcounter{th@qzCnt} +\def\theth@qzCnt{\alph{th@qzCnt}} +\newcommand{\InputQuizBody}[1]{\newpage %\thPageOne + \@ifundefined{thisQuizOrig}{\edef\thisQuizOrig{\thisQuiz} + \let\Hy@EveryPageAnchor\relax}{}\stepcounter{th@qzCnt}% + \edef\x{\thisQuizOrig\theth@qzCnt}\expandafter + \th@DeclareQuiz\expandafter{\x}% + \renewcommand\sqslsecrunhead{}% + \InputIfFileExists{#1.cut}{}{} +% \end{macrocode} +% Before we include quiz solutions, we close the \cs{quiz@solns} stream. +% \begin{macrocode} + \immediate\closeout\quiz@solns %\th@QzHeaderLS + \let\eq@normallheader\relax + \newpage + \@ifundefined{ps@webheadings}{% + \def\th@QzHeaderL{\th@QzHeaderLS}% + \def\th@QzHeaderC{\th@QzHeaderCS}% + }{% + \lheader{\th@QzHeaderLS}% + \cheader{\th@QzHeaderCS}% + } + \includequizsolutions*\relax + \global\therearequizsolutionsfalse + \renewcommand\sqslsecrunhead{\eq@sqslsecrunhead}% + \eq@noformstrue +% \end{macrocode} +% Putting \cs{eq@noformtrue} assures us that the solution file will not be +% input a |\end{document}|. Next, we open a new quiz solution file stream +% so the another rendition to write solutions to a fresh file. +% \begin{macrocode} + \immediate\openout \quiz@solns \jobname.qsl + \@ifundefined{ps@webheadings}{% + \def\th@QzHeaderL{\th@QzHeaderLQ}% + \def\th@QzHeaderC{\th@QzHeaderCQ}% + }{% + \lheader{\th@QzHeaderLQ}% + \cheader{\th@QzHeaderCQ}% + }% +} +% \end{macrocode} +% \subsection{Building quizzes with \tops{\protect\env}{}{makeClassFiles} \& \tops{\protect\cs}{\textbackslash}{sadQuizzes}} +% Central to this whole process is building customized quizzes. This done by the +% \cs{sadQuizzes} expanded within the \env{makeClassFiles} environment.\medskip +% +% \noindent\DescribeEnv{makeClassFiles} is an \env{execJS} environment, the base name has been +% preset to be \texttt{mcfthor}. The contents of this environment is \cs{sadQuizzes}. +% Beginning the 2019/07/15 of \pkg{insdljs}, \env{execJS} has an option argument +% that is used to pass a command to the \texttt{.djs} file. We use this to make +% special definitions to support \DescribeMacro\oct\cs{oct} and \DescribeMacro\u\cs{u}. +% \changes{v1.1.9}{2019/07/15}{Added optional argument \string\cs{mkClFlsSpcls}} +% +% \begin{macrocode} +\def\mkClFlsSpcls{\let\oct\eqbs\let\u\relax} +\newenvironment{makeClassFiles}{% +\execJS[\mkClFlsSpcls]{mcfthor}}{\endexecJS} +% \end{macrocode} +% \DescribeMacro\sadQuizzes (save and distribute quizzes) +% is a script for the \env{makeClassFiles} environment. +% \changes{v1.4.6}{2019/08/26}{Renamed \string\cs{sadMultQuizzes} to +% \string\cs{sadQuizzes}, removed old \string\cs{sadQuizzes}.} +%\begin{verbatim} +%\begin{makeClassFiles} +%\sadQuizzes +%\end{makeClassFiles} +%\begin{document} +%... +%\end{verbatim} +%The above is placed just above |\begin{document}|. The script populates, for each entry in the +%\cs{classEntries} array, the \texttt{Name.first} and \texttt{Name.last} fields with the student's +%first and last name. It then saves a copy of the document to the instructor's folder under the name +%\texttt{\string\jobname-\ameta{first-name}\_\ameta{last-name}}. It does the same thing for the +%student's private folder. Finally, it clears the \texttt{Name} fields, and saves itself to the +%source folder. The script may be redefined in the preamble of the document using the +%\env{defineJS*} environment. The script also deals with solution and cover pages. +% \begin{macrocode} +\def\setClassArray{\ifClassEntries + \classEntries\else\classEntriesDef\fi} +\def\setArrayLength{\ifbasicmethods0\else lst.length\fi} +\def\setfilesuffix{\ifuseclassOpt"-"+fN+"_"+lN\else + \ifbasicmethods""\else"-"+(i+1)\fi\fi+".pdf"} +\begin{defineJS}[\def\defineJSjsR{^^J}\let\u\relax + \catcode`\@=0\relax]{\sadQuizzes} +% \end{macrocode} +% If \cs{autoCopyOff}, then this script does nothing +% \begin{macrocode} +if(@bFlattenState) + this.addScript({ + cName: "thorshammer: Do not flatten", + cScript:"var _flattenThisDoc=false;" + }); +if (@autoCopy) { +% \end{macrocode} +% \textbf{JavaScript variables common to building quizzes} +% \begin{macrocode} + var bUseClass=@bUseClass; + var reRmFn=new RegExp(this.documentFileName,"i"); + var instrPath=@InstrPath; + var cLast=instrPath[instrPath.length-1]; + if (cLast=="/") + instrPath=instrPath.substring(0,instrPath.length-1); + var classPath=@ClassPath; + cLast=classPath[classPath.length-1]; + if (cLast=="/") + classPath=classPath.substring(0,classPath.length-1); + var thInstrFS="@thInstrFS"; + var thClassFS="@thClassFS"; + var isthereCvrPg=@thIsCP; + var cvrPgNum="@thCvrPg"; + console.println("autocopy "+((@autoCopy)?"on":"off")); + var retn; + var solnSuffix=""; + var oSolnSuffix=new Object; + var parentoDoc=this; + var workingFolder=this.path; + var pos=workingFolder.lastIndexOf("/"); + workingFolder=workingFolder.substring(0,pos+1); + var _workingFolder=""; + // console.println("working folder: " + workingFolder); + var willSaveScript='isAQuizUnfinishedAtSave();\r' + +'if (oRecordOfQuizData !=undefined) collectQuizData();'; + var oHSD=this.getField("holdScoreData"); + var Rect=oHSD.rect; + this.removeField("holdScoreData"); + var hsdFmt='if(typeof oRecordOfQuizData=="undefined")\r\t\ + oRecordOfQuizData=new Object;'; + var restQD='@restoreQD'; +% \end{macrocode} +% \textbf{Cover page or pages.} Determine if there are cover pages, if yes, extract it and save it +% to the instructor's folder. Cover pages are declared in the preamble with +% the command \cs{DeclareCoverPage}, the argument of which is either a single number (usually 0) +% of a range of zero-based page numbers. +% \begin{macrocode} + if(isthereCvrPg) {// -------- extract cover pages ------------ + var aCvrPgRng=cvrPgNum.split("-"); + if (aCvrPgRng[0]=="") { + console.println("Start Range not specified, using 0 instead"); + var bPg=0; + } else var bPg=aCvrPgRng[0]; + var ePg=(aCvrPgRng.length>1)?aCvrPgRng[1]:aCvrPgRng[0]; + var oDoc=aebTrustedFunctions(this,aebExtractPages, + {nStart: bPg, nEnd: ePg}); + // save cover page(s) to the instructor folder + _workingFolder=(@InstrPathFull)?"":workingFolder; + aebDocSaveAs.msg="Cannot access the local folder " + + _workingFolder+instrPath+"/@jobname-cvrpg.pdf"; + var retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thInstrFS,cPath: _workingFolder+instrPath+"/@jobname-" + +"cvrpg.pdf",bCopy:false}); + oDoc.dirty=false; + oDoc.closeDoc(true); + // delete cover page before continuing, will reinsert it later + this.deletePages({nStart: bPg, nEnd: ePg}); + this.dirty=false; + } +// ------- end cover page code -------------- + var nQz=aQuizzesInDoc.length; // number of quizzes this doc +% \end{macrocode} +% \textbf{Solution pages.} Before getting into generating the customized quizzes for the class, we must +% first see if there are any solutions in this document, if so, we separate +% the solution page(e) from the quiz. +% \begin{macrocode} + var bOkBasicSolns=false; + var f=this.getField("thsolns4"); + if (f != null ) { + console.println("There are solutions"); + bOkBasicSolns=true; +% \end{macrocode} +% Save the solution suffixes for later use +% \begin{macrocode} + var g=f.getArray(); + for (var i=0; i + var oDoc=aebTrustedFunctions(this,aebExtractPages, + {nStart: bPg, nEnd: ePg}); + // save + _workingFolder=(@InstrPathFull)?"":workingFolder; + aebDocSaveAs.msg="Cannot access the local folder " + + _workingFolder+instrPath+"/@jobname-"+solnSuffix+".pdf"; + var retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thInstrFS,cPath: _workingFolder+instrPath+"/@jobname-" + +solnSuffix+".pdf",bCopy:false}); + // close + oDoc.dirty=false; + oDoc.closeDoc(true); + // delete solution page before continuing + this.deletePages({ + nStart: bPg, + nEnd: ePg}); + this.dirty=false; + } + } + } +// ------ begin creating custom quizzes for class members ------ + var cnt=0; // determines which quiz to generate + var lst=new Array(@setClassArray); + var l=(bUseClass)?@setArrayLength:1; // dps + for (var i=0; i < l; i++) { + var qzName=aQuizzesInDoc[cnt]; +// console.println("Working on " + qzName); + var fN=lst[i][0]; + var lN=lst[i][1]; + var folder=lst[i][2]; + var isAbsPth=lst[i][3]; // dps + if (folder!="")folder+="/"; + // pre-populate with the student's name + this.getField("Name.first").value=fN; + this.getField("Name.last").value=lN; + // extract quiz +// var f=this.getField("Name.first."+cnt); + var f=this.getField("bMrkQz."+cnt); + var bPg=f.page; +// var f=this.getField("Name.first."+(cnt+1)); + var f=this.getField("bMrkQz."+(cnt+1)); + var ePg=(f==null)?(this.numPages-1):(f.page-1); +% \end{macrocode} +% \textbf{Extraction:} We extract a quiz from the master document. Extracting +% causes some problems: the restore quiz data is lost, the WillSave event is +% lost, and the \texttt{holdScoreData} field is lost. We try to overcome this +% problems. +% \begin{macrocode} + // ------------- extraction of quiz pages -------------- + if(bUseClass)var oDoc=aebTrustedFunctions(this,aebExtractPages, + {nStart: bPg, nEnd: ePg}); + else oDoc=this; // dps +% \end{macrocode} +% Restore the \textsf{WillSave} event. +% \begin{macrocode} + // extracting preserves doc JS but not doc actions + oDoc.setAction({cTrigger: "WillSave", cScript: willSaveScript}); +% \end{macrocode} +% We have had problems with \texttt{oRecordOfQuizData} is \texttt{undefined}, +% to (finally) overcome this, we place some code at the document level. +% \begin{macrocode} + oDoc.addScript({ + cName: "oRecordOfQuizData Obj Declaration", cScript: hsdFmt}); +% \end{macrocode} +% The \texttt{holdScoreData} is on the first page of the document, this first +% page may not survive on the extracted pages, so we place this text field +% and the top of each of the first pages of the extracted quizzes. +% \begin{macrocode} + var oDocHSD=oDoc.addField({ + cName: "holdScoreData", + cFieldType: "text", + nPageNum: 0, + oCoords: Rect + }); +% \end{macrocode} +% Create a page open action to execute the restore quiz data +% \begin{macrocode} + oDoc.setPageAction({ + nPage: 0, + cTrigger: "Open", + cScript: restQD + }); +% \end{macrocode} +% We save custom info to each of the files being saved: \texttt{StudentPath} +% has the path to the students' folders and \texttt{cFS} is the file system. +% These two are used by `protect and distribute'. +% \begin{macrocode} + oDoc.info.qzBaseName="@jobname"; + if(isAbsPth) // dps + oDoc.info.StudentPath=folder; + else + oDoc.info.StudentPath=classPath+"/"+folder; + var bOkSolns=(typeof oSolnSuffix[qzName]!="undefined"); + if(bOkSolns) oDoc.info.SolnSet=oSolnSuffix[qzName]; + oDoc.info.SolnPath=_workingFolder+instrPath+"/"; + if(isthereCvrPg) oDoc.info.CvrPg="cvrpg"; + oDoc.info.cFS=thInstrFS; +% \end{macrocode} +% \textbf{Insert cover page, if any} +% \changes{v1.4.2}{2019/08/22}{Insert cover page in \string\cs{sadQuizzes}} +% \changes{v1.4.17}{2019/10/03}{Saved path to cover page} +% \begin{macrocode} + // Insert cover page, if any. + if (isthereCvrPg) { + if (typeof bCVMsg == "undefined") { + console.println("Inserting cover page from " + + _workingFolder+instrPath+"/@jobname-cvrpg.pdf"); + var bCVMsg=true; + } + if (cnt==0) var _cvrPath=_workingFolder+instrPath; + aebTrustedFunctions(oDoc,aebInsertPages, + {nPage: -1, + cPath: _cvrPath+"/@jobname-cvrpg.pdf"}); + } + var filesuffix=@setfilesuffix; + // Now save this as a copy +% \end{macrocode} +% \textbf{Instructor's folder:} Save a copy to the instructor's folder +% \begin{macrocode} + if(bUseClass) { + _workingFolder=(@InstrPathFull)?"":workingFolder; + aebDocSaveAs.msg="Cannot access the local folder " + + _workingFolder+instrPath+"/@jobname-"+fN+"_"+lN+".pdf"; + if(@distrToInstr) retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thInstrFS, + cPath: _workingFolder+instrPath+"/@jobname"+filesuffix, + bCopy:true}); +% \end{macrocode} +% \textbf{Student's folder:} Save a copy to the student's folder +% \changes{v1.4.17}{2019/10/03}{Defined \string\texttt{\_workingFolderC} to avoid +% redefinition of \string\texttt{\_workingFolder}} +% \begin{macrocode} + var _workingFolderC=(@ClassPathFull)?"":workingFolder; + if(isAbsPth) + var cPath=folder+"@jobname"+filesuffix; + else + var cPath=_workingFolderC+classPath+"/"+folder + +"@jobname"+filesuffix + aebDocSaveAs.msg="Cannot access the path "+ cPath; + if(@distrToStudents) retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thClassFS, + cPath: cPath, + bCopy:true}); + oDoc.dirty=false; + oDoc.closeDoc(true); + } + cnt=++cnt % nQz + } +} +this.resetForm(["Name"]); +console.println("automatically saving this file..."); +% \end{macrocode} +% Remove the following line\\ +%|// this.oRecordOfQuizData=undefined;| +% \begin{macrocode} +% \end{macrocode} +% \textbf{Save the source document:} Finally, save any changes +% that have occurred source document. Before saving, we make +% some adjustments in the case this is the basic method case. +% \begin{macrocode} +var toSa=app.setTimeOut("aebTrustedFunctions(this,aebSaveAs);\ +app.clearTimeOut(toSa);",50); +\end{defineJS} +\let\sadMultQuizzes\sadQuizzes +\let\rasSolns\sadQuizzes +% \end{macrocode} +% \begin{macrocode} +% +%<*container> +% \end{macrocode} +% \section{Batch support files} +% These files are designed for a workflow wherein the \opt{usebatch} +% option is taken. This option, though largely symbolic, declares the instructor +% is going to use a batch sequence to process the students' quizzes, after they +% have taken the quiz and returned to the instructor. +% A custom batch file \texttt{Thor's way} was written for this purpose. +% +% \paragraph*{\textsf{Thor's way}.}\hskip-\lastskip\space +% This batch sequence is run after the instructor has +% has a final look at each quiz (additional markup needed in the case of essay questions +% and assigning a final mark. the batch sequence performs a number of actions, +% for each quiz file selected, it acquires minimal quiz data (first name, last name, +% number of points awarded, total points, and final mark. +%\changes{v1.2}{2019/07/16}{Added batch support files} +% \subsection{The container file for Thor's way} +% This file should be brought into \app{Acrobat}, its fields filled, and the button pushed. It sets +% global JavaScript variables \texttt{global.qzName} and \texttt{global.gradedPath}. +% \changes{v1.3.1}{2019/07/20}{container: Push now closes the container} +% \begin{macrocode} +\documentclass{article} +\usepackage[designi]{web} +\usepackage{eforms} +\hypersetup{pdfpagemode=UseAttachments} +%% \previewOn\pmpvOn +\parindent0pt \parskip6pt +\begin{defineJS}{\pbContainer} +var f=this.getField("qzName"); +if(typeof global.RcrdData=="undefined") + global.RcrdData=1; +% \end{macrocode} +% If the `\textsf{Record class data}' box is checked we create a new attachment to receive the data; +% otherwise, no new attachment file is created. +% \begin{macrocode} +if(global.RcrdData) { + global.qzName=f.value; + if (global.qzName=="") { + f.value="qzData"; + global.qzName="qzData.txt"; + } else global.qzName=f.value+".txt"; + var d=this.dataObjects; + if (d!=null) { + for(var i=0; i< d.length; i++) + this.removeDataObject(d[i].name); + } + this.createDataObject({ + cName: global.qzName, + cValue: "First\\tSecond\\tPoints\\tTotal\\tGrade" + }); +} +var _path=this.path; +var pos=_path.lastIndexOf("/"); +global.containerPath=_path.substring(0,pos+1); +var f=this.getField("gradedPath"); +var v=f.value; +var pos=v.indexOf(":"); +if(pos!=-1||v[0]=="/") global.gradedPath=v; +else global.gradedPath=global.containerPath+v; +aebTrustedFunctions(this,aebSaveAs); +this.closeDoc(true); +\end{defineJS} +% \end{macrocode} +% (2019/11/21) Put JS for Clear Btn in \env{defineJS} environment +% \changes{v1.5.2}{2019/11/21}{Put JS for Clear Btn in \string\env{defineJS}} +% \begin{macrocode} +\begin{defineJS}{\clrContainer} +this.resetForm(["qzName","gradedPath"]); +try{ +% \end{macrocode} +% (2019/11/21) Fixed a bug with exception thrown +% \changes{v1.5.2}{2019/11/21}{Fixed a bug with exception thrown} +% \begin{macrocode} + if (typeof global.qzName!="undefined") + delete global.qzName; global.qzName=""; + if (typeof global.gradedPath!="undefined") + delete global.gradedPath; global.gradedPath=""; + if (typeof global.appndSolns!="undefined") + delete global.appndSolns; global.appndSolns=true; + if (typeof global.RcrdDat!="undefined") + delete global.RcrdDat; global.RcrdDat=true; +} catch(e){} +\end{defineJS} +\begin{document} +This file contains the quiz data as an attachment. Before you +start the batch action \textsf{Thor's way}, build and +\emph{place this file in the class folder of the instructor}. +\begin{center} +\begin{tabular}{rl} +\pushButton[\TU{Fill in the two fields then push this button +before starting the batch sequence}\CA{Push}\AAmouseup{\pbContainer} +]{pbContainer}{}{13bp}&% +\parbox[c]{1.5in}{\textField[\TU{Enter base name of the file that +stores quiz results}]{qzName}{1.5in}{13bp}\vcgBdry[3bp] +\textField[\TU{The path to the folder that will hold the graded +quizzes, it may be a relative or an absolute path} +]{gradedPath}{1.5in}{13bp}}\cgBdry[\columnsep]%\makebox[0pt][l] +{\pushButton[\CA{Clear} + \AAmouseup{\clrContainer}]{clear}{}{13bp}}\\[12pt] + \checkBox[\V{Yes}\DV{Yes}\AAmouseup{% + global.appndSolns=(event.target.isBoxChecked(0)); +}]{AppdSolns}{11bp}{11bp}{Yes}&% +\rlap{Append solutions, if they exist}\\[6pt] +\checkBox[\V{Yes}\DV{Yes}\AAmouseup{% + global.RcrdData=(event.target.isBoxChecked(0)); +}]{RecordData}{11bp}{11bp}{Yes}&% +\rlap{Record class data} +\end{tabular} +\end{center} +Fill in the base name of the file in the text field above. After +you push the button, the file is saved, then start +\textsf{Thor's way} action. After the batch sequence finishes, +this file is opened again. Open the attachments panel and save +the attached file. The file just saved is a tab delimited text +file that can be opened in Microsoft Excel. +\end{document} +% +%<*bterminate> +% \end{macrocode} +% \subsection{The batch termination file} +% When running \pkg{Thor's way}, it is important that \texttt{terminate-batch.pdf} is the last +% file processed by the batch. The batch test each file initially, if the current file being process, +% the batch exits `gracefully', otherwise, the batch processes the current file. The role +% \texttt{terminate-batch.pdf} plays it that it is detected by the batch, it performs no actions. +% \begin{macrocode} +\documentclass{article} +\usepackage[designi]{web} +\parindent0pt\parskip6pt +\begin{document} +\null\vfil +\begin{center} +\fbox{\begin{minipage}{.67\linewidth} +This file is the last to be processed by \textsf{Thor's way}, +the batch action identifies it and gracefully terminates. +\end{minipage}} +\end{center} +\vfil +\end{document} +% +% \end{macrocode} +% \begin{macrocode} +%<*package> +% \end{macrocode} +% \section{Configuration files} +% \subsection{Class configureation} +% It was suggested by Loki that we should be able to have a configuration file +% for the class. In the case an instructor has several classes, this is a great +% convenience.\medskip\par\noindent +% \DescribeMacro\InputClassData\nmpsep{\darg{\ameta{base-name}}} Input the class file +% with name \texttt{\ameta{base-name}.cfg}. The class configuration file (\texttt{\ameta{base-name}.cfg}) consists +% of a series of declarations of the form, +% \begin{quote}\ttfamily +% \string\instrPath\darg{\ameta{path}}\\ +% \string\classPath\darg{\ameta{path}}\\ +% \string\classMember*\darg{\ameta{first-name}}\darg{\ameta{last-name}}\darg{\ameta{folder}}\\ +% ... +% \end{quote} +% where the \texttt* is optionally included. +% \begin{macrocode} +\def\InputClassData#1{\def\InputCl@ssData{#1}\mkClFlsSpcls + \InputIfFileExists{#1.cfg} + {\PackageInfo{thorshammer}{Inputting class file #1.cfg}} + {\PackageWarning{thorshammer} + {Cannot find the class file #1.cfg}}} +% \end{macrocode} +% \DescribeMacro\InputFormattedClass\nmpsep{[\ameta{\cs{cmd}}]\darg{\ameta{base-name}}} +% We define a more general input method. +% The format for the class configuration file is as follows: +% \begin{quote}\ttfamily +% \string\instrPath\darg{\ameta{path}}\\ +% \string\classPath\darg{\ameta{path}}\\ +% \string\bClassData\\ +% \ameta{entry1}\\ +% \ameta{entry2}\\ +% ... +% \end{quote} +% Prior to \cs{bClassData}, the entries are passed through, so you can, for example, +% set the \cs{instrPath} and \cs{classPath} here. After \cs{bClassData} comes a series +% of lines, one each student. Each line (\ameta{entry}) should be marked up so it can be parsed and information +% extracted; at the minimum, each line should contain \ameta{first-name}, \ameta{last-name}, +% and \ameta{folder}, with possibly more. The default for \ameta{\cs{cmd}} is \cs{classMember}. +% For each line following \cs{bClassData}, \ameta{\cs{cmd}} is placed in front of each entry +% like so, \ameta{\cs{cmd}}\ameta{entry}. +% +% The first optional argument is the command (\ameta{\cs{cmd}}) that parses each line. +% The end purpose of the command is to construct a data structure, +% \begin{quote}\ttfamily +% \string\classMember*\darg{\ameta{first-name}}\darg{\ameta{last-name}}\darg{\ameta{folder}} +% \end{quote} +% A simple example is the following (filename is \texttt{myclassroll.cfg}): +%\begin{verbatim} +% \instrPath{myClass} +% \classPath{/z/Users/thor/myClass} +% \bClassData +% {Peter}{Pan}{A} +% *{J\"{u}rgen}{Loki}{B} +% {Thors}{Hammer}{C} +%\end{verbatim} +%We can then input this CFG file with \cs{InputFormattedClass\darg{myclassroll}}. +% For each line after \cs{bClassData}, the default \ameta{\cs{cmd}} is placed in front; +% for example, the first two lines of class data become |\classMember{Peter}{Pan}{A}| +% and |\classMember*{J\"{u}rgen}{Loki}{B}|, and so on. +% \begin{macrocode} +\newcommand\InputFormattedClass[2][\classMember]{\ClassEntriestrue + \begingroup + \mkClFlsSpcls + \endlinechar=-1 + \let\procThisLine\relax + \let\bClassData\relax + \let\re@dOK\dl@YES + \newread\fmtclass + \immediate\openin\fmtclass=#2.cfg + \loop + \read\fmtclass to \classmember + \ifeof\fmtclass\let\re@dOK\dl@NO + \else + \expandafter + \ifx\classmember\endinput\let\re@dOK\dl@NO + \else + \ifx\classmember\@empty %\let\procThisLine\relax + \else + \expandafter\procThisLine\classmember + \expandafter\ifx\classmember\bClassData +% \end{macrocode} +% After we process the current line, if this line is \cs{bClassData}, +% we switch over to \texttt{\#1} as the definition of +% \cs{procThisLine}. +% \begin{macrocode} + \def\procThisLine{#1}\fi + \fi + \fi + \fi + \ifx\re@dOK\dl@YES\repeat + \immediate\closein\fmtclass + \endgroup +} +% \end{macrocode} +% \subsection{Load the configuration file} +% \changes{v1.3.7}{2019/08/11}{fixed typo in loading cfg} +% \begin{macrocode} +\def\th@InputCFG{\InputIfFileExists{thorshammer.cfg} + {\PackageInfo{thorshammer} + {Inputting the configuration file}} + {\PackageInfo{thorshammer} + {No configuration file found}}} +\ifx\th@loadCFG\dl@YES\expandafter\th@InputCFG\fi +% \end{macrocode} +% \begin{macrocode} +% \end{macrocode} +% \begin{macrocode} +\catcode`\"=\th@dquoteCat +% +% \end{macrocode} +%\Finale diff --git a/texmf-dist/source/latex/thorshammer/thorshammer.ins b/texmf-dist/source/latex/thorshammer/thorshammer.ins new file mode 100644 index 00000000..06434d0d --- /dev/null +++ b/texmf-dist/source/latex/thorshammer/thorshammer.ins @@ -0,0 +1,62 @@ +%% +%% This file will generate fast loadable files and documentation +%% driver files from the doc files in this package when run through +%% LaTeX or TeX. +%% +%% Copyright 1999-2012 D. P. Story +%% +%% This file is part of the `AcroTeX eDucation Bundle'. +%% ------------------------------------------- +%% +%% It may be distributed under the conditions of the LaTeX Project Public +%% License, either version 1.2 of this license or (at your option) any +%% later version. The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.2 or later is part of all distributions of LaTeX +%% version 1999/12/01 or later. +%% +%% --------------- start of docstrip commands ------------------ +%% +\def\filedate{2020/01/13} +\def\batchfile{thorshammer.ins} + +\input docstrip +\ifx\generate\undefined + \Msg{**********************************************} + \Msg{*} + \Msg{* This installation requires docstrip} + \Msg{* version 2.4 or later.} + \Msg{*} + \Msg{* An older version of docstrip has been input} + \Msg{*} + \Msg{**********************************************} + \errhelp{Move or rename old docstrip.tex and get a newer one.} + \errmessage{Old docstrip in input path} + \batchmode + \csname @@end\endcsname\end +\fi + +\keepsilent +\askforoverwritefalse +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\preamble +\endpreamble + +\generate +{% + \file{thorshammer.sty}{\from{thorshammer.dtx}{copyright,package}} + \file{container.tex}{\from{thorshammer.dtx}{container}} + \file{terminate-batch.tex}{\from{thorshammer.dtx}{bterminate}} +} + +\Msg{***************************************************************} +\Msg{*} +\Msg{* \space To finish the installation you have to copy the files } +\Msg{*} +\Msg{* \space *.sty, *.cfg and *.def into a directory searched by TeX} +\Msg{*} +\Msg{***************************************************************} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\endinput diff --git a/texmf-dist/tex/latex/thorshammer/thorshammer.cfg b/texmf-dist/tex/latex/thorshammer/thorshammer.cfg new file mode 100644 index 00000000..2b59b360 --- /dev/null +++ b/texmf-dist/tex/latex/thorshammer/thorshammer.cfg @@ -0,0 +1,52 @@ +% +% Configuration file for Thor's Hammer +% +\pwdInstrFldTU{Enter password to mark this quiz} +\markQzFldCA{Mark It} +\markQzFldTU{Press to mark this quiz} +\freezeQuizFldTU{Make all fields readonly, cannot be undone} +\freezeQuizFldCA{Freeze Quiz} +\essayQFldTU{Assign points to extended responses} +\completeMsgFldV{Congratulations, you have completed the quiz, + before doing anything else, you need to save this document.} +\ShrtPtsFldFmt{"Short Pts: "+event.value} +\LngPtsFldFmt{"Long Pts: "+event.value} +\TotalsFldFmt{"Total: "+event.value+" \eqOutOf "% ++NPointTotal} +\NoNumEnteredMsg{"You did not enter a number, enter a nonnegative number only"} +\TooMuchCreditMsg{"You've assigned too much credit for this problem, assigning the maximum instead"} +% caption and tool tip for \stuSaveBtn +\stuSaveBtnCA{Save} +\stuSaveBtnTU{Press to save and close the document} +% verify ending the quiz +\EndQzWarningMsg{"When you end the quiz, you cannot change +any of your answers without starting the quiz over from the +beginning.\n\n +Press \\"Yes\\" to end the quiz."} +\ThorsAlertTitle{"Thor's Hammer"} +% beginning of quiz warning if no name fields +\InitQzMsg{"You cannot begin the quiz before entering + your first and last names in the fields provided.\n\n + Enter the name as you are known in the class; otherwise, + you will receive no credit for your work."} +% +\instrSaveFldTU{Save and close this file to the current folder} +\instrSaveFldCA{Save \string& Close} +% +% Other definitions +% +\thQHFirstName{First name:} +\thQHLastName{Last name:} +\thQHPoints{Points:} +\thQHGrade{Grade:} +\MarkWarningMsg{"You did not award the student a final mark.\ + \\n\\nAward the mark and then save."} +% Second save warning, appears on dismissal of Save As dialog +\SecondSaveMsg{"Alert! This document has not been saved, do not + exit before saving!"} + + + + + + diff --git a/texmf-dist/tex/latex/thorshammer/thorshammer.sty b/texmf-dist/tex/latex/thorshammer/thorshammer.sty new file mode 100644 index 00000000..a2571433 --- /dev/null +++ b/texmf-dist/tex/latex/thorshammer/thorshammer.sty @@ -0,0 +1,1100 @@ +%% +%% This is file `thorshammer.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% thorshammer.dtx (with options: `copyright,package') +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% thorshammer.sty package, %% +%% Copyright (C) 2020 D. P. Story %% +%% dpstory@uakron.edu dpstory@acrotex.net %% +%% %% +%% 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. %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{thorshammer} + [2020/01/13 v1.5.7 Support commands for Thor's way] +\RequirePackage{xkeyval} +\edef\th@dquoteCat{\the\catcode`\"} +\catcode`\"=12\relax +\DeclareOptionX{nocfg}{\let\th@loadCFG\dl@NO} +\let\th@loadCFG\dl@YES +\newif\ifthtestmode\thtestmodefalse +\DeclareOptionX{testmode}{\thtestmodetrue} +\DeclareOptionX{!testmode}{\thtestmodefalse} +\newif\ifthordinary \thordinaryfalse +\DeclareOptionX{ordinary}{\thtestmodetrue\thordinarytrue} +\newif\ifbasicmethods\basicmethodstrue +\newif\ifuseclassOpt\useclassOptfalse +\def\bUseClass{false} +\DeclareOptionX{useclass}{\useclassOpttrue + \def\bUseClass{true}\basicmethodsfalse +} +\newif\ifth@allowfreeze \th@allowfreezetrue +\DeclareOptionX{usebatch}{\th@allowfreezefalse + \ExecuteOptionsX{useclass}} +\DeclareOptionX{batchdistr}{\ExecuteOptionsX{usebatch}% + \AtEndOfPackage{\distrToStudentsOff + \let\distrToStudentsOff\relax\let\distrToStudentsOff\relax}} +\ProcessOptionsX +\edef\thOrdQz{\ifthordinary true\else false\fi} +\RequirePackage{insdljs}[2019/08/06] +\ifx\usedAdbFuncs\dl@NO + \def\inputAltAdbFncs{\InputIfFileExists{altadbfncs.def}% + {\PackageInfo{insdljs}{Inputting code for usealtadobe option}}% + {\PackageWarning{insdljs}{Cannot find altadbfncs.def.\MessageBreak + Reinstall or refresh your file name database.}}}% + \let\usedAdbFuncs\dl@YES +\else + \let\inputAltAdbFncs\relax +\fi +\inputAltAdbFncs +\RequirePackage{exerquiz}[2019/08/13] +\RequirePackage{eq-save}[2019/08/07] +\let\execjs\dl@YES +\@ifundefined{CommentStream}{\newwrite\CommentStream}{} +\def\csarg#1#2{\expandafter#1\csname#2\endcsname} +\providecommand{\eqSP}{\string\040} +\def\thPageOne{\setcounter{page}{1}} +\def\setInitMag#1{\setkeys{thim}{mag=#1}} +\define@choicekey+{thim}{mag}[\val\nr]% + {fitpage,actualsize,fitwidth,fitheight,% + fitvisible,inheritzoom}[fitpage]% + {\edef\th@initmag{\@nameuse{dl@\val}}} + {\PackageWarning{thorshammer}{% + Bad choice for initial magnification,\MessageBreak + permissible values are fitpage, actualsize,\MessageBreak + fitwidth, fitheight, fitvisible, and\MessageBreak + inheritzoom. Try again}} +\def\th@initmag{\dl@fitpage} +\addToDocOpen{\JS{% + var stmot=app.setTimeOut("this.calculate=false;",100);}} +\addToDocOpen{\GoToD[\Page{1}\th@initmag]} +\def\instrPathIsCHTTP{\def\thInstrFS{CHTTP}} +\let\thInstrFS\@empty +\newcommand\instrPath{\@ifstar + {\gdef\InstrPathFull{false}\instrPath@i} + {\gdef\InstrPathFull{true}\instrPath@i}} +\def\instrPath@i#1{\gdef\InstrPath{"#1"}} +\def\InstrPathFull{true} +\def\InstrPath{this.path.replace(reRmFn,"")} +\def\classPathIsCHTTP{\def\thClassFS{CHTTP}} +\let\thClassFS\@empty +\newcommand\classPath{\@ifstar + {\gdef\ClassPathFull{false}\classPath@i} + {\gdef\ClassPathFull{true}\classPath@i}} +\def\classPath@i#1{\gdef\ClassPath{"#1"}} +\def\ClassPath{this.path.replace(reRmFn,"")} +\def\ClassPathFull{true} +\def\thQzHeaderL#1{\def\th@QzHeaderLQ{\makebox[0pt][l]{#1}}} +\def\th@QzHeaderL{\th@QzHeaderLQ} +\thQzHeaderL{Thor's Class} +\def\th@QzHeaderLS{\th@HeaderOffset\th@QzHeaderLQ} +\def\thQzHeaderCQ#1{\def\th@QzHeaderCQ{\makebox[0pt][c]{#1}}} +\thQzHeaderCQ{Quiz \thQuizName} +\def\th@QzHeaderC{\th@QzHeaderCQ} +\def\thQzHeaderCS#1{\def\th@QzHeaderCS{\makebox[0pt][c]{#1}}} +\thQzHeaderCS{Solutions: \thQuizName} +\def\thQzHeaderR#1{\def\t@hQzHeaderR{\makebox[0pt][r]{#1}}} +\thQzHeaderR{\thepage} +\@ifundefined{ps@webheadings}{% + \def\th@setHeaders{% + \renewcommand{\@oddhead}{\th@QzHeaderL\hfil\th@QzHeaderC\hfil + \t@hQzHeaderR}\renewcommand{\@evenhead}{\@oddhead}}% +}{% + \def\th@setHeaders{% + \lheader{\th@QzHeaderL}% + \cheader{\th@QzHeaderC}% + \rheader{\t@hQzHeaderR}}% +} +\def\eq@normallheader{% + \@ifundefined{ps@webheadings}{% + \def\th@QzHeaderL{\th@QzHeaderLS}% + \def\th@QzHeaderC{\th@QzHeaderCS}% + }{% + \lheader{\th@QzHeaderLS}% + \cheader{\th@QzHeaderCS}% + } +} +\def\rhPgNumsOnly{\thQzHeaderL{}\thQzHeaderCQ{}\thQzHeaderCS{}} +\AtBeginDocument{\th@setHeaders} +\newif\ifthCoverPage \thCoverPagefalse +\newcommand{\DeclareCoverPage}[1]{\thCoverPagetrue + \def\thIsCP{true}\def\thCvrPg{#1}} +\def\thIsCP{false}\def\thCvrPg{0} +\@onlypreamble\DeclareCoverPage +\def\useNameToCustomize{\def\thUseNameToCustomize{true}} +\def\thUseNameToCustomize{false} +\def\enumQuizzes#1{\def\bUseClass{true}\basicmethodsfalse + \ClassEntriestrue\def\ClassPathFull{true}\def\InstrPathFull{true}% + \def\ClassPath{this.path.replace(reRmFn,"")}% + \def\InstrPath{this.path.replace(reRmFn,"")}% + \bgroup\@tempcnta#1\relax + \@whilenum\@tempcnta>\z@\do{\classMember{}{}{}% + \advance\@tempcnta\m@ne}\egroup + \def\thEnumQuizzes{#1}\def\bEnumQuizzes{true}} +\def\thEnumQuizzes{0}\def\bEnumQuizzes{false} +\newcommand{\distrQuizzes}{% + \ifuseclassOpt + \def\th@next{\PackageWarning{thorshammer} + {Use have specified the useclass option or higher\MessageBreak + yet you employ \string\distrQuizzes, these are\MessageBreak + incompatible. Assuming the specified package option}}% + \else + \let\th@next\th@distrQuizzes + \fi\th@next +} +\def\th@distrQuizzes{\def\bUseClass{true}\basicmethodsfalse + \ClassEntriestrue\bgroup\@makeother\_\th@distrQuizzes@i} +\def\rmSTAR#1*\@nil{\def\@folder{#1}} +\def\tstForSTAR#1*#2*\@nil{\def\@rgi{#1}\ifx\@rgi\@empty + \def\ISSTAR{*}\rmSTAR#2\@nil\else\let\ISSTAR\@empty\fi}% +\def\th@distrQuizzes@i#1{\@tempcnta\z@ + \@tfor\@folder:=#1\do{\advance\@tempcnta\@ne + \expandafter\tstForSTAR\@folder**\@nil + \edef\x{\noexpand\classMember{}{}\ISSTAR{\@folder}}\x + }\xdef\enumQuizzes{\the\@tempcnta}% + \gdef\bDistrQuizzes{true}\egroup +} +\def\bDistrQuizzes{false} +\@ifundefined{executeSave} + {\def\executeSave(){% + console.println("automatically saving this file...");^^J% + var retn=aebTrustedFunctions(this,aebDocSaveAs,% + {cPath:this.path,bCopy:false})}}{} +\@ifundefined{docassembly} + {\newenvironment{docassembly}{% + \execJS[\mkClFlsSpcls]{docassembly}}{\endexecJS}} + {\renewenvironment{docassembly}{% + \execJS[\mkClFlsSpcls]{docassembly}}{\endexecJS}} +\ifbasicmethods\let\th@namePresets\@empty\else +\def\th@namePresets{\Ff\FfReadOnly\BC{}}\fi +\newcommand\FirstName[3][]{\th@bMrkQz\textField[% + \presets{\th@namePresets}#1]{Name.first}{#2}{#3}} +\newcommand\LastName[3][]{\textField[% + \presets{\th@namePresets}#1]{Name.last}{#2}{#3}} +\def\th@bMrkQz{\@ifundefined{bMrkQz\currQuiz} + {\rlap{\textField[\Ff\FfReadOnly\BC{}\BG{}]{bMrkQz}{0pt}{0pt}}% + \@namedef{bMrkQz\currQuiz}{}}{}} +\def\th@fullnamePresets{\Ff\FfReadOnly\BG{}\BC{}} +\def\thfullnameFmt#1{\def\th@fullnameFmt##1##2{#1}} +\thfullnameFmt{#1+" "+#2} +\newcommand{\FullName}[3][]{\textField[% + \presets{\th@fullnamePresets}#1\AAcalculate{% + var fName=this.getField("Name.first").value;\r + var lName=this.getField("Name.last").value;\r + event.value=\th@fullnameFmt{fName}{lName};}]{FullName}{#2}{#3}} +\def\pwdInstrFldTU#1{\def\pwdInstrFld@TU{#1}} +\pwdInstrFldTU{Enter password to mark this quiz} +\newcommand{\pwdInstrFld}[4][]{% opts, pwd, wd, ht + \@ifundefined{\currQuiz-nQs}{\def\nQs{0}} + {\edef\nQs{\@nameuse{\currQuiz-nQs}}}% + \textField[\cmd{\bParams{\currQuiz}{\nQs}{"#2"}\eParams} + \Ff\FfPassword\AAkeystroke{\pwdKeyJS} + \protect\AA\protect\Ff\TU{\pwdInstrFld@TU}#1% +]{pwdtxt}{#3}{#4}} +\def\markQzFldCA#1{\def\markQzFld@CA{#1}} +\markQzFldCA{Mark It} +\def\markQzFldTU#1{\def\markQzFld@TU{#1}} +\markQzFldTU{Press to mark this quiz} +\newcommand{\markQz}[3][]{% + \@ifundefined{\currQuiz-nQs}{\def\nQs{0}}% + {\edef\nQs{\@nameuse{\currQuiz-nQs}}}% + \makebox[0pt][l]{\textField[\BC{}\BG{}\H{S}\AAformat{% + var f=this.getField("MarkIt");\r + var g=this.getField("freezeQz");\r + if(typeof _thorshammer!="undefined" && _thorshammer){\r\t + if(f!=null)f.display=display.visible;\r\t +} else{\r\t + if(f!=null)f.display=display.hidden;\r\t + if(g!=null)g.display=display.hidden;\r +}}]{hideTxtFldMI}{0pt}{0pt}}% + \pushButton[\cmd{\bParams{\currQuiz}{\nQs}\eParams}\F\FHidden + \AAmouseup{\commonPassKey}\CA{\markQzFld@CA} + \TU{\markQzFld@TU}\protect\AA\protect\F#1% + ]{MarkIt}{#2}{#3}} +\def\freezeQuizFldTU#1{\def\freezeQuizFld@TU{#1}} +\freezeQuizFldTU{Make all fields readonly, cannot be undone} +\def\freezeQuizFldCA#1{\def\freezeQuizFld@CA{#1}} +\freezeQuizFldCA{Freeze Quiz} +\newcommand\freezeQuiz[3][]{\pushButton[\cmd{\let\%\defjsLB} + \CA{\freezeQuizFld@CA}\F\FHidden + \TU{\freezeQuizFld@TU}\AAmouseup{freezeQuizMU()} + \protect\AA\protect\F + #1]{freezeQz}{}{11bp}} +\def\instrSaveFldTU#1{\def\instrSaveFld@TU{#1}} +\instrSaveFldTU{Save and close this file to the current folder} +\def\instrSaveFldCA#1{\def\instrSaveFld@CA{#1}} +\instrSaveFldCA{Save \string& Close} +\newcommand\instrSave[3][]{\pushButton[% + \CA{\instrSaveFld@CA}\F\FHidden + \TU{\instrSaveFld@TU}\AAmouseup{% + var f=this.getField("studentenGrade");\r + var str=""+f.value;\r + str=str.replace(/\string\s/g,"");\r + if (str=="")\r\t + app.alert("You did not award the student a final mark." + +"\\n\\nAward the mark and then save.");\r + else {\r\t + aebTrustedFunctions(this,aebSaveAs);\r\t + this.closeDoc(true);\r + }}\protect\AA\protect\F + #1]{freezeQz}{}{11bp}} +\AtEndOfPackage{\ifth@allowfreeze\let\freezeOrSave\freezeQuiz + \else\let\freezeOrSave\instrSave\fi} +\newcommand{\studentReport}[3][]{% + \textField[\BC{}\BG{}\F\FHidden\Ff\FfReadOnly\protect\Ff#1% + ]{studentenReport}{#2}{#3}} +\newcommand{\studentGrade}[3][]{\textField[\F\FHidden\protect\F + \BC{red}\BG{}\Q1\textSize{12}\textColor{blue} + \AAkeystroke{event.change=event.change.toUpperCase()}#1% + ]{studentenGrade}{#2}{#3}} +\def\thQHFirstName#1{\def\th@QHFirstName{\textbf{#1}\space}} +\thQHFirstName{First name:} +\def\thQHLastName#1{\def\th@QHLastName{\textbf{#1}\space}} +\thQHLastName{Last name:} +\def\thQHPoints#1{\def\th@QHPoints{\textbf{#1}\space}} +\thQHPoints{Points:} +\def\thQHGrade#1{\def\th@QHGrade{\textbf{#1}\space}} +\thQHGrade{Grade:} +\newcommand{\thQuizHeader}{\let\Hy@EveryPageAnchor\relax + \@ifstar{\thPageOne\thQuizHeaderLayout} + {\newpage\thPageOne\thQuizHeaderLayout}% +} +\newcommand\thQuizHeaderLayout{\noindent + \th@QHFirstName\FirstName{1.5in}{13bp}\vcgBdry[3pt] + \th@QHLastName\LastName{1.5in}{13bp}\vcgBdry[6pt] + \begin{minipage}[t]{1.2in}\kern0pt + \makebox[0pt][r]{\raggedleft\markQz{}{11bp}% + \hspace{\marginparsep}}% + \th@QHPoints\studentReport{\widthof{000/000}}{11bp}\vcgBdry[6pt] + \makebox[0pt][r]{\raggedleft\freezeOrSave{}{11bp}% + \hspace{\marginparsep}}% + \th@QHGrade\studentGrade{14bp}{14bp}\vcgBdry[6pt] + \end{minipage}\hfill + \begin{minipage}[t]{\linewidth-1em-1.2in}\kern0pt + \begin{sumryTblAux}{\currQuiz} + \displaySumryTbl[ntables=1,showmarkup]{\currQuiz} + \end{sumryTblAux} + \end{minipage}} +\def\completeMsgFldV#1{\def\completeMsgFld@V{#1}} +\completeMsgFldV{Congratulations, you have completed the quiz, + before doing anything else, you need to save this document.} +\newcommand{\completeMsgFld}[3][]{\textField[\F\FHidden\Ff\FfMultiline + \Ff\FfReadOnly\V{\completeMsgFld@V} + \DV{\completeMsgFld@V}]{postQzMsg}{#2}{#3}} +\def\ShrtPtsFldFmt{\bgroup\obeyspaces\ShrtPtsFldFmt@i} +\def\ShrtPtsFldFmt@i#1{\egroup\flJSStr[noquotes]{\ShrtPtsFld@Fmt}{#1}} +\ShrtPtsFldFmt{"Short Pts: "+event.value} +\newcommand{\ShrtPtsFld}[2][]{% + \PointsField[\AAformat{if(event.value!="") + event.value=\ShrtPtsFld@Fmt}\F\FHidden\protect\AA + \protect\F#1]{#2}} +\def\LngPtsFldFmt{\bgroup\obeyspaces\LngPtsFldFmt@i} +\def\LngPtsFldFmt@i#1{\egroup\flJSStr[noquotes]{\LngPtsFld@Fmt}{#1}} +\LngPtsFldFmt{"Long Pts: "+event.value} +\newcommand{\LngPtsFld}[2][]{% + \textField[\presets{\PointsFieldDefaults}\F\FHidden + \AAformat{if(event.value!="") event.value=\LngPtsFld@Fmt} + \AAcalculate{var f=this.getField("essayMrkUp");\r + if(f!=null)EFSimple_Calculate("SUM",% +new Array("essayMrkUp.\currQuiz"));} + ]{EssayField.\currQuiz}{\PtFW}{\DefaultHeightOfWidget}} +\def\TotalsFldFmt{\bgroup\obeyspaces\TotalsFldFmt@i} +\def\TotalsFldFmt@i#1{\egroup\flJSStr[noquotes]{\TotalsFld@Fmt}{#1}} +\TotalsFldFmt{"Total: "+event.value+"\space\eqOutOf\space"% ++NPointTotal} +\newcommand{\TotalsFld}[2][]{% + \textField[\presets{\PointsFieldDefaults}\F\FHidden + \AAformat{try{event.value=(\TotalsFld@Fmt)}catch(e){}} + \AAcalculate{EFSimple_Calculate("SUM",% +new Array("PointsField.\currQuiz","EssayField.\currQuiz"));\r + var\eqSP f=this.getField("studentenReport");\r + f.value=(1*event.value)+"\eqSP/\eqSP"+\theeqpointvalue; + }]{TotalsField.\currQuiz}{\PtFW}{\DefaultHeightOfWidget}} +\newcommand{\thQuizTrailer}{\raisebox{\baselineskip-\fboxsep}% + {\makebox[0pt][l]{\parbox[t]{3in}{\kern0pt + \completeMsgFld{3in}{3\baselineskip}}}}% + \makebox[0pt][l]{\hspace{3in}\quad + \ifthtestmode\CorrButton{\currQuiz}\else + \stuSaveBtn{}{11bp}\fi}\parbox[t]{3in} + {\ShrtPtsFld{\currQuiz}\vcgBdry[6pt] + \LngPtsFld{\currQuiz}\vcgBdry[6pt] + \TotalsFld{\currQuiz}}} +\def\essayQFldTU#1{\def\essayQFld@TU{#1}} +\essayQFldTU{Assign points to extended responses} +\def\EsW{33bp}\def\EsH{14bp} +\def\essayQ#1{\let\qMark@HookSave\qMark@Hook + \def\qMark@Hook{\makebox[0pt][r]{\smash + {\raisebox{-7bp+\fboxsep}{\stepcounter{questionno}\textField[% + \cmd{\bParams{#1}\eParams}\F\FHidden\Q{1} + \AAkeystroke{\essayQKey} + \AAformat{if(event.value!="") event.value=event.value + +((event.value==1)?" \eqptLabel":" \eqptsLabel")} + \TU{\essayQFld@TU} + ]{essayMrkUp.\currQuiz.\thequestionno}{\EsW}{\EsH}% + \addtocounter{questionno}{-1}}}}\global + \let\qMark@Hook\qMark@HookSave}} +\def\essayitem#1{\essayQ{#1}\item\PTs{#1}} +\begin{defineJS}[\catcode`\@=0\relax]{\pwdKeyJS} +if (event.willCommit) { + if (event.value==@p(3)) { + @commonPassKey + } +} +\end{defineJS} +\begin{defineJS}[\catcode`\@=0\relax]{\commonPassKey} +if(typeof aQuizzesInDoc=="undefined") + var aQuizzesInDoc=new Array(); +if (aQuizzesInDoc.indexOf("@oField")) + aQuizzesInDoc.push("@oField"); +if (typeof @oField=="undefined") + var @oField=new Object; +restoreQuizData(); +this.calculate=true; +var f=this.getField("postQzMsg"); +if (f!=null) f.display=display.hidden; +var f=this.getField("pbStuSvCl"); +if (f!=null) f.display=display.hidden; +var f=this.getField("ScoreField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("PointsField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("EssayField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("TotalsField.@p(1)"); +if (f!=null) f.display=display.visible; +var f=this.getField("essayMrkUp"); +if (f!=null) f.display=display.visible; +correctQuiz("@p(1)",@p(2)); +var f=this.getField("qzreset"); +if (f!=null) f.display=display.visible; +var f=this.getField("freezeQz"); +if (f!=null) f.display=display.visible; +var f=this.getField("studentenReport"); +if (f!=null) f.display=display.visible; +var f=this.getField("studentenGrade"); +if (f!=null) f.display=display.visible; +if (typeof correctSumryTbl == "function") + correctSumryTbl("@p(1)",@p(2)); +\end{defineJS} +\def\NoNumEnteredMsg#1{\flJSStr*[noquotes]{\cNoNumEnteredMsg}{#1}} +\NoNumEnteredMsg{"You did not enter a number, % +enter a nonnegative number only"} +\def\TooMuchCreditMsg#1{\flJSStr*[noquotes]{\cTooMuchCredit}{#1}} +\TooMuchCreditMsg{"You've assigned too much credit for this % +problem, assigning the maximum instead"} +\begin{defineJS}[\makeesc\@\catcode`\%=14\relax]{\essayQKey} +if (event.willCommit) { + var qpts=(1*event.value); + if (isNaN(qpts)) { + app.alert(@cNoNumEnteredMsg); + event.rc=false; + } else if (qpts<0) { + event.value=-1*event.value; + qpts=1*event.value; + } + if (event.rc) { + if (qpts > @p(1) ) { + app.alert(@cTooMuchCredit); + qpts=@p(1); + } + // update ProbDist array + ProbDist[@thequestionno]=qpts; + // see if table is present + if (typeof correctSumryTbl == "function") { + f=this.getField("% +@dlcombine(@currQuiz)(SanityCheckPts).@thequestionno"); + var thesePts= qpts + (( qpts == 1 )?% +" @eqptLabel":" @eqptsLabel"); + f.value=thesePts; + // add color + var cb=this.getField("% +@dlcombine(@currQuiz)(SanityCheck).@thequestionno"); + if (qpts==@p(1)) cb.strokeColor=@rghtColorJS; + else if (qpts>0) cb.strokeColor=@partialColorJS; + else cb.strokeColor=@wrngColorJS; + } + event.value=qpts; + } +} +\end{defineJS} +\def\instrAutoSaveOn{\def\instrAutoSave{true}} +\def\instrAutoSaveOff{\def\instrAutoSave{false}} +\instrAutoSaveOn +\def\instrAutoCloseOn{\def\instrAutoClose{true}} +\instrAutoCloseOn +\def\instrAutoCloseOff{\def\instrAutoClose{false}} +\def\MarkWarningMsg#1{\dlJSStr*[noquotes]{\MarkWarning@Msg}{#1}} +\MarkWarningMsg{"You did not award the student a final mark.\ + \\n\\nAward the mark and then save."} +\def\flattenOn{\def\bFlattenState{false}} +\def\flattenOff{\def\bFlattenState{true}} +\ifbasicmethods\flattenOff\else\flattenOn\fi +\begin{insDLJS}{jsforthor}{thorshammer: Freeze/Save Doc} +var sndSaveWarning=\SecondSave@Msg; +var isthereCvrPg=\thIsCP; +var cvrPgNum="\thCvrPg"; +function freezeQuizMU() { +var f, fname; +var bOK=true; +var f=this.getField("studentenGrade"); +var str=""+f.value; +str=str.replace(/\s/g,""); +if (str=="") { + app.alert(\MarkWarning@Msg); + bOK=false; +} +var SolnSet=this.info.SolnSet; +if (bOK&&SolnSet!=""){ +var SolnPath=this.info.SolnPath; +// var SolnSet=this.info.SolnSet; +var qzbasename=this.info.qzBaseName; + aebTrustedFunctions(this,aebInsertPages,{ + nPage: (this.numPages-1), + cPath: SolnPath+"/"+qzbasename+"-"+SolnSet+".pdf" + }) +}; +if(\instrAutoSave&&bOK) { +// var cSave="\jobname"; + var docFN=this.documentFileName; + docFN=docFN.substring(0,docFN.length-4); + var cSave=(\thUseNameToCustomize)?"\jobname":docFN; + if(\thUseNameToCustomize) { + var f=this.getField("Name.first"); + if(f!=null)cSave+=("-"+f.value+"_"); + f=this.getField("Name.last"); + if(f!=null)cSave+=(f.value); + cSave+=("-g"); + } + var oRetn=aebTrustedFunctions(this,aebBrowseForDoc,{bSave:true,% +cFilenameInit: cSave }); + bOK=(typeof oRetn=="object"); + if(bOK) { + for (var i=0; i0\relax + \FncyHdrsFmtNoTitleQuiz\fi\else + \aebTitleQuiz\protect\ + \ifnum\@eqquestiondepth=0\else\\\relax + \FncyHdrsFmtQuestion\fi + \fi %\space + \ifcase\@eqquestiondepth + \ifx\aebTitleQuiz\@empty\FncyHdrsFmtNoTitleQuiz\fi + \or + \string\llap{\arabic{eqquestionnoi}.\space}% + \or + \string\llap{\arabic{eqquestionnoi}.\space}% + (\alph{eqquestionnoii})\space + \or + \string\llap{\arabic{eqquestionnoi}.\space}% + (\alph{eqquestionnoii})% + (\roman{eqquestionnoiii})\space + \fi +} +\dclrFncyQzHdrsFmt{\myFQHFmt} +\let\ReturnTo\@gobbletwo +\let\bWebCustomize\endinput +\let\eWebCustomize\relax +\providecommand{\inputWebCfg}{% + \let\bWebCustomize\relax + \let\eWebCustomize\endinput + \let\ExecuteOptions@SAVE\ExecuteOptions + \let\ExecuteOptions\@gobble + \makeatletter + \InputIfFileExists{web.cfg}{}{}\makeatother + \let\ExecuteOptions\ExecuteOptions@SAVE + \let\bWebCustomize\endinput + \let\eWebCustomize\relax +} +\def\classEntriesDef{["","","",false]} +\newif\ifClassEntries\ClassEntriesfalse +\let\classEntries\@gobble +\def\classMember{\ClassEntriestrue\@ifstar + {\let\th@star\ef@YES\classMember@i} + {\let\th@star\ef@NO\classMember@i}} +\newcommand\classMember@i[2]{% + \@ifstar{\let\th@exstar\ef@YES\classMember@ii{#1}{#2}} + {\let\th@exstar\ef@NO\classMember@ii{#1}{#2}}} +\newcommand\classMember@ii[3]{% + \ifx\th@exstar\ef@YES\def\AbsPth{true}\else + \def\AbsPth{false}\fi + \ifx\th@star\ef@NO + \ifx\th@exstar\ef@YES + \g@addto@macro\classEntries{,["#1","#2","#3",true]}\else + \g@addto@macro\classEntries{,["#1","#2","#3",false]}\fi + \else + \g@addto@macro\classEntries{,["}% + \pdfstringdef\x{#1}\expandafter + \g@addto@macro\expandafter\classEntries\expandafter{\x}% + \g@addto@macro\classEntries{","}% + \pdfstringdef\x{#2}\expandafter + \g@addto@macro\expandafter\classEntries\expandafter{\x}% + \g@addto@macro\classEntries{","}% + \pdfstringdef\x{#3}\expandafter + \g@addto@macro\expandafter\classEntries\expandafter{\x}% + \ifx\th@exstar\ef@YES + \g@addto@macro\classEntries{",true]}\else + \g@addto@macro\classEntries{",false]}\fi + \fi} +\def\autoCopyOn{\def\autoCopy{true}} +\def\autoCopyOff{\def\autoCopy{false}} +\autoCopyOn +\newcommand{\cFS}[1]{\def\@rgi{#1}\ifx\@rgi\@empty + \let\cFSth\@empty\else\def\cFSth{CHTTP}\fi} +\let\cFSth\@empty +\def\distrToStudentsOn{\def\distrToStudents{true}}\distrToStudentsOn +\def\distrToStudentsOff{\def\distrToStudents{false}} +\def\distrToInstrOn{\def\distrToInstr{true}}\distrToInstrOn +\def\distrToInstrOff{\def\distrToInstr{false}} +\def\th@QzVer{0} +\def\QzVer{1} +\newcommand{\declareQuizBody}[1]{% + \bgroup\@tempcnta\th@QzVer\relax + \advance\@tempcnta\@ne + \edef\th@qbCnt{\the\@tempcnta}% + \csarg\xdef{#1-QzVer}{\th@qbCnt}\egroup + \csarg\def{#1}{\immediate\openout\CommentStream #1.cut + \let\verbatim@out\CommentStream + \immediate\write\verbatim@out{\string + \def\string\QzVer{\@nameuse{#1-QzVer}}}% + \verbatimwrite}% + \csarg\def{end#1}{\endverbatimwrite + \immediate\closeout\CommentStream}} +\newcounter{th@qzCnt} +\def\theth@qzCnt{\alph{th@qzCnt}} +\newcommand{\InputQuizBody}[1]{\newpage %\thPageOne + \@ifundefined{thisQuizOrig}{\edef\thisQuizOrig{\thisQuiz} + \let\Hy@EveryPageAnchor\relax}{}\stepcounter{th@qzCnt}% + \edef\x{\thisQuizOrig\theth@qzCnt}\expandafter + \th@DeclareQuiz\expandafter{\x}% + \renewcommand\sqslsecrunhead{}% + \InputIfFileExists{#1.cut}{}{} + \immediate\closeout\quiz@solns %\th@QzHeaderLS + \let\eq@normallheader\relax + \newpage + \@ifundefined{ps@webheadings}{% + \def\th@QzHeaderL{\th@QzHeaderLS}% + \def\th@QzHeaderC{\th@QzHeaderCS}% + }{% + \lheader{\th@QzHeaderLS}% + \cheader{\th@QzHeaderCS}% + } + \includequizsolutions*\relax + \global\therearequizsolutionsfalse + \renewcommand\sqslsecrunhead{\eq@sqslsecrunhead}% + \eq@noformstrue + \immediate\openout \quiz@solns \jobname.qsl + \@ifundefined{ps@webheadings}{% + \def\th@QzHeaderL{\th@QzHeaderLQ}% + \def\th@QzHeaderC{\th@QzHeaderCQ}% + }{% + \lheader{\th@QzHeaderLQ}% + \cheader{\th@QzHeaderCQ}% + }% +} +\def\mkClFlsSpcls{\let\oct\eqbs\let\u\relax} +\newenvironment{makeClassFiles}{% +\execJS[\mkClFlsSpcls]{mcfthor}}{\endexecJS} +\def\setClassArray{\ifClassEntries + \classEntries\else\classEntriesDef\fi} +\def\setArrayLength{\ifbasicmethods0\else lst.length\fi} +\def\setfilesuffix{\ifuseclassOpt"-"+fN+"_"+lN\else + \ifbasicmethods""\else"-"+(i+1)\fi\fi+".pdf"} +\begin{defineJS}[\def\defineJSjsR{^^J}\let\u\relax + \catcode`\@=0\relax]{\sadQuizzes} +if(@bFlattenState) + this.addScript({ + cName: "thorshammer: Do not flatten", + cScript:"var _flattenThisDoc=false;" + }); +if (@autoCopy) { + var bUseClass=@bUseClass; + var reRmFn=new RegExp(this.documentFileName,"i"); + var instrPath=@InstrPath; + var cLast=instrPath[instrPath.length-1]; + if (cLast=="/") + instrPath=instrPath.substring(0,instrPath.length-1); + var classPath=@ClassPath; + cLast=classPath[classPath.length-1]; + if (cLast=="/") + classPath=classPath.substring(0,classPath.length-1); + var thInstrFS="@thInstrFS"; + var thClassFS="@thClassFS"; + var isthereCvrPg=@thIsCP; + var cvrPgNum="@thCvrPg"; + console.println("autocopy "+((@autoCopy)?"on":"off")); + var retn; + var solnSuffix=""; + var oSolnSuffix=new Object; + var parentoDoc=this; + var workingFolder=this.path; + var pos=workingFolder.lastIndexOf("/"); + workingFolder=workingFolder.substring(0,pos+1); + var _workingFolder=""; + // console.println("working folder: " + workingFolder); + var willSaveScript='isAQuizUnfinishedAtSave();\r' + +'if (oRecordOfQuizData !=undefined) collectQuizData();'; + var oHSD=this.getField("holdScoreData"); + var Rect=oHSD.rect; + this.removeField("holdScoreData"); + var hsdFmt='if(typeof oRecordOfQuizData=="undefined")\r\t\ + oRecordOfQuizData=new Object;'; + var restQD='@restoreQD'; + if(isthereCvrPg) {// -------- extract cover pages ------------ + var aCvrPgRng=cvrPgNum.split("-"); + if (aCvrPgRng[0]=="") { + console.println("Start Range not specified, using 0 instead"); + var bPg=0; + } else var bPg=aCvrPgRng[0]; + var ePg=(aCvrPgRng.length>1)?aCvrPgRng[1]:aCvrPgRng[0]; + var oDoc=aebTrustedFunctions(this,aebExtractPages, + {nStart: bPg, nEnd: ePg}); + // save cover page(s) to the instructor folder + _workingFolder=(@InstrPathFull)?"":workingFolder; + aebDocSaveAs.msg="Cannot access the local folder " + + _workingFolder+instrPath+"/@jobname-cvrpg.pdf"; + var retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thInstrFS,cPath: _workingFolder+instrPath+"/@jobname-" + +"cvrpg.pdf",bCopy:false}); + oDoc.dirty=false; + oDoc.closeDoc(true); + // delete cover page before continuing, will reinsert it later + this.deletePages({nStart: bPg, nEnd: ePg}); + this.dirty=false; + } +// ------- end cover page code -------------- + var nQz=aQuizzesInDoc.length; // number of quizzes this doc + var bOkBasicSolns=false; + var f=this.getField("thsolns4"); + if (f != null ) { + console.println("There are solutions"); + bOkBasicSolns=true; + var g=f.getArray(); + for (var i=0; i + var oDoc=aebTrustedFunctions(this,aebExtractPages, + {nStart: bPg, nEnd: ePg}); + // save + _workingFolder=(@InstrPathFull)?"":workingFolder; + aebDocSaveAs.msg="Cannot access the local folder " + + _workingFolder+instrPath+"/@jobname-"+solnSuffix+".pdf"; + var retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thInstrFS,cPath: _workingFolder+instrPath+"/@jobname-" + +solnSuffix+".pdf",bCopy:false}); + // close + oDoc.dirty=false; + oDoc.closeDoc(true); + // delete solution page before continuing + this.deletePages({ + nStart: bPg, + nEnd: ePg}); + this.dirty=false; + } + } + } +// ------ begin creating custom quizzes for class members ------ + var cnt=0; // determines which quiz to generate + var lst=new Array(@setClassArray); + var l=(bUseClass)?@setArrayLength:1; // dps + for (var i=0; i < l; i++) { + var qzName=aQuizzesInDoc[cnt]; +// console.println("Working on " + qzName); + var fN=lst[i][0]; + var lN=lst[i][1]; + var folder=lst[i][2]; + var isAbsPth=lst[i][3]; // dps + if (folder!="")folder+="/"; + // pre-populate with the student's name + this.getField("Name.first").value=fN; + this.getField("Name.last").value=lN; + // extract quiz +// var f=this.getField("Name.first."+cnt); + var f=this.getField("bMrkQz."+cnt); + var bPg=f.page; +// var f=this.getField("Name.first."+(cnt+1)); + var f=this.getField("bMrkQz."+(cnt+1)); + var ePg=(f==null)?(this.numPages-1):(f.page-1); + // ------------- extraction of quiz pages -------------- + if(bUseClass)var oDoc=aebTrustedFunctions(this,aebExtractPages, + {nStart: bPg, nEnd: ePg}); + else oDoc=this; // dps + // extracting preserves doc JS but not doc actions + oDoc.setAction({cTrigger: "WillSave", cScript: willSaveScript}); + oDoc.addScript({ + cName: "oRecordOfQuizData Obj Declaration", cScript: hsdFmt}); + var oDocHSD=oDoc.addField({ + cName: "holdScoreData", + cFieldType: "text", + nPageNum: 0, + oCoords: Rect + }); + oDoc.setPageAction({ + nPage: 0, + cTrigger: "Open", + cScript: restQD + }); + oDoc.info.qzBaseName="@jobname"; + if(isAbsPth) // dps + oDoc.info.StudentPath=folder; + else + oDoc.info.StudentPath=classPath+"/"+folder; + var bOkSolns=(typeof oSolnSuffix[qzName]!="undefined"); + if(bOkSolns) oDoc.info.SolnSet=oSolnSuffix[qzName]; + oDoc.info.SolnPath=_workingFolder+instrPath+"/"; + if(isthereCvrPg) oDoc.info.CvrPg="cvrpg"; + oDoc.info.cFS=thInstrFS; + // Insert cover page, if any. + if (isthereCvrPg) { + if (typeof bCVMsg == "undefined") { + console.println("Inserting cover page from " + + _workingFolder+instrPath+"/@jobname-cvrpg.pdf"); + var bCVMsg=true; + } + if (cnt==0) var _cvrPath=_workingFolder+instrPath; + aebTrustedFunctions(oDoc,aebInsertPages, + {nPage: -1, + cPath: _cvrPath+"/@jobname-cvrpg.pdf"}); + } + var filesuffix=@setfilesuffix; + // Now save this as a copy + if(bUseClass) { + _workingFolder=(@InstrPathFull)?"":workingFolder; + aebDocSaveAs.msg="Cannot access the local folder " + + _workingFolder+instrPath+"/@jobname-"+fN+"_"+lN+".pdf"; + if(@distrToInstr) retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thInstrFS, + cPath: _workingFolder+instrPath+"/@jobname"+filesuffix, + bCopy:true}); + var _workingFolderC=(@ClassPathFull)?"":workingFolder; + if(isAbsPth) + var cPath=folder+"@jobname"+filesuffix; + else + var cPath=_workingFolderC+classPath+"/"+folder + +"@jobname"+filesuffix + aebDocSaveAs.msg="Cannot access the path "+ cPath; + if(@distrToStudents) retn=aebTrustedFunctions(oDoc,aebDocSaveAs, + {cFS:thClassFS, + cPath: cPath, + bCopy:true}); + oDoc.dirty=false; + oDoc.closeDoc(true); + } + cnt=++cnt % nQz + } +} +this.resetForm(["Name"]); +console.println("automatically saving this file..."); +var toSa=app.setTimeOut("aebTrustedFunctions(this,aebSaveAs);\ +app.clearTimeOut(toSa);",50); +\end{defineJS} +\let\sadMultQuizzes\sadQuizzes +\let\rasSolns\sadQuizzes +\def\InputClassData#1{\def\InputCl@ssData{#1}\mkClFlsSpcls + \InputIfFileExists{#1.cfg} + {\PackageInfo{thorshammer}{Inputting class file #1.cfg}} + {\PackageWarning{thorshammer} + {Cannot find the class file #1.cfg}}} +\newcommand\InputFormattedClass[2][\classMember]{\ClassEntriestrue + \begingroup + \mkClFlsSpcls + \endlinechar=-1 + \let\procThisLine\relax + \let\bClassData\relax + \let\re@dOK\dl@YES + \newread\fmtclass + \immediate\openin\fmtclass=#2.cfg + \loop + \read\fmtclass to \classmember + \ifeof\fmtclass\let\re@dOK\dl@NO + \else + \expandafter + \ifx\classmember\endinput\let\re@dOK\dl@NO + \else + \ifx\classmember\@empty %\let\procThisLine\relax + \else + \expandafter\procThisLine\classmember + \expandafter\ifx\classmember\bClassData + \def\procThisLine{#1}\fi + \fi + \fi + \fi + \ifx\re@dOK\dl@YES\repeat + \immediate\closein\fmtclass + \endgroup +} +\def\th@InputCFG{\InputIfFileExists{thorshammer.cfg} + {\PackageInfo{thorshammer} + {Inputting the configuration file}} + {\PackageInfo{thorshammer} + {No configuration file found}}} +\ifx\th@loadCFG\dl@YES\expandafter\th@InputCFG\fi +\catcode`\"=\th@dquoteCat +\endinput +%% +%% End of file `thorshammer.sty'. -- cgit v1.2.3