summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/moodle
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/moodle
Initial commit
Diffstat (limited to 'macros/latex/contrib/moodle')
-rw-r--r--macros/latex/contrib/moodle/README.md50
-rw-r--r--macros/latex/contrib/moodle/moodle.dtx3316
-rw-r--r--macros/latex/contrib/moodle/moodle.ins57
-rw-r--r--macros/latex/contrib/moodle/moodle.pdfbin0 -> 306019 bytes
4 files changed, 3423 insertions, 0 deletions
diff --git a/macros/latex/contrib/moodle/README.md b/macros/latex/contrib/moodle/README.md
new file mode 100644
index 0000000000..e2ab4cd420
--- /dev/null
+++ b/macros/latex/contrib/moodle/README.md
@@ -0,0 +1,50 @@
+==============================================================================
+
+The `moodle' package v0.5
+Copyright (C) 2016 Anders Hendrickson (anders.hendrickson@snc.edu)
+
+This package allows dramatic highlighting of words and phrases
+by painting shapes around them. It is chiefly intended for
+use in Beamer presentations, but it can be used in other
+document classes as well.
+
+Changes:
+- 2016/01/11 Initial version
+
+==============================================================================
+
+This work may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3
+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.3 or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+
+
+==============================================================================
+
+ This work consists of the files:
+README (this file)
+moodle.dtx
+moodle.ins
+ and the derived file:
+moodle.sty
+
+ The distribution consists of the files:
+README (this file)
+moodle.dtx
+moodle.ins
+moodle.pdf (the user manual)
+
+-----------------------------------------------------------------
+
+ To install the package:
+- run: latex moodle.ins (which will generate moodle.sty)
+- Move moodle.sty to a location where LaTeX will find it (typically
+ in a local texmf tree at tex/latex/moodle) and refresh the
+ file database. See the FAQ on CTAN at help/uk-tex-faq or
+ http://www.tug.ac.uk/faq for more information on this.
+ To process the user manual
+- run: pdflatex moodle.dtx
+- run: pdflatex moodle.dtx
diff --git a/macros/latex/contrib/moodle/moodle.dtx b/macros/latex/contrib/moodle/moodle.dtx
new file mode 100644
index 0000000000..02b43f7923
--- /dev/null
+++ b/macros/latex/contrib/moodle/moodle.dtx
@@ -0,0 +1,3316 @@
+% \iffalse meta-comment
+%
+% moodle.dtx
+% Copyright 2016 by Anders O.F. Hendrickson (anders.hendrickson@snc.edu)
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% 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.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Anders O.F. Hendrickson.
+%
+% This work consists of the files moodle.dtx and moodle.ins
+% and the derived files moodle.sty and getitems.sty.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{moodle.dtx}
+%</driver>
+%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+%<package>\ProvidesPackage{moodle}
+%<*package>
+ [2016/01/11 v0.5 Moodle quiz XML generation]
+%</package>
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{moodle}
+\usepackage{amssymb}
+\usepackage{fancyvrb}
+\EnableCrossrefs
+\CodelineIndex
+\OnlyDescription
+\RecordChanges
+\begin{document}
+ \DocInput{moodle.dtx}
+ \PrintChanges
+ %\PrintIndex
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{3827}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \changes{v0.5}{2016/01/05}{Initial version}
+%
+% \GetFileInfo{moodle.sty}
+%
+% \DoNotIndex{\newcommand,\newenvironment,\def}
+%
+%
+% \title{The \textsf{moodle} package: \\
+% generating Moodle quizzes via \LaTeX%
+% \thanks{This document
+% corresponds to \textsf{moodle.sty}~\fileversion, dated \filedate.}}
+% \author{Anders Hendrickson\\ St.~Norbert College, De~Pere, WI, USA \\ \url{anders.hendrickson@snc.edu}}
+% \date{January 11, 2016}
+%
+% \maketitle
+%
+% \providecommand\TikZ{Ti\emph{k}Z}
+%
+% \section{Motivation}
+%
+% The acronym Moodle stands for ``Modular Object-Oriented Dynamic Learning Environment.''
+% It is an open source learning management system employed by many universities, colleges,
+% and high schools to provide digital access to course materials, such as
+% notes, video lectures, forums, and the like; see
+% \url{https://moodle.com/moodle-lms/} for more information.
+% One of the many useful
+% features of Moodle is that mathematical and scientific notation can be entered in
+% \LaTeX\ or \TeX\ code, which will be typeset either through a built-in \TeX\ filter
+% or by invoking MathJax.
+%
+% For instructors who want to give students frequent feedback,
+% but lack the time to do so, a particularly valuable module in Moodle
+% is the \emph{quiz}. A Moodle quiz can consist of several different types of
+% questions---not only multiple choice or true/false questions, but also
+% questions requiring a short phrase or numerical answer, and even essay
+% questions. All but the essay questions are automatically graded by the
+% system, and the instructor has full control over how often the quiz may be
+% attempted, its duration, and so forth. Feedback can be tailored to specific
+% mistakes the student makes.
+%
+% All these features make Moodle quizzes very useful tools for instructors
+% who have access to them.
+% Unfortunately, the primary way to create or edit a Moodle quiz
+% is through a web-based interface that can be slow to operate.
+% To users of \LaTeX, accustomed to the speed of typing source code on
+% a keyboard alone, the agonizing slowness of switching between mouse and keyboard
+% to navigate a web form with its myriad dropdown boxes, radio buttons,
+% compounded with a perceptible time lag as one's Moodle server responds to requests,
+% can produce a very frustrating experience. Moreover, editing is entirely
+% impossible without network access.
+%
+% Once the quiz is written, there is no easy way to view and proofread all the
+% information of which it is made. Each question is edited on a separate webpage,
+% which is so full of options that it cannot be viewed on a single screen.
+% An instructor has to spend much time checking over the newly created quiz in
+% order to be confident there are no errors.
+%
+% Added to all this is the frustration of managing graphics.
+% If a question requires an image---say, asking a calculus student to interpret
+% the graph of a function---the image must first be produced as a standalone file
+% (e.g., in JPG or PNG format), uploaded to Moodle, and then chosen in a web-based
+% HTML editor. Great is the vexation of the instructor who decided to alter a
+% question, as there are more and more possibilities of error whenever multiple
+% files must be kept synchronized.
+%
+% Users of \LaTeX\ are also accustomed to the speed and flexibility that
+% comes from defining their own macros, which may be as brief as writing
+% |\R| instead of |\mathbb{R}|
+% or as complex as macros that generate entire paragraphs of text.
+% The Moodle editor, by contrast, requires you to type |\mathbb{R}|
+% every single time you want $\mathbb{R}$.
+%
+% Finally, there is the question of archiving and reusing one's work.
+% Much, much work goes into creating Moodle quizzes, which then reside
+% on a Moodle server somewhere in the cloud in a format neither easily browsable
+% nor easily modifiable.
+%
+% \LaTeX\ itself has the power to solve all these difficulties:
+% it is swift to edit and swifter to compile a \LaTeX\ document,
+% and the PDF may be previewed onscreen or printed out for ease of proofreading.
+% Mathematical graphics can be integrated within the main file through \TikZ,
+% and of course \LaTeX\ macros can be customized.
+% Using the present \textsf{moodle.sty} package,
+% a quiz author can type a quiz using familiar \LaTeX\ syntax and document
+% structure. Upon compilation, \LaTeX\ will generate both a well-organized
+% PDF that is easy to proofread and an XML file that can be uploaded directly
+% to Moodle. The entire process is far faster than using Moodle's own
+% web-based editor, makes it easier to catch one's mistakes,
+% and the ultimate source code of one's work is a human-readable |.tex| file
+% that can be archived, browsed, and edited offline.
+%
+% \section{Workflow}
+% The process of creating a quiz in Moodle using this package is as follows:
+% \begin{enumerate}
+% \item Write a \LaTeX\ document using |\usepackage{moodle}| as described below.
+% \item Compile the document to PDF using pdf\LaTeX. This will also produce the file
+% \meta{jobname}|-moodle.xml|.
+% \item Open Moodle, navigate to the desired course,
+% and under ``Question bank'' select ``Import.''
+% \item Select ``Moodle XML format,'' choose the XML file to upload, and press ``Import.''
+% \item After Moodle verifies that the questions have been imported correctly,
+% you may add them to your quizzes.
+% \end{enumerate}
+%
+% \section{Usage}\label{sect:usage}
+% \subsection{Example Document}
+%
+% The following pages presume the reader already has some familiarity with creating
+% and editing Moodle quizzes through the web interface.
+% The |xkeyval| package is used to provide a key-value interface.
+% Here is a simple example document:
+% \begin{verbatim}
+% \documentclass[12pt]{article}
+% \usepackage{moodle}
+%
+% \begin{document}
+%
+% \begin{quiz}{My first quiz}
+% \begin{numerical}[points=2]{Basic addition}
+% What is $8+3$?
+% \item 11
+% \end{numerical}
+%
+% \begin{shortanswer}[case sensitive=true]{Newton's name}
+% What was Newton's first name?
+% \item Isaac
+% \item[fraction=0, feedback={No, silly!}] Fig
+% \item{fraction=0} Sir
+% \end{shortanswer}
+%
+% \begin{multi}[points=3]{A first derivative}
+% What is the first derivative of $x^3$?
+% \item $\frac{1}{4} x^4+C$
+% \item* $3x^2$
+% \item $51$
+% \end{multi}
+% \end{quiz}
+%
+% \end{document}
+% \end{verbatim}
+% Key features to note in this first example are that a |quiz| environment
+% contains several question environments.
+% Each question takes a name as a mandatory argument,
+% and it may also take optional key-value arguments within brackets.
+% The question environments resemble list environments
+% such as |itemize| or |enumerate|, in that answers are set off by
+% |\item|'s, but the question itself is the text that occurs before
+% the first |\item|.
+%
+% \DescribeMacro{draft}
+% If the package option |draft| is invoked, by calling |\usepackage[draft]{moodle}|,
+% then no XML file will be generated. This is especially useful while editing a quiz
+% containing graphics, so as to avoid the time spent converting image files.
+%
+% \newpage
+% \subsection{Quiz and Question Environments}
+%
+% \DescribeMacro{quiz}
+% A |.tex| document to generate Moodle quizzes contains one or more
+% |quiz| environments, within which various question environments are nested.
+% The required argument to the |quiz| environment names the ``question bank''
+% to which the questions inside will belong after being uploaded to moodle.
+% \begin{center}
+% |\begin{quiz}|\oarg{options}\marg{question bank name}%
+% \end{center}
+% There are no |quiz|-specific options,
+% but any \meta{options} set with |\begin{quiz}|
+% will be inherited by all questions contained within that |quiz| environment.
+%
+% \DescribeMacro{\moodleset}
+% Options may also be set at any time with |\moodleset|\marg{options};
+% these changes are local to \TeX-groups.
+% \bigskip
+%
+% The syntax for each question environment is
+% \begin{quote}
+% |\begin|\marg{question type}\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item| \meta{item} \\
+% \rule{2em}{0pt}\quad$\vdots$ \\
+% \rule{2em}{0pt}|\item| \meta{item} \\
+% |\end|\marg{question type}
+% \end{quote}
+% The meaning of the \meta{item}s varies depending on the question type,
+% but they usually are answers to the question.
+% Details will be given below.
+%
+% The following key-value options may be set for all questions:
+%
+% \DescribeMacro{points}\DescribeMacro{default grade}
+% By default, each question is worth 1 point on the quiz.
+% This may be changed with the |points| key or its synonym, |default grade|;
+% for example, |points=2| makes that question worth two points.
+%
+% \DescribeMacro{penalty}
+% The |penalty| is the fraction of points that is taken off for each wrong attempt;
+% it may be set to any value between 0 and 1.
+% The default is |penalty=0.10|.
+%
+% \DescribeMacro{fraction}
+% In most question types, it is possible to designate some answers as being
+% worth partial credit---that is, some fraction of a completely correct answer.
+% The |fraction| key may be set to any integer from |0| (entirely wrong) to |100| (entirely correct).
+%
+% \DescribeMacro{feedback}
+% The |feedback| key sets text that will appear to the student after completing the quiz.
+% For example, one might set
+% \begin{center}
+% |feedback={A question like this will appear on the exam.}|
+% \end{center}
+% The desired feedback should be included in braces.
+%
+% Two kinds of feedback can be given. If the |feedback| key is set for a
+% question, then that feedback will appear to each student regardless of the student's answer.
+% Answer-specific feedback (perhaps explaining a common mistake)
+% may also be given by setting the |feedback| key \emph{at the individual answer}.
+%
+% \newpage
+% \subsection{Question Types}
+%
+% We next discuss the various question types supported by \textsf{moodle.sty}
+% and the options that may be set.
+%
+% \subsubsection{Multiple Choice}
+%
+% \DescribeMacro{multi}
+% The syntax for a classic multiple choice question,
+% with only one correct answer, is as follows:
+% \begin{quote}
+% |\begin{multi}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item*| \meta{correct answer} \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{wrong answer} \\
+% \rule{2em}{0pt}\quad$\vdots$ \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{wrong answer} \\
+% |\end{multi}|
+% \end{quote}
+% The correct answer is designated by the asterisk |*| after the |\item|;
+% it need not appear first in the list.
+%
+%
+% \DescribeMacro{shuffle}
+% The boolean key |shuffle| determines whether Moodle will
+% rearrange the possible answers in a random order.
+% Setting |shuffle=false| will guarantee that the answer appear
+% in the order they were typed; the default is |shuffle=true|.
+%
+% \DescribeMacro{numbering}
+% Moodle offers different options for numbering the possible answers.
+% You may set the |numbering| key to any of the following values,
+% which mirror the usual \LaTeX\ syntax:
+% |alph|, |Alph|, |arabic|, |roman|, |Roman|, and |none|.
+% Calling |numbering=none| produces an unnumbered list of answers.
+% The Moodle syntax of |abc|, |ABC|, |123|, |iii|, and |IIII| is also acceptable,
+% but note that it requires \emph{four} |I|'s to obtain upper-case Roman numerals this way.
+%
+% \DescribeMacro{fraction}
+% The |fraction| key can be used to designate some wrong answers
+% as being worth partial credit. For example, a question might read thus:
+% \begin{verbatim}
+% \begin{multi}{my question}
+% Compute $\int 4x^3\,dx$.
+% \item* $x^4+C$
+% \item[fraction=50] $x^4$
+% \item $12x^2$
+% \end{multi}
+% \end{verbatim}
+% Thus the asterisk |*| is shorthand for |fraction=100|,
+% whereas a bare |\item| sets |fraction=0|.
+%
+% \DescribeMacro{single}\DescribeMacro{multiple}
+% By default, the |multi| environment produces
+% a multiple choice question operates with only one correct answer;
+% this is called |single| mode, and on Moodle it appears with radio buttons.
+% It is also possible to write questions with more than one correct answer,
+% asking the user to check all correct answers.
+% To do this, use the key |multiple| or |single=false|.
+%
+% The worth of each correct answers in |multiple| mode may be set by |fraction|,
+% but Moodle will require that all the fractions add up to at least 100.
+% If you simply designate each correct answer with |\item*|, then \textsf{moodle.sty}
+% will divide the 100\% equally among those answers.
+% For example, the following two examples produce equivalent results:
+% \begin{verbatim}
+% \begin{multi}[multiple]{my question}
+% Which numbers are prime?
+% \item* 5
+% \item 6
+% \item* 7
+% \item 8
+% \end{multi}
+% \end{verbatim}
+% \begin{verbatim}
+% \begin{multi}[multiple]{my question}
+% Which numbers are prime?
+% \item[fraction=50] 5
+% \item 6
+% \item[fraction=50] 7
+% \item 8
+% \end{multi}
+% \end{verbatim}
+%
+% \subsubsection{Numerical}
+%
+% A numerical question in Moodle requires the student
+% to input a real number in decimal form.
+% Its typical format is
+% \begin{quote}
+% |\begin{numerical}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{correct answer} \\
+% |\end{numerical}|
+% \end{quote}
+% If there is more than one correct answer, additional |\item|'s may be included.
+% Because this is not a multiple choice question, there is no need to provide
+% incorrect answers. There may nevertheless be reasons to include incorrect answers.
+% For example, partially correct answers may be specified by setting the |fraction| key.
+% Feedback for a common mistake may be given by including the incorrect answer like this:
+% \begin{quote}\footnotesize
+% |\item[fraction=0,feedback={You forgot to antidifferentiate!}]| \meta{incorrect answer}
+% \end{quote}
+%
+% \newpage
+% \subsubsection{Short Answer}
+% A short answer question resembles a numerical question: the student is to fill
+% in a text box with a missing word or phrase.
+% \begin{quote}
+% |\begin{shortanswer}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{correct answer} \\
+% \rule{2em}{0pt}\quad$\vdots$ \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{correct answer} \\
+% |\end{shortanswer}|
+% \end{quote}
+% You can make the text box appear as part of the question with the
+% control sequence |\blank|. For example,
+% your question might read
+% \begin{verbatim}
+% \begin{shortanswer}{Leibniz}
+% Newton's rival was Gottfried Wilhelm \blank.
+% \item Leibniz
+% \item Leibniz.
+% \end{shortanswer}
+% \end{verbatim}
+% Note that as the blank occurred at the end of a sentence,
+% we included two answers,
+% lest students get the question wrong merely by
+% including or omitting a period.
+%
+% \DescribeMacro{case sensitive}\DescribeMacro{usecase}
+% By default, Moodle ignores the distinction between upper- and lower-case letters
+% when grading a short answer question.
+% You can make a question case-sensitive with the key |case sensitive|
+% or its shorter synonym |usecase|.
+%
+% \subsubsection{Essay Questions}
+% Instructors may ask essay questions on a Moodle quiz,
+% although Moodle's software is not up to the task of grading them!
+% Instead each essay question answer must be graded manually by the
+% instructor or a teaching assistant.
+% \begin{quote}
+% |\begin{essay}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{notes for grader} \\
+% \rule{2em}{0pt}\quad$\vdots$ \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{notes for grader} \\
+% |\end{essay}|
+% \end{quote}
+% Instead of containing answers, the |\item| tags for the |essay| question
+% contain notes that will appear to whoever is grading the question manually.
+%
+% \DescribeMacro{response required}
+% Although Moodle cannot grade the content of an essay question,
+% it can at least determine whether the question has been left blank.
+% If the |response required| key is set, Moodle will insist that the student
+% enter something in the blank before accepting the quiz as completed.
+%
+% \newpage
+% \DescribeMacro{response format}
+% Moodle offers five different ways for students to enter and/or upload their
+% answers to an essay question. You may choose one of these five options:
+% \begin{description}
+% \item[{\tt html}] An editor with the ability to format HTML responses
+% including markup for italics, boldface, etc. This is the default.
+% \item[{\tt file}] A file picker allowing the student to upload a file, such as
+% a PDF or DOC file, containing the essay.
+% \item[{\tt html+file}] The same HTML editor as above, but with the ability
+% to upload files as well. This permits some students to type answers
+% directly into the web form, and others to compose their essays in
+% another program first.
+% \item[{\tt text}] This editor allows only for entering plain text without any markup.
+% \item[{\tt monospaced}] This yields a plain text editor, without any markup,
+% and with a fixed-width font. This could be useful for entering code snippets, for example.
+% \end{description}
+%
+% \DescribeMacro{response field lines}
+% The key |response field lines| controls the height of the input box.
+% The default is |response field lines=15|.
+%
+% \DescribeMacro{attachments allowed}
+% The |attachments allowed| key controls \emph{how many} attachments a student is
+% allowed to upload. Permissible values are |0|, |1|, |2|, |3|, or |unlimited|.
+%
+% \DescribeMacro{attachments required}
+% You may also require the student to upload a certain number of attachments
+% by setting |attachments required| to |0|, |1|, |2|, or |3|.
+%
+% \DescribeMacro{response template}
+% Finally, you may preload the essay question with a template that the student
+% will edit and/or type over, with the key |response template=|\marg{template}.
+% The \meta{template} should be enclosed in braces.
+%
+% \subsection{Matching Questions}
+%
+% A matching question offers a series of subquestions
+% and a set of possible answers from which to choose.
+% If there are $m$ questions and $n$ possible answers,
+% a matching question will look like this:
+%
+% \begin{quote}
+% |\begin{matching}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{question 1} |\answer| \meta{answer 1}\\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{question 2} |\answer| \meta{answer 2}\\
+% \rule{2em}{0pt}\quad$\vdots$ \\
+% \rule{2em}{0pt}|\item|\oarg{options} \meta{question $m$} |\answer| \meta{answer $m$}\\
+% \rule{2em}{0pt}|\item|\oarg{options} |\answer| \meta{answer $m+1$}\\
+% \rule{2em}{0pt}\quad$\vdots$ \\
+% \rule{2em}{0pt}|\item|\oarg{options} |\answer| \meta{answer $n$}\\
+% |\end{matching}|
+% \end{quote}
+% Answers $1$ through $m$ correspond to questions $1$ through $m$;
+% answers $m+1$ through $n$ are ``decoy'' answers.
+% If multiple questions should have the same answer,
+% be sure your typed answer match exactly, so that Moodle will not
+% create duplicate copies of the same answer!
+%
+% \DescribeMacro{shuffle}
+% The |matching| question accepts the option of |shuffle| to randomly
+% permute the questions and answers; by default |shuffle=true|.
+%
+% \DescribeMacro{drag and drop}\DescribeMacro{dd}
+% Moodle has two formats for matching questions.
+% The older matching question offered a dropdown box
+% for choosing the answer to each question;
+% the newer ``drag and drop matching'' format
+% shows all questions in one column,
+% all answers in a second column, and allows students to drag the correct
+% answer to the question using a mouse.
+% To enable drag-and-drop matching, use the key `|drag and drop|' or `|dd|' for
+% short. The default is |dd=false|. If you choose the older format,
+% then due to the limitations of dropdown boxes, no \LaTeX\ or HTML code can be used
+% in the answers.
+%
+% \subsection{Cloze Questions}
+%
+% A ``cloze question'' has one or more subquestions embedded within a passage of text.
+% For example, you might ask students to fill in several missing words within
+% a sentence, or calculate several coefficients of a polynomial.
+% To encode cloze questions in \LaTeX\ using this package is easy:
+% you simply nest one or more |multi|, |shortanswer|, or |numerical| environments
+% within a |cloze| environment, as in the following example:
+% \begin{verbatim}
+% \begin{cloze}{my cloze question} \\
+% Thanks to calculus, invented by Isaac
+% \begin{shortanswer}
+% \item Newton
+% \end{shortanswer},
+% we know that the derivative of $x^2$ is
+% \begin{multi}[horizontal]
+% \item $2x$
+% \item* $\frac{1}{3} x^3 + C$
+% \item $0$
+% \end{multi}
+% and that $\int_0^2 x^2\,dx$ equals
+% \begin{numerical}
+% \item[tolerance=0.0004] 2.667
+% \end{numerical}.
+% Thanks, Isaac!
+% \end{cloze}
+% \end{verbatim}
+% Note that when used as a subquestion within a cloze question,
+% |\begin{multi}| is \emph{not} followed by name in braces;
+% the same is true for the |shortanswer| and |numerical|
+% environments.
+%
+% \DescribeMacro{vertical}\DescribeMacro{horizontal}
+% Within a cloze question, by default a multiple choice question is implemented
+% as an inline dropdown box. This is visually compact, but it also prevents the
+% use of mathematical or HTML formatting.
+% Adding the option |vertical| displays the subquestion as a vertical column
+% of radio buttons instead; likewise the option |horizontal| creates a horizontal
+% row of radio buttons.
+%
+% \section{Conversion to HTML}
+%
+% Questions should be typed as usual for \LaTeX,
+% including |\$| to obtain dollar signs, |$|'s for math shifts,
+% |$$|'s for display math, et cetera.
+% The package \textsf{moodle.sty} automatically converts
+% this \LaTeX\ code into HTML for web display.
+%
+% The following table lists \LaTeX\ commands and environments that
+% will be converted to HTML:
+% \begin{center}
+% \begin{tabular}{lll}
+% |~| & |\#| & |\$| \\
+% |\&| & |\\| & |\S| \\
+% |\{| & |\}| & {\tt\catcode`\ =12\relax\catcode`\\=12\relax\ }\\
+% |\emph| & |\textbf| & |\par| \\
+% |\ldots| & |\dots| & |\relax| \\
+% |\euro| & |\texteuro| \\
+% |\begin{center}| \\
+% |\begin{enumerate}| \\
+% |\begin{itemize}| \\
+% |\begin{tikzpicture}| \\
+% \end{tabular}
+% \end{center}
+% Single and double quotation marks and the diacritical commands |\^|, |\'|, |\`|, |\"|, |\~|, and |\H| are also handled,
+% as are the characters |\aa|, |\ae|, |\o|, |\ss|, |\l|, and their capitalizations.
+%
+% In addition, |<| and |>| will be converted to |&lt;| and |&gt;| \emph{within math mode only}.
+% If they should be typed outside of math mode, they will be passed as typed to
+% the HTML, and probably interpreted by students' browsers as HTML tags
+% or other unpredicated results.
+%
+% Be aware that \emph{\textsf{moodle.sty} does not know how to convert any
+% other \TeX\ or \LaTeX\ commands to HTML.}
+% If other sequences are used, they may be passed verbatim to the XML file
+% or may cause unpredicted results.
+%
+% If you think of another \LaTeX\ command that should be changed to an HTML equivalent,
+% please contact the author at \url{anders.hendrickson@snc.edu}
+% so that it may be added to a future revision of the package.
+%
+% \section{Graphics}
+% The \textsf{moodle.sty} package can handle two kinds of graphics seamlessly.
+% External graphics files may be included with the |\includegraphics| command
+% from the |graphicx| package,
+% and graphics may be generated internally using \TikZ. In either case, the
+% graphics will be embedded in base-64 encoding directly within
+% the Moodle~XML produced. This prevents the hassle of managing separate
+% graphics files on the Moodle server, as Moodle will store the picture
+% within the question in the question bank.
+%
+% \DescribeMacro{\includegraphics}\DescribeMacro{height}\DescribeMacro{width}
+% When using |\includegraphics|, the only options currently supported
+% are |height| and |width|. Attempts to use other |\includegraphics| options,
+% such as |scale| or |angle|, will affect the PDF but not the XML output.
+% The dimensions set by |height| and |width| are \TeX\ dimensions such as |4in| or |2.3cm|.
+% In order to prepare the image for web viewing, this package converts those
+% dimensions to pixels using a default of
+% 103 pixels per inch.\footnote{This
+% number was selected because an image with
+% |<IMG HEIGHT=103 WIDTH=103 SRC="...">| showed up as almost exactly 1 inch
+% tall and 1 inch wide on several of this author's devices and browsers
+% as of January 2016.}
+% \DescribeMacro{ppi}
+% That value may be changed by setting the |ppi| key (e.g., |ppi=72|);
+% this is probably best done for the entire document with a |\moodleset| command,
+% rather than image-by-image.
+%
+% The mechanism used is somewhat fragile and relies upon one \TikZ\ library and three free external programs.
+% \begin{enumerate}
+% \item \textsf{moodle.sty} invokes |\usetikzlibrary{external}|,
+% so that each |tikzpicture| environment is compiled to a freestanding PDF file.
+% \item GhostScript (\url{www.ghostscript.com}) is used to convert the PDF output
+% from \TikZ\ into a PNG raster graphics file.
+% The default command line is presumed to be |gswin64c.exe|
+% (if |\ifwindows| from the |ifplatform| package returns true)
+% or |gs| (if |\ifwindows| returns false).
+% If your system requires a different command line to invoke Ghostscript,
+% \DescribeMacro{\ghostscriptcommand}
+% you may change it by invoking |\ghostscriptcommand|\marg{executable filename}.
+% \item When external graphics files such as JPG or GIF are included,
+% the open-source ImageMagick software (\url{www.imagemagick.org})
+% converts each file to PNG format.
+% The command line for ImageMagick is the nondescript word |convert|,
+% \DescribeMacro{\imagemagickcommand}
+% but may be changed by invoking |\imagemagickcommand|\marg{executable filename}.
+% \item Finally, the OpenSSL toolkit (\url{www.openssl.org}) is used to base64-encode
+% the PNG file so that it can be included directly in the text of the XML file.
+% The command line is presumed to be |openssl|, but can be changed with
+% \DescribeMacro{\opensslcommand}
+% |\opensslcommand|\marg{executable filename}.
+% \end{enumerate}
+%
+% Please note the following vital points to make the graphics handling work:
+% \begin{itemize}
+% \item As of now, graphics are only supported when compiling directly to a PDF
+% with |pdflatex|. Including PS graphics or using \TikZ\ with the DVI$\to$PS workflow is not
+% yet supported.
+% \item Filenames should not contains spaces or special characters like |_| or |\|.
+% \item You must have Ghostscript, ImageMagick, and OpenSSL installed on your system
+% to fully use the graphics-handling capabilities of \textsf{moodle.sty}.
+% \item \LaTeX\ must be able to call system commands; that is, |\write18| must be enabled.
+% For Mik\TeX, this means adding |--enable-write18| to the command line of |pdflatex|;
+% for \TeX Live, this means adding |--shell-escape=true|.
+% \end{itemize}
+%
+% \newpage
+% \section{Known Limitations and Call for Bug Reports}
+% Some features of Moodle quizzes have not yet been implemented in \textsf{moodle.sty}.
+% Here is a non-exhaustive list.
+% \begin{itemize}
+% \item Moodle's feature of designating feedback for correct,
+% partially correct, and incorrect answers.
+% \item Calculated questions; that is, automatically generated numerical questions
+% using randomly chosen numbers.
+% \item Hints
+% \item Keywords
+% \item So-called ``description'' questions.
+% \item Shuffled answers in multiple choice cloze subquestions.
+% \end{itemize}
+% I have used Version 0.5 for one semester's teaching,
+% but if other users adopt this package, I fully expect them to find bugs.
+% \emph{Please} send all bugs you find to \url{anders.hendrickson@snc.edu},
+% so that I can fix them for subsequent versions.
+%
+% \section{Compatibility}
+% This package has been written for and tested with the implementation of
+% Moodle 2.9 run by Moodlerooms for St.~Norbert College in January 2016.
+% Future versions of this package will probably include some support for
+% specifying your version of Moodle in the |.tex| file to help ensure compatability.
+%
+% As the ultimate purpose of this package is the generation of XML files,
+% future versions of \textsf{moodle.sty} will attempt to maintain backwards
+% compatability with earlier versions of regarding the XML output, apart from
+% bug fixes.
+% Backwards compatibility of the PDF output is not yet guaranteed, however,
+% in case the author or users discover better ways for the PDF to display
+% the underlying XML data to be proofread.
+%
+% In other words, compiling your current |.tex| file with a future version
+% of \textsf{moodle.sty} should produce the same XML file it does now
+% (apart from bug fixes),
+% but it might produce a more informative, and hence different,
+% PDF output.
+%
+%
+% \section{Unrelated Tip: Quality of Moodle \TeX\ Images}
+% This has nothing to do with |moodle.sty|, but is a Frequently Asked Question
+% in is own right.
+% On some servers, at least, Moodle's default ``\TeX\ Filter'' for
+% displaying mathematical notation is of abysmally poor quality, rending mathematics
+% as low-resolution PNG's. One solution that has worked for me is to go
+% to ``Course Administration $\to$ Filters,'' turn ``\TeX\ Notation'' \emph{off},
+% but turn ``MathJax'' \emph{on}. This forces \TeX\ code to be rendered by MathJax
+% instead of Moodle, producing much higher-quality results.
+%
+% \StopEventually{}
+%
+% \section{Implementation}
+% \subsection{Packages, Options, and Utilities}
+% \begin{macrocode}
+\newif\ifmoodle@draftmode
+\newif\ifmoodle@tikzloaded
+
+%%DECLARATION OF OPTIONS
+\DeclareOption{draft}{\moodle@draftmodetrue}
+
+\moodle@draftmodefalse
+\moodle@tikzloadedfalse
+
+\ProcessOptions
+
+\RequirePackage{environ} %To be able to take environment body as a macro argument
+\RequirePackage{xkeyval} %For key-handling
+\RequirePackage{amssymb} %For \checkmark symbol
+\RequirePackage{trimspaces} %To remove extra spaces from strings
+\RequirePackage{etex} %Expansion control, detokenization, etc.
+\RequirePackage{etoolbox}%List management
+\RequirePackage{xpatch} %To patch commands easily in HTML mode
+\RequirePackage{array} %For formatting tables in the LaTeX mode of Clozes
+\RequirePackage{ifplatform} % To choose Ghostscript commands
+\RequirePackage{ifpdf} % Needed to know whether we can convert output from PDF to PNG
+
+\RequirePackage{getitems} %To gather the header and items
+
+\let\xa=\expandafter
+\def\@star{*}%
+\def\@hundred{100}%
+\def\@moodle@empty{}%
+\def\@relax{\relax}%
+% \end{macrocode}
+% As the package involves a fair bit of file processing,
+% we automate the naming of auxiliary files.
+% \begin{macrocode}
+\def\jobnamewithsuffixtomacro#1#2{%
+ \filenamewithsuffixtomacro{#1}{\jobname}{#2}%
+}
+\def\@jn@quote{"}%
+\def\filenamewithsuffixtomacro#1#2#3{%
+ % #1 = macro to create
+ % #2 = filename to add suffix to
+ % #3 = suffix to add
+ \edef\jn@suffix{#3}%
+ \def\jn@macro{#1}%
+ \xa\testforquote#2\@jn@rdelim
+}
+\def\testforquote#1#2\@jn@rdelim{%
+ \def\jn@test@i{#1}%
+ \ifx\jn@test@i\@jn@quote
+ % Involves quotes
+ \edef\jn@next{"\jn@stripquotes#1#2\jn@suffix"}%
+ \else
+ \edef\jn@next{#1#2\jn@suffix}%
+ \fi
+ \xa\xdef\jn@macro{\jn@next}%
+}
+\def\jn@stripquotes"#1"{#1}%
+
+
+\jobnamewithsuffixtomacro{\outputfilename}{-moodle.xml}
+% \end{macrocode}
+% Next, we create macros to open and close the Moodle XML file
+% we will be writing.
+% \begin{macrocode}
+\newwrite\moodle@outfile
+\def\openmoodleout{%
+ \immediate\openout\moodle@outfile=\outputfilename\relax
+ \writetomoodle{<?xml version="1.0" encoding="UTF-8"?>}%
+ \writetomoodle{<quiz>}%
+ \writetomoodle{ }%
+}%
+\def\closemoodleout{%
+ \writetomoodle{ }%
+ \writetomoodle{</quiz>}%
+ \immediate\closeout\moodle@outfile
+}%
+% \end{macrocode}
+% To both make this |.sty| file and the XML output more readable,
+% we create a mechanism for writing to the output file with indents.
+% The macro |\calculateindent|\marg{$n$} globally defines
+% |\moodle@indent| to be a string of \meta{$n$} |\otherspace|'s.
+% \begin{macrocode}
+\def\calculateindent#1{%
+ \bgroup
+ \count0=\number#1\relax
+ \gdef\moodle@indent{}%
+ \calculateindent@int
+ \egroup
+}%
+\def\calculateindent@int{%
+ \ifnum\count0>0\relax
+ \g@addto@macro{\moodle@indent}{\otherspace}%
+ \advance\count0 by -1\relax
+ \expandafter
+ \calculateindent@int
+ \fi
+}%
+% \end{macrocode}
+% Now the command |\writetomoodle|\oarg{n}\marg{stuff} adds the line
+% ``\meta{stuff}'' to the XML file
+% preceded by an indent of \meta{n} spaces.
+% Note that this command |\edef|'s its second argument.
+% \begin{macrocode}
+\newcommand\writetomoodle[2][0]{%
+ \edef\test@ii{#2}%
+ \ifnum#1=0\relax
+ \immediate\write\moodle@outfile{\test@ii}%
+ \else
+ \calculateindent{#1}%
+ \immediate\write\moodle@outfile{\moodle@indent\trim@pre@space{\test@ii}}%
+ \fi
+}%
+% \end{macrocode}
+% We now create the main |quiz| environment that will contain
+% the questions we write. It outputs to XML as a |<question type="category">| tag.
+% \begin{macrocode}
+\newenvironment{quiz}[2][]%
+ {\setkeys{moodle}{#1}%
+ \@moodle@ifgeneratexml{%
+ \openmoodleout%
+ \setcategory{#2}%
+ }{}%
+ \subsection*{#2}%
+ \begin{enumerate}%
+ }
+ {\end{enumerate}%
+ \@moodle@ifgeneratexml{\closemoodleout}{}}
+
+{\catcode`\$=12\catcode`\ =12%
+\gdef\setcategory#1{%
+\writetomoodle{<question type="category">}%
+\writetomoodle{ <category>}%
+\writetomoodle{ <text>$module$/#1</text>}%
+\writetomoodle{ </category>}%
+\writetomoodle{</question>}%
+\writetomoodle{ }%
+}}%
+% \end{macrocode}
+% The next utility takes a single macro control sequence |#1|,
+% and allows that macro's current value to persist
+% after the next |\egroup|, |}|, or |\endgroup|.
+% \begin{macrocode}
+\def\passvalueaftergroup#1{%
+ \xa\xa\xa\gdef\xa\xa\csname moodle@remember@\string#1\endcsname\xa{\xa\def\xa#1\xa{#1}}%
+ \xa\aftergroup\csname moodle@remember@\string#1\endcsname
+}
+% \end{macrocode}
+%
+% \subsubsection{Main Switch: to create XML or not}
+%
+% \begin{macrocode}
+\long\def\@moodle@ifgeneratexml#1#2{%
+ % If we are generating XML, do #1; otherwise do #2.
+ \tikzifexternalizing{%
+ % This run of LaTeX is currently ONLY generating a Tikz image
+ % to be saved in an external file. We do NOT want to waste time
+ % generating XML, and moreover trying to do so would cause errors
+ % because of file dependencies.
+ #2%
+ }{%
+ \ifmoodle@draftmode
+ #2%
+ \else
+ #1%
+ \fi
+ }%
+}
+% \end{macrocode}
+%
+% \subsection{Key-Value Pairs for Quiz Questions}
+%
+% The various options are set using key-value syntax of |xkeyval|.
+% \begin{macrocode}
+\def\moodleset#1{\setkeys{moodle}{#1}}%
+% \end{macrocode}
+% We first define some macros that will help us write other macros.
+% Calling |\generate@moodle@write@code|\marg{name}|<|\meta{HTML tag}|>|\marg{text to write}
+% creates a macro |\moodle@write|\meta{name}, taking no parameters,
+% which writes the code |<|\meta{HTML tag}|>...</|\meta{HTML tag}|>|
+% to the output XML file.
+%
+% The ordinary version |\generate@moodle@write@code| passes its output text |#3|
+% through the HTMLizer, producing HTML code, while the starred version
+% |\generate@moodle@write@code*| passes |#3| verbatim as text.
+%
+% For example,
+% |\generate@moodle@write@code{excuse}<EXC>{\theexcuse}|
+% would expand to
+% \begin{Verbatim}[gobble=4,frame=single]
+% \gdef\moodle@writeexcuse{%
+% \xa\def\xa\test@iii\xa{\theexcuse}%
+% \ifx\test@iii\@moodle@empty
+% \writetomoodle[2]{ <EXC format="html"><text/></EXC>}%
+% \else
+% \xa\converttohtmlmacro\xa\moodle@htmltowrite\xa{\theexcuse}%
+% \writetomoodle[2]{ <EXC format="html">}%
+% \writetomoodle[4]{ <text><![CDATA[<p>\moodle@htmltowrite</p>]]></text>}%
+% \writetomoodle[2]{ </EXC>}%
+% \fi
+% }%
+% \end{Verbatim}
+% but
+% |\generate@moodle@write@code*{excuse}<EXC>{\theexcuse}|
+% would expand only to
+% \begin{Verbatim}[gobble=4,frame=single]
+% \gdef\moodle@writeexcuse{%
+% \writetomoodle[2]{ <EXC>\theexcuse</EXC>}%
+% }
+% \end{Verbatim}
+% \begin{macrocode}
+\def\generate@moodle@write@code{%
+ \@ifnextchar*\generate@moodle@write@data\generate@moodle@write@html
+}%
+
+\def\generate@moodle@write@html#1<#2>#3{%
+ % #1 = NAME for \moodle@writeNAME
+ % #2 = HTML tag
+ % #3 = what, exactly, to write
+ \xa\gdef\csname moodle@write#1\endcsname{%
+ \xa\def\xa\test@iii\xa{#3}%
+ \ifx\test@iii\@moodle@empty
+ \writetomoodle[2]{ <#2 format="html"><text/></#2>}%
+ \else
+ \xa\converttohtmlmacro\xa\moodle@htmltowrite\xa{#3}%
+ \writetomoodle[2]{ <#2 format="html">}%
+ \writetomoodle[4]{ <text><![CDATA[<p>\moodle@htmltowrite</p>]]></text>}%
+ \writetomoodle[2]{ </#2>}%
+ \fi
+ }%
+}%
+
+
+\def\generate@moodle@write@data*#1<#2>#3{%
+ % #1 = NAME for \moodle@writeNAME
+ % #2 = HTML tag
+ % #3 = what, exactly, to write
+ \xa\gdef\csname moodle@write#1\endcsname{%
+ \writetomoodle[2]{ <#2>#3</#2>}%
+ }%
+}%
+
+% \end{macrocode}
+% \subsubsection{Keys for all question types}
+% \begin{macrocode}
+%% QUESTIONNAME
+ \define@cmdkey{moodle}[moodle@]{questionname}{}%
+ \gdef\moodle@writequestionname{%
+ \writetomoodle[2]{<name>}%
+ \writetomoodle[4]{ <text>\moodle@questionname</text>}%
+ \writetomoodle[2]{</name>}%
+ }%
+
+%% QUESTIONTEXT
+ %I tried to use questiontext as a key, but it doesn't seem to work.
+ %The trouble is that xkeyval has trouble parsing a key with a \par token followed by a comma within brackets,
+ %like \setkeys{moodle}{questiontext={ABC\par [D,E]}}
+ %It's not worth trying to fix.
+
+ \long\def\questiontext#1{%
+ %\converttohtmlmacro\myoutput{#1}%
+ %\let\moodle@questiontext=\myoutput%
+ \def\moodle@questiontext{#1}%
+ }%
+ \generate@moodle@write@code{questiontext}<questiontext>{\moodle@questiontext}%{%
+
+%% PENALTY FOR WRONG ATTEMPT
+ \define@cmdkey{moodle}[moodle@]{penalty}[0.1000000]{}%
+ \generate@moodle@write@code*{penalty}<penalty>{\moodle@penalty}%
+ \moodleset{penalty}%
+
+%% FEEDBACK
+ % Moodle allows for feedback tailored to each question,
+ % and feedback tailored to each right or wrong answer.
+ % We shall use the key 'feedback' to record both kinds of feedback,
+ % relying on TeX's grouping mechanism to keep them apart.
+ % When it comes time to write them to XML,
+ % \moodle@writegeneralfeedback uses the HTML tag <generalfeedback>
+ % whereas \moodle@writefeedback uses the tag <feedback>.
+ % Note that the general feedback is NOT inherited by each answer!
+ \define@cmdkey{moodle}[moodle@]{feedback}[]{}%
+ \generate@moodle@write@code{generalfeedback}<generalfeedback>{\moodle@feedback}%
+ \generate@moodle@write@code{feedback}<feedback>{\moodle@feedback}%
+ \moodleset{feedback}%
+
+%% DEFAULT GRADE
+ %The next line creates \moodle@defaultgrade,
+ %which is how many points the quiz question is worth.
+ %Key calls like [default grade=7] set \moodle@defaultgrade.
+ \define@cmdkey{moodle}[moodle@]{default grade}[1.0]{}%
+ %Next, makes 'points' a synonym for 'default grade'
+ \define@key{moodle}{points}[1.0]{\xa\def\csname moodle@default grade\endcsname{#1}}
+ \generate@moodle@write@code*{defaultgrade}<defaultgrade>{\csname moodle@default grade\endcsname}%
+ \moodleset{default grade=1.0} %This sets the default.
+
+%% HIDDEN
+ \define@boolkey{moodle}[moodle@]{hidden}[true]{}%
+ \generate@moodle@write@code*{hidden}<hidden>{\ifmoodle@hidden 1\else 0\fi}%
+ \moodleset{hidden=false}%
+
+\def\moodle@writecommondata{%
+ \moodle@writequestionname%
+ \moodle@writequestiontext%
+ \moodle@writedefaultgrade%
+ \moodle@writegeneralfeedback%
+ \moodle@writepenalty%
+ \moodle@writehidden%
+}%
+
+% TO DO: 'tags' (i.e., keywords)
+
+% \end{macrocode}
+% \subsubsection{Keys for all answers}
+% \begin{macrocode}
+%% FRACTION -- how much this answer is worth out of 100 percent
+ \define@cmdkey{moodle}[moodle@]{fraction}[100]{}%
+ %We do not create \moodle@writefraction, because the fraction occurs in
+ %the XML within the answer tag, like <answer fraction="75">.
+ \moodleset{fraction=100} %This sets the default.
+% \end{macrocode}
+% \subsubsection{Keys for multiple choice questions}
+% \begin{macrocode}
+
+%% SINGLE and MULTIPLE -- for multichoice, is there 1 right answer or more than 1?
+ \define@boolkey{moodle}[moodle@]{single}[true]{}%
+ \generate@moodle@write@code*{single}<single>{\ifmoodle@single true\else false\fi}%
+ \moodleset{single}%
+ %The key 'multiple' is an antonym to 'single'.
+ \define@boolkey{moodle}[moodle@]{multiple}[true]{\ifmoodle@multiple\moodle@singlefalse\else\moodle@singletrue\fi}%
+
+%% SHUFFLE ANSWERS
+ \define@boolkey{moodle}[moodle@]{shuffle}[true]{}%
+ \generate@moodle@write@code*{shuffle}<shuffleanswers>{\ifmoodle@shuffle 1\else 0\fi}%
+ \moodleset{shuffle=true}%
+
+%% TO DO: CORRECTFEEDBACK
+%% TO DO: PARTIALLYCORRECTFEEDBACK
+%% TO DO: INCORRECTFEEDBACK
+%% TO DO: NUMCORRECT key
+
+%% NUMBERING -- for numbering of multichoice questions
+ \define@choicekey{moodle}{numbering}%
+ {alpha,alph,Alpha,Alph,arabic,roman,Roman,%
+ abc,ABC,123,iii,IIII,none}[abc]{%
+ \def\moodle@numbering{#1}%
+ \def\test@@i{#1}%
+ \ifx\test@@i\@moodle@alpha
+ \def\moodle@numbering{abc}\fi
+ \ifx\test@@i\@moodle@alph
+ \def\moodle@numbering{abc}\fi
+ \ifx\test@@i\@moodle@Alpha
+ \def\moodle@numbering{ABC}\fi
+ \ifx\test@@i\@moodle@Alph
+ \def\moodle@numbering{ABC}\fi
+ \ifx\test@@i\@moodle@arabic
+ \def\moodle@numbering{123}\fi
+ \ifx\test@@i\@moodle@roman
+ \def\moodle@numbering{iii}\fi
+ \ifx\test@@i\@moodle@Roman
+ \def\moodle@numbering{IIII}\fi
+ }%
+ %'answer numbering' will be a synonym to 'numbering'
+ \define@key{moodle}{answer numbering}[abc]{\setkeys{moodle}{numbering={#1}}}%
+ \generate@moodle@write@code*{answernumbering}<answernumbering>{\moodle@numbering}%
+ %N.B. if we did not set the default here, then \moodle@numbering would be undefined, causing problems.
+ \moodleset{answer numbering=abc}%
+
+ \def\@moodle@alpha{alpha}%
+ \def\@moodle@Alpha{Alpha}%
+ \def\@moodle@alph{alph}%
+ \def\@moodle@Alph{Alph}%
+ \def\@moodle@arabic{arabic}%
+ \def\@moodle@roman{roman}%
+ \def\@moodle@Roman{Roman}%
+ \def\@moodle@abc{abc}%
+ \def\@moodle@ABC{ABC}%
+ \def\@moodle@arabicnumbers{123}%
+ \def\@moodle@iii{iii}%
+ \def\@moodle@IIII{IIII}%
+ \def\@moodle@none{none}%
+ \def\moodle@obeynumberingstyle{%
+ \ifx\moodle@numbering\@moodle@abc
+ \renewcommand\theenumii{\alph{enumii}}%
+ \fi
+ \ifx\moodle@numbering\@moodle@ABC
+ \renewcommand\theenumii{\Alph{enumii}}%
+ \fi
+ \ifx\moodle@numbering\@moodle@arabicnumbers
+ \renewcommand\theenumii{\arabic{enumii}}%
+ \fi
+ \ifx\moodle@numbering\@moodle@iii
+ \renewcommand\theenumii{\roman{enumii}}%
+ \fi
+ \ifx\moodle@numbering\@moodle@IIII
+ \renewcommand\theenumii{\Roman{enumii}}%
+ \fi
+ \ifx\moodle@numbering\@moodle@none
+ \renewcommand\labelenumii{$\bullet$~}%
+ \fi
+ }
+ %TO DO: * In the PDF, how should 'none' in a multi look different from
+ % short answer or numerical options?
+ % * Instead of \theenumi and \labelenumi,
+ % use \@enumdepth to automatically set the correct depth.
+
+%% DISPLAY MODE -- affects Cloze multiple choice questions only.
+ % 0 = inline, 1 = vertical, 2 = horizontal
+ \def\moodle@multi@mode{0}%
+ \define@key{moodle}{inline}[]{\def\moodle@multi@mode{0}}%
+ \define@key{moodle}{vertical}[]{\def\moodle@multi@mode{1}}%
+ \define@key{moodle}{horizontal}[]{\def\moodle@multi@mode{2}}%
+% \end{macrocode}
+% \subsubsection{Keys for numerical questions}
+% \begin{macrocode}
+%% TOLERANCE
+ \define@cmdkey{moodle}[moodle@]{tolerance}[0]{}%
+ \moodleset{tolerance=0}%
+ %There is no \moodle@writetolerance, because in the XML the
+ %tolerance is given within the answer tag,
+ %like <answer fraction=100 tolerance=0.03>.
+
+% TO DO: implement unit-handling for numerical questions!
+% \end{macrocode}
+% \subsubsection{Keys for short answer questions}
+% \begin{macrocode}
+%% CASE SENSITIVE
+ \define@boolkey{moodle}[moodle@]{case sensitive}[true]{}%
+ \generate@moodle@write@code*{usecase}<usecase>{\csname ifmoodle@case sensitive\endcsname 1\else 0\fi}%
+ % We make 'usecase' a synonym for 'case sensitive'.
+ \define@boolkey{moodle}[moodle@]{usecase}[true]{\ifmoodle@usecase\csname moodle@case sensitivetrue\endcsname\else\csname moodle@case sensitivefalse\endcsname\fi}%
+ \moodleset{case sensitive=false}%
+% \end{macrocode}
+% \subsubsection{Keys for matching questions}
+% \begin{macrocode}
+%% DRAG-AND-DROP FORMAT
+ \define@boolkey{moodle}[moodle@]{draganddrop}[true]{}%
+ % We make 'dd' and 'dragdrop' and 'drag and drop' synonyms for 'draganddrop'.
+ \define@boolkey{moodle}[moodle@]{dd}[true]{\ifmoodle@dd\moodle@draganddroptrue\else\moodle@draganddropfalse\fi}%
+ \define@boolkey{moodle}[moodle@]{drag and drop}[true]{\moodle@ddsynonym}%
+ \def\moodle@ddsynonym{%
+ \csname ifmoodle@drag and drop\endcsname
+ \moodle@draganddroptrue
+ \else
+ \moodle@draganddropfalse
+ \fi
+ }
+ \moodleset{draganddrop=false}%
+% \end{macrocode}
+% \subsubsection{Keys for essay questions}
+% \begin{macrocode}
+%% EDITOR
+ \def\@moodle@html{html}%
+ \def\@moodle@htmlfile{html+file}%
+ \def\@moodle@text{text}%
+ \def\@moodle@plain{plain}%
+ \def\@moodle@monospaced{monospaced}%
+ \def\@moodle@file{file}%
+ \def\@moodle@noinline{noinline}%
+ \define@choicekey{moodle}{response format}%
+ {html,html+file,text,monospaced,file}[html]%
+ {\def\test@i{#1}%
+ \ifx\test@i\@moodle@html
+ % HTML Editor
+ \def\moodle@responseformat{editor}%
+ \fi
+ \ifx\test@i\@moodle@htmlfile
+ % HTML Editor with File Picker
+ \def\moodle@responseformat{editorfilepicker}%
+ \fi
+ \ifx\test@i\@moodle@text
+ % Plain text
+ \def\moodle@responseformat{plain}%
+ \fi
+ \ifx\test@i\@moodle@plain
+ % Plain text
+ \def\moodle@responseformat{plain}%
+ \fi
+ \ifx\test@i\@moodle@monospaced
+ % Plain text, monospaced font
+ \def\moodle@responseformat{monospaced}%
+ \fi
+ \ifx\test@i\@moodle@file
+ % No inline text (i.e., attachments only)
+ \def\moodle@responseformat{noinline}%
+ \fi
+ \ifx\test@i\@moodle@noinline
+ % No inline text (i.e., attachments only)
+ \def\moodle@responseformat{noinline}%
+ \fi
+ }%
+ \generate@moodle@write@code*{responseformat}<responseformat>{\moodle@responseformat}%
+ \moodleset{response format=html}%
+ %N.B. if we did not set a default, then \moodle@responseformat would be undefined, causing problems.
+
+%% RESPONSE REQUIRED
+ \define@boolkey{moodle}[moodle@]{response required}[true]{}%
+ % TO DO: Make synonym 'required'
+ \generate@moodle@write@code*{responserequired}<responserequired>{\csname ifmoodle@response required\endcsname 1\else 0\fi}%
+ \moodleset{response required=false}%
+
+%% RESPONSEFIELDLINES
+ \define@cmdkey{moodle}[moodle@]{response field lines}[15]{}%
+ \generate@moodle@write@code*{responsefieldlines}<responsefieldlines>{\csname moodle@response field lines\endcsname}%
+ %Make synonyms 'input box size' or 'height' or 'lines'?
+ \moodleset{response field lines=15}% N.B. if we do not set a default, then \moodle@responseformat will be undefined, causing problems.
+
+%% ATTACHMENTS ALLOWED
+ \def\@moodle@unlimited{unlimited}%
+ \define@choicekey{moodle}{attachments allowed}{0,1,2,3,unlimited}[1]{%
+ \def\test@i{#1}%
+ \ifx\test@i\@moodle@unlimited
+ \def\moodle@attachmentsallowed{-1}%
+ \else
+ \def\moodle@attachmentsallowed{#1}%
+ \fi
+ }
+ \generate@moodle@write@code*{attachmentsallowed}<attachments>{\moodle@attachmentsallowed}
+ \moodleset{attachments allowed=0}%
+
+%% ATTACHMENTS REQUIRED
+ \define@choicekey{moodle}{attachments required}{0,1,2,3}[1]{\def\moodle@attachmentsrequired{#1}}%
+ \generate@moodle@write@code*{attachmentsrequired}<attachmentsrequired>{\moodle@attachmentsrequired}
+ \moodleset{attachments required=0}%
+
+%% RESPONSE TEMPLATE
+ \define@key{moodle}{template}{\long\def\moodle@responsetemplate{#1}}%
+ \generate@moodle@write@code{responsetemplate}<responsetemplate>{\moodle@responsetemplate}
+ \moodleset{template={}}%
+% \end{macrocode}
+% \subsubsection{Hint tags}
+% The following are not yet fully implemented.
+% \begin{macrocode}
+%% SHOWNUMCORRECT
+ \define@boolkey{moodle}[moodle@]{shownumcorrect}[true]{}%
+ \gdef\moodle@writeshownumcorrect{%
+ \if\moodle@shownumcorrect
+ \writetomoodle[4]{ <shownumcorrect/>}%
+ \fi
+ }%
+ \moodleset{shownumcorrect=false}%
+
+%% CLEARWRONG
+ \define@boolkey{moodle}[moodle@]{clearwrong}[true]{}%
+ \gdef\moodle@writeclearwrong{%
+ \if\moodle@clearwrong
+ \writetomoodle[4]{ <clearwrong/>}%
+ \fi
+ }%
+ \moodleset{clearwrong=false}%
+
+% TO DO: Implement hints
+% \end{macrocode}
+%
+% \subsection{Answer handling}
+%
+% \begin{macrocode}
+%The Answers XML depends heavily on the question type.
+%Each type of question defines how it obtains answers from the LaTeX input,
+%how it typesets those in a PDF or DVI, and how it writes them as XML code.
+%It will write that XML to the macro \moodle@answers@xml,
+%which them gets written to the file when \moodle@writeanswers
+%is invoked.
+
+\def\moodle@answers@xml{}%
+\gdef\moodle@writeanswers{%
+ \writetomoodle{\moodle@answers@xml}%
+}%
+
+\newcommand\addto@xml[3][0]{%
+ % #1 = spaces to indent (default=0)
+ % #2 = macro containing XML code (possibly empty)
+ % #3 = XML text to be appended to that macro (will be \edef'd)
+ \calculateindent{#1}%
+ \edef\xml@to@add{\moodle@indent\trim@pre@space{#3}}%
+ \ifx#2\@moodle@empty
+ \edef\newxml{\noexpand#2\xml@to@add}%
+ \else
+ \edef\newxml{\noexpand#2^^J\xml@to@add}%
+ \fi
+ \xa\xa\xa\def\xa\xa\xa#2\xa\xa\xa{\newxml}%
+}%
+% \end{macrocode}
+%
+% \subsubsection{Not yet implemented}
+%
+% \begin{macrocode}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TRUE/FALSE QUESTIONS %%%%%%%%%%%%%%%%%
+
+% TODO: implement the \writetruefalsequestion
+% and a front-end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% DESCRIPTION 'QUESTIONS' %%%%%%%%%%%%%
+
+% TODO: implement the \writedescription and a suitable front-end.
+% Should this be \begin{description}...\end{description},
+% or should \begin{quiz}...\end{quiz} just scoop up all
+% text outside question environments and package it in descriptions?
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% CALCULATED %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% TODO: I don't think I really want to handle this. Not now.
+
+% \end{macrocode}
+
+% \subsection{Front Ends}
+% This section creates the user interface for the various question types.
+% First, we define a generic command to create
+% a front-end environment for a Moodle question type.
+% In order to function, the following macros must be hard-coded:
+% \begin{itemize}
+% \item |\moodle@|\meta{type}|@latexprocessing|:
+% Loops through the saved |\item|'s to typeset them in LaTeX,
+% usually inside an itemize or enumerate environment.
+% \item |\save|\meta{type}|answer#1|:
+% Processes the text of a single |\item| to save the information to memory,
+% usually inside |\moodle@answers@xml|.
+% \item |\write|\meta{type}|question|:
+% Writes the information, hitherto saved only in macros,
+% into the XML file.
+% \end{itemize}
+% For example, to create the `shortanswer' question type,
+% we shall call
+% \begin{Verbatim}[gobble=5,frame=single]
+% \moodle@makefrontend{shortanswer}
+% \def\moodle@shortanswer@latexprocessing{...}
+% \def\saveshortansweranswer#1{...}
+% \def\writeshortanswerquestion{...}
+% \end{Verbatim}
+%
+% \begin{macrocode}
+\def\moodle@makefrontend#1{%
+ \NewEnviron{#1}[2][]{%
+ \bgroup
+ \setkeys{moodle}{##1,questionname={##2}}%
+ \expandafter\gatheritems\xa{\BODY}%
+ \let\moodle@questionheader=\gatheredheader
+ %First, the LaTeX processing
+ \item \textbf{\moodle@questionname}\par
+ \noindent
+ \moodle@questionheader
+ \csname moodle@#1@latexprocessing\endcsname
+ %Now, writing information to XML
+ \@moodle@ifgeneratexml{%
+ \xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+ \bgroup
+ \gdef\moodle@answers@xml{}%
+ \setkeys{moodle}{feedback={}}%
+ \xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}%
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+ \csname write#1question\endcsname
+ }{}%
+ \egroup
+ }%
+}
+% \end{macrocode}
+%
+% \subsubsection{Essay Question Front-End}
+% The essay question is the only question type whose front end
+% is not yet created by |\moodle@makefrontend|.
+% This is because of what it must do with its |\item|'s.
+%
+% \begin{macrocode}
+\def\moodle@essay@latexprocessing{%
+ % Moodle cannot automatically grade an essay,
+ % but if the user puts \item's in, we can list them in an itemize as notes.
+ \ifnum\c@numgathereditems>0\relax
+ \par\noindent Notes: (not included in XML)
+ \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@essay@answer}%
+ \end{itemize}%
+ \fi
+}
+
+\NewEnviron{essay}[2][]{%
+ \bgroup
+ \setkeys{moodle}{#1,questionname={#2}}%
+ \expandafter\gatheritems\expandafter{\BODY}%
+ \let\moodle@questionheader=\gatheredheader
+ %First, the LaTeX processing.
+ \item \textbf{\moodle@questionname}\par
+ \noindent
+ \moodle@questionheader
+ \csname moodle@essay@latexprocessing\endcsname
+ %Now, writing information to memory.
+ \@moodle@ifgeneratexml{%
+ \xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+ \bgroup
+ \gdef\moodle@answers@xml{}%
+ %
+ \ifnum\c@numgathereditems=0\relax
+ \addto@xml[2]\moodle@answers@xml{<graderinfo format="html"><text/></graderinfo>}%
+ \else
+ \addto@xml[2]\moodle@answers@xml{<graderinfo format="html"><text><![CDATA[}%
+ \ifnum\c@numgathereditems>1\relax
+ \addto@xml[4]\moodle@answers@xml{<ul>}%
+ \fi
+ \loopthroughitemswithcommand{\moodle@savegraderinfo}%
+ \ifnum\c@numgathereditems>1\relax
+ \addto@xml[4]\moodle@answers@xml{</ul>}%
+ \fi
+ \addto@xml[2]\moodle@answers@xml{]]></text></graderinfo>}%
+ \fi
+ %
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+ \writeessayquestion
+ }{}%
+ \egroup
+}%
+
+%%%% TO DO
+%%%% To make essay work will be tough.
+%%%% Every line from \ifnum\c@numgathereditems=0\relax through its \else and \fi,
+%%%% with the exception of
+%%%% \xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}%
+%%%% , does not exist in our current \moodle@makefrontend code.
+%%%% How can we cope?
+%%%%
+%%%% Idea: change \moodle@makefrontend so that
+%%%% 1. if \c@numgathereditems=0, we don't do anything.
+%%%% 2. it calls a preamble and postamble around the \loopthroughitemswithcommand.
+%%%% Like this:
+%%%%
+%%%% \@moodle@ifgeneratexml{%
+%%%% \xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+%%%% \bgroup
+%%%% \gdef\moodle@answers@xml{}%
+%%%% \setkeys{moodle}{feedback={}}%
+%%%% \@ifundefined{moodle@#1@answers@preamble}{}{}%
+%%%% \csname moodle@#1@answers@preamble\endcsname
+%%%% \ifnum\c@numgathereditems=0\relax
+%%%% \relax
+%%%% \else
+%%%% \xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}%
+%%%% \fi
+%%%% \@ifundefined{moodle@#1@answers@postamble}{}{}%
+%%%% \csname moodle@#1@answers@postamble\endcsname
+%%%% \passvalueaftergroup{\moodle@answers@xml}%
+%%%% \egroup
+%%%% \csname write#1question\endcsname
+%%%% }{}%
+%%%% The \@ifundefined lines should automatically define the
+%%%% \...@preamble \...@postamble macros to be \relax if they don't exist already.
+
+\gdef\writeessayquestion{%
+ \writetomoodle{<question type="essay">}%
+ \moodle@writecommondata%
+ \moodle@writeresponserequired%
+ \moodle@writeresponseformat%
+ \moodle@writeresponsefieldlines%
+ \moodle@writeattachmentsallowed%
+ \moodle@writeattachmentsrequired%
+ \moodle@writeanswers% The 'answers' XML really contains the grader info.
+ \moodle@writeresponsetemplate%
+ \writetomoodle{</question>}%
+}%
+
+\def\moodle@print@essay@answer#1{%
+ \item #1%
+}%
+
+
+\def\moodle@savegraderinfo#1{%
+ \bgroup
+ \moodle@savegraderinfo@int#1\moodle@answer@rdelim
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+}%
+\newcommand\moodle@savegraderinfo@int[1][]{%
+ \setkeys{moodle}{fraction=0,#1}%
+ \moodle@savegraderinfo@int@int%
+}%
+\def\moodle@savegraderinfo@int@int#1\moodle@answer@rdelim{%
+ \xa\converttohtmlmacro\xa\moodle@answertext@html\xa{#1}%
+ %\trim@spaces@in\moodle@answertext
+ \ifnum\c@numgathereditems>1\relax
+ \addto@xml[6]{\moodle@answers@xml}{<li>\moodle@answertext@html</li>}%
+ \else
+ \addto@xml[4]{\moodle@answers@xml}{\moodle@answertext@html}%
+ \fi
+}%
+% \end{macrocode}
+%
+% \subsubsection{Short Answer Question Front-End}
+%
+% \begin{macrocode}
+\def\blank{\rule{1in}{0.5pt}}%
+% TO DO: Make an optional argument for width? This wouldn't affect Moodle,
+% only the appearance in the PDF. It doesn't seem worth it.
+
+% \NewEnviron{shortanswer}[2][]{%
+% \bgroup
+% \setkeys{moodle}{#1,questionname={#2}}%
+% \expandafter\gatheritems\xa{\BODY}%
+% \let\moodle@questionheader=\gatheredheader
+% %First, the LaTeX processing.
+% \bigskip\par\noindent
+% \fbox{\textbf{\moodle@questionname}}\par
+% \noindent
+% \moodle@questionheader
+% \csname moodle@shortanswer@latexprocessing\endcsname
+% %Now, writing information to memory.
+% \@moodle@ifgeneratexml{%
+% \xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+% \bgroup
+% \gdef\moodle@answers@xml{}%
+% \setkeys{moodle}{feedback={}}%
+% \xa\loopthroughitemswithcommand\xa{\csname saveshortansweranswer\endcsname}%
+% \passvalueaftergroup{\moodle@answers@xml}%
+% \egroup
+% \csname writeshortanswerquestion\endcsname
+% }{}%
+% \egroup
+% }%
+
+\moodle@makefrontend{shortanswer}%
+
+% LATEX PROCESSING
+\def\moodle@shortanswer@latexprocessing{%
+ \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@shortanswer@answer}%
+ \end{itemize}%
+}
+
+ \def\moodle@print@shortanswer@answer#1{%
+ \moodle@print@shortanswer@answer@int#1\@rdelim
+ }%
+ \newcommand\moodle@print@shortanswer@answer@int[1][]{%
+ \setkeys{moodle}{#1}%
+ \moodle@print@shortanswer@answer@int@int%
+ }%
+ \def\moodle@print@shortanswer@answer@int@int#1\@rdelim{%
+ \ifx\moodle@fraction\@hundred
+ \item #1\quad$\checkmark$%
+ \else
+ \item #1\quad (\moodle@fraction\%)%
+ \fi
+ }%
+
+% SAVING ANSWERS TO MEMORY
+\def\saveshortansweranswer#1{%
+ \bgroup
+ \saveshortansweranswer@int#1\moodle@answer@rdelim
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+}%
+ \newcommand\saveshortansweranswer@int[1][]{%
+ \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100%
+ \saveshortansweranswer@int@int%
+ }%
+ \def\saveshortansweranswer@int@int#1\moodle@answer@rdelim{%
+ \def\moodle@answertext{#1}%
+ \addto@xml[2]{\moodle@answers@xml}{<answer fraction="\moodle@fraction" format="plain_text">}%
+ \addto@xml[4]{\moodle@answers@xml}{ <text>\moodle@answertext</text>}%
+ \ifx\moodle@feedback\@empty\relax\else
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{</answer>}%
+ }%
+
+% WRITING QUESTION TO XML FILE
+\gdef\writeshortanswerquestion{%
+ \writetomoodle{<question type="shortanswer">}%
+ \moodle@writecommondata%
+ \moodle@writeusecase%
+ \moodle@writeanswers%
+ \writetomoodle{</question>}%
+}%
+% \end{macrocode}
+%
+% \subsubsection{Numerical Question Front-End}
+%
+% \begin{macrocode}
+\moodle@makefrontend{numerical}%
+
+% LATEX PROCESSING
+\def\moodle@numerical@latexprocessing{%
+ \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@numerical@answer}%
+ \end{itemize}%
+}
+
+ \def\moodle@print@numerical@answer#1{%
+ \moodle@print@numerical@answer@int#1\@rdelim
+ }%
+ \newcommand\moodle@print@numerical@answer@int[1][]{%
+ \setkeys{moodle}{#1}%
+ \moodle@print@numerical@answer@int@int%
+ }%
+ \def\moodle@print@numerical@answer@int@int#1\@rdelim{%
+ \ifdim0pt=\moodle@tolerance pt\relax
+ \def\moodle@numericalprint@tolerance{}%
+ \else
+ \edef\moodle@numericalprint@tolerance{\noexpand\pm\moodle@tolerance}%
+ \fi
+ \ifx\moodle@fraction\@hundred
+ \item $#1\moodle@numericalprint@tolerance\quad\checkmark$%
+ \else
+ \item $#1\moodle@numericalprint@tolerance$\quad (\moodle@fraction\%)%
+ \fi
+ }%
+
+% SAVING ANSWERS TO MEMORY
+\def\savenumericalanswer#1{%
+ \bgroup
+ \savenumericalanswer@int#1\moodle@answer@rdelim
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+}%
+ \newcommand\savenumericalanswer@int[1][]{%
+ \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100%
+ \savenumericalanswer@int@int%
+ }%
+ \def\savenumericalanswer@int@int#1\moodle@answer@rdelim{%
+ \def\moodle@answertext{#1}%
+ \addto@xml[2]{\moodle@answers@xml}{<answer fraction="\moodle@fraction" format="plain_text">}%
+ \addto@xml[4]{\moodle@answers@xml}{ <text>\moodle@answertext</text>}%
+ \addto@xml[4]{\moodle@answers@xml}{ <tolerance>\moodle@tolerance</tolerance>}%
+ \ifx\moodle@feedback\@empty\relax\else
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{</answer>}%
+ }%
+
+
+% WRITING QUESTION TO XML FILE
+\gdef\writenumericalquestion{%
+ \writetomoodle{<question type="numerical">}%
+ \moodle@writecommondata%
+ \moodle@writeanswers%
+ \writetomoodle{</question>}%
+}%
+% \end{macrocode}
+%
+% \subsubsection{Multiple Choice Question Front-End}
+%
+% \begin{macrocode}
+%Multiple choice has the structure
+% \begin{multi}[options]{name}%
+% What is 5+7?
+% \item 13
+% \item* 12
+% \item 11
+% \end{multi}%
+
+\moodle@makefrontend{multi}
+
+% LATEX PROCESSING
+\def\moodle@multi@latexprocessing{%
+ \moodle@countcorrectanswers
+ \begin{enumerate}\moodle@obeynumberingstyle
+ %\renewcommand{\theenumi}{\alph{enumi}}%
+ \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@multichoice@answer}%
+ \end{enumerate}%
+}
+ \def\moodle@print@multichoice@answer#1{%
+ \moodle@print@multichoice@answer@int#1\@rdelim
+ }%
+ \newcommand\moodle@print@multichoice@answer@int[1][]{%
+ \setkeys{moodle}{fraction=0,#1}%
+ \moodle@print@multichoice@answer@int@int
+ }%
+ \def\moodle@print@multichoice@answer@int@int#1#2\@rdelim{%
+ \def\test@i{#1}%
+ \ifmoodle@single
+ \ifx\test@i\@star
+ \item #2$~\checkmark$%
+ \else
+ \item #1#2%
+ \fi
+ \else
+ \ifx\test@i\@star
+ \item #2%
+ \setkeys{moodle}{fraction=\moodle@autopoints}%
+ \else
+ \item #1#2%
+ \fi
+ $~(\moodle@fraction\%)$
+ \fi
+ }%
+
+% COMMON UTILITY: COUNTING CORRECT ANSWERS
+ \newcounter{moodle@numcorrectanswers}%
+ \newlength{\moodle@pointspercorrect}%
+ \def\moodle@countcorrectanswers{%
+ \setcounter{moodle@numcorrectanswers}{0}%
+ \global\setlength{\moodle@pointspercorrect}{100pt}%
+ \loopthroughitemswithcommand{\moodle@countcorrectanswers@a}%
+ \ifnum0=\c@moodle@numcorrectanswers\relax
+ \PackageError{moodle}{No correct answers given for multiple choice question.}{Please mark at least one answer correct.}%
+ \gdef\moodle@autopoints{0}%
+ \else
+ \global\divide\moodle@pointspercorrect by \c@moodle@numcorrectanswers\relax
+ \edef\moodle@autopoints{\strip@pt\moodle@pointspercorrect}%
+ \fi
+ }
+ \def\moodle@countcorrectanswers@a#1{%
+ %The grouping is to keep key answer-specific key changes local.
+ \bgroup
+ \moodle@countcorrectanswers@b#1\moodle@answer@rdelim
+ \egroup
+ }%
+ \newcommand\moodle@countcorrectanswers@b[1][]{%
+ \setkeys{moodle}{fraction=0,#1}%
+ \moodle@countcorrectanswers@c%
+ }%
+ \def\moodle@countcorrectanswers@c#1#2\moodle@answer@rdelim{%
+ \def\test@i{#1}%
+ \ifx\test@i\@star
+ \stepcounter{moodle@numcorrectanswers}%
+ \else
+ \global\addtolength{\moodle@pointspercorrect}{-\moodle@fraction pt}%
+ \fi
+ }%
+ \def\moodle@setautopoints#1pt{%
+ \gdef\moodle@autopoints{#1}%
+ }
+
+% TODO: What if rounding errors make the percentages not add to 100%? Will Moodle complain?
+% TODO: Verify that negative scores are handled correctly.
+% TODO: Put these macros in same order as other sections'.
+
+% SAVING ANSWERS TO MEMORY
+\def\savemultianswer#1{%
+ \bgroup
+ \savemultianswer@int#1\moodle@answer@rdelim
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+}%
+ \newcommand\savemultianswer@int[1][]{%
+ \setkeys{moodle}{fraction=0,#1}%
+ \savemultianswer@int@int%
+ }%
+ \def\savemultianswer@int@int#1#2\moodle@answer@rdelim{%
+ \def\test@i{#1}%
+ \ifx\test@i\@star
+ \ifmoodle@single
+ \setkeys{moodle}{fraction=100}%
+ \else
+ \setkeys{moodle}{fraction=\moodle@autopoints}%
+ \fi
+ \def\moodle@answertext{#2}%
+ \else
+ \def\moodle@answertext{#1#2}%
+ \fi
+ \trim@spaces@in\moodle@answertext
+ \addto@xml[2]{\moodle@answers@xml}{<answer fraction="\moodle@fraction" format="html">}%
+ \xa\converttohtmlmacro\xa\moodle@answertext@html\xa{\moodle@answertext}%
+ \addto@xml[4]{\moodle@answers@xml}{ <text><![CDATA[<p>\moodle@answertext@html</p>]]></text>}%
+ \ifx\moodle@feedback\@empty\relax\else
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{</answer>}%
+ }%
+
+% WRITING QUESTION TO XML FILE
+\gdef\writemultiquestion{%
+ \writetomoodle{<question type="multichoice">}%
+ \moodle@writecommondata%
+ \moodle@writesingle%
+ \moodle@writeshuffle%
+ \moodle@writeanswernumbering%
+ \moodle@writeanswers%
+ \writetomoodle{</question>}%
+}%
+% \end{macrocode}
+%
+% \subsubsection{Matching Question Front-End}
+%
+% \begin{macrocode}
+\let\answer=\hfill
+
+\moodle@makefrontend{matching}
+
+% LATEX PROCESSING
+\def\moodle@matching@latexprocessing{%
+ \bgroup
+ \let\answer=\hfill
+ \begin{enumerate}\renewcommand{\theenumi}{\alph{enumi}}\setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@matching@answer}%
+ \end{enumerate}%
+ \egroup
+}
+ \long\def\moodle@print@matching@answer#1{%
+ \moodle@print@matching@answer@int#1\@rdelim
+ }%
+ \newcommand\moodle@print@matching@answer@int[1][]{%
+ \moodle@print@matching@answer@int@int\relax
+ }%
+ \long\def\moodle@print@matching@answer@int@int#1\answer#2\@rdelim{%
+ \item #1\hfill #2%
+ }%
+
+
+% SAVING ANSWERS TO MEMORY
+\long\def\savematchinganswer#1{%
+ \bgroup
+ \savematchinganswer@int#1\moodle@answer@rdelim%
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+}%
+ \newcommand\savematchinganswer@int[1][]{%
+ \setkeys{moodle}{#1}%
+ \xa\savematchinganswer@int@int\space%
+ }%
+ \long\def\savematchinganswer@int@int#1\answer#2\moodle@answer@rdelim{%
+ % Note that #1 may simply be \relax.
+ \def\moodle@subquestiontext{#1}%
+ \def\moodle@subanswertext{#2}%
+ \trim@spaces@in\moodle@subquestiontext
+ \xa\converttohtmlmacro\xa\moodle@subquestiontext@htmlized\xa{\moodle@subquestiontext}%
+ \trim@spaces@in\moodle@subanswertext
+ \ifmoodle@draganddrop
+ \xa\converttohtmlmacro\xa\moodle@subanswertext@htmlized\xa{\moodle@subanswertext}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{<subquestion format="html">}%
+ \ifx\moodle@subquestiontext\@empty
+ \addto@xml[4]{\moodle@answers@xml}{ <text></text>}%
+ \else
+ \addto@xml[4]{\moodle@answers@xml}{ <text><![CDATA[<p>\moodle@subquestiontext@htmlized</p>]]></text>}%
+ \fi
+ \ifmoodle@draganddrop
+% \show\moodle@subanswertext@htmlized
+ \addto@xml[4]{\moodle@answers@xml}{ <answer format="html"><text><![CDATA[<p>\moodle@subanswertext@htmlized</p>]]></text></answer>}%
+ \else
+% \show\moodle@subanswertext
+ \addto@xml[4]{\moodle@answers@xml}{ <answer><text>\moodle@subanswertext</text></answer>}%
+ \fi
+ \ifx\moodle@feedback\@empty\relax\else
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{</subquestion>}%
+ }%
+
+% WRITING QUESTION TO XML FILE
+\gdef\writematchingquestion{%
+ \ifmoodle@draganddrop
+ \writetomoodle{<question type="ddmatch">}%
+ \else
+ \writetomoodle{<question type="matching">}%
+ \fi
+ \moodle@writecommondata%
+ \moodle@writesingle%
+ \moodle@writeshuffle%
+ \moodle@writeanswernumbering%
+ \moodle@writeanswers%
+ \writetomoodle{</question>}%
+% \gdef\moodle@answ
+}%
+% \end{macrocode}
+%
+% \subsection{Cloze Questions}
+% Because cloze questions are so complicated, they get their own section of code.
+% The cloze strategy is as follows.
+%
+% All subquestions show up as part of the question body text.
+% For each type of subquestion, we have a cloze-version environment
+% that actually has 2 versions, depending on whether we are doing LaTeX or XML processing.
+% So the main environment is quite typical:
+% \begin{enumerate}
+% \item Process the body as LaTeX.
+% During this run, a |\begin{multi}| etc.~will be processed for display onscreen.
+% \item Then save the body as the questiontext for XML.
+% During this run, a |\begin{multi}| etc.~will be parsed and turned into
+% cloze code as part of the XML questiontext.
+% \end{enumerate}
+% \begin{macrocode}
+% LATEX PROCESSING
+% SAVING ANSWERS TO MEMORY
+
+\NewEnviron{cloze}[2][]{%
+ \bgroup
+ \setkeys{moodle}{default grade=1}%
+ \setkeys{moodle}{#1,questionname={#2}}%
+ % A cloze question won't have any \item's in it, so we just use \BODY.
+ \moodle@enableclozeenvironments
+ %First, the LaTeX processing.
+ \item \textbf{\moodle@questionname}\par
+ \noindent
+ \BODY
+ %Now, writing information to memory.
+ \@moodle@ifgeneratexml{%
+ \xa\questiontext\xa{\BODY}% Save the question text as HTML.
+ \writeclozequestion
+ }{}%
+ \egroup%
+}
+
+\def\moodle@enableclozeenvironments{%
+ \let\multi=\clozemulti
+ \let\endmulti=\endclozemulti
+ \let\numerical=\clozenumerical
+ \let\endnumerical=\endclozenumerical
+ \let\shortanswer=\clozeshortanswer
+ \let\endshortanswer=\endclozeshortanswer
+}
+
+% WRITING QUESTION TO XML FILE
+\gdef\writeclozequestion{%
+ \writetomoodle{<question type="cloze">}%
+ \moodle@writecommondata%
+ \writetomoodle{</question>}%
+}%
+% \end{macrocode}
+%
+% \subsubsection{Cloze Multiple Choice Questions}
+%
+% \begin{macrocode}
+% TODO: Guard against [single=false] option
+
+\NewEnviron{clozemulti}[1][]{%
+ \bgroup
+ \setkeys{moodle}{default grade=1}%
+ \setkeys{moodle}{#1}%
+ \expandafter\gatheritems\xa{\BODY}%
+ \let\moodle@questionheader=\gatheredheader
+ \ifhtmlizer@active
+ %HTML version
+ \def\moodle@clozemulti@output{}%
+ \xa\g@addto@macro\xa\moodle@clozemulti@output\xa{\moodle@questionheader}%
+ \def\clozemulti@coding{}%
+ \edef\clozemulti@coding{\otherlbrace\csname moodle@default grade\endcsname:}%
+ \ifcase\moodle@multi@mode\relax
+ % Case 0: dropdown box style
+ \g@addto@macro{\clozemulti@coding}{MULTICHOICE:}%
+ \or
+ % Case 1: vertical style
+ \g@addto@macro{\clozemulti@coding}{MULTICHOICE_V:}%
+ \else
+ % Case 2: horizontal radio buttons
+ \g@addto@macro{\clozemulti@coding}{MULTICHOICE_H:}%
+ \fi
+ \bgroup
+ \setkeys{moodle}{feedback={}}%
+ \loopthroughitemswithcommand{\saveclozemultichoiceanswer}%
+ \egroup
+ \xa\g@addto@macro\xa\clozemulti@coding\xa{\otherrbrace}%
+ \xa\g@addto@macro\xa\moodle@clozemulti@output\xa{\clozemulti@coding}%
+ \xa\gdef\xa\htmlize@afteraction@hook\xa{\moodle@clozemulti@output}%
+ \def\endclozemulti@code{\htmlize@patchendenvironment}%
+ \else
+ %LaTeX version
+ \moodle@questionheader% %Any introductory text just continues to be typeset.
+ \def\cloze@multichoice@table@text{}%
+ \loopthroughitemswithcommand{\moodle@print@clozemultichoice@answer}%
+ \ifcase\moodle@multi@mode\relax
+ %Case 0: dropdown box style
+ \begin{tabular}[t]{|l|}\firsthline% (\firsthline is from the array package.)
+ \cloze@multichoice@table@text%
+ \end{tabular}%
+ \or
+ %Case 1: vertical style
+ \begin{itemize}\setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \cloze@multichoice@table@text%
+ \end{itemize}%
+ \else
+ %Case 2: horizontal radio buttons
+ \par{\cloze@multichoice@table@text}\par%
+ \fi
+ \def\endclozemulti@code{\relax}%
+ \fi
+ \passvalueaftergroup\endclozemulti@code%
+ \passvalueaftergroup\htmlize@afteraction@hook%
+ \egroup%
+}[\endclozemulti@code]%
+
+
+\def\moodle@print@clozemultichoice@answer#1{%
+ \moodle@print@clozemultichoice@answer@int#1\@rdelim%
+}%
+\newcommand\moodle@print@clozemultichoice@answer@int[1][]{%
+ \moodle@print@clozemultichoice@answer@int@int%
+}%
+\def\moodle@print@clozemultichoice@answer@int@int#1#2\@rdelim{%
+ % Case 0: "(answer) \\ \hline"
+ % Case 1: "\item (answer)"
+ % Case 2: "$\bullet~$(answer)\hfill"
+ \ifcase\moodle@multi@mode\relax
+ \relax% Case 0
+ \or
+ \g@addto@macro\cloze@multichoice@table@text{\item}% Case 1
+ \else
+ \g@addto@macro\cloze@multichoice@table@text{$\bullet~$}% Case 2
+ \fi
+ \def\test@i{#1}%
+ \ifx\test@i\@star
+ \g@addto@macro\cloze@multichoice@table@text{#2$~\checkmark$}%
+ \else
+ \g@addto@macro\cloze@multichoice@table@text{#1#2}%
+ \fi
+ \ifcase\moodle@multi@mode\relax
+ \g@addto@macro{\cloze@multichoice@table@text}{\\ \hline}% Case 0
+ \or
+ \relax% Case 1
+ \else
+ \g@addto@macro{\cloze@multichoice@table@text}{\hfill}% Case 2
+ \fi
+}%
+
+\def\saveclozemultichoiceanswer#1{%
+ \bgroup
+ \saveclozemultichoiceanswer@int#1\moodle@answer@rdelim
+ \egroup
+}%
+\newcommand\saveclozemultichoiceanswer@int[1][]{%
+ \setkeys{moodle}{fraction=0,#1}%
+ \saveclozemultichoiceanswer@int@int%
+}%
+\def\saveclozemultichoiceanswer@int@int#1#2\moodle@answer@rdelim{%
+ \def\test@i{#1}%
+ \ifgatherbeginningofloop\else
+ \xa\gdef\xa\clozemulti@coding\xa{\clozemulti@coding\clozetilde}% separator between answers
+ \fi
+ \ifx\test@i\@star
+ \setkeys{moodle}{fraction=100}%
+ \def\moodle@answertext{#2}%
+ \else
+ \def\moodle@answertext{#1#2}%
+ \fi
+ \trim@spaces@in\moodle@answertext
+ \ifx\moodle@fraction\@hundred
+ \g@addto@macro\clozemulti@coding{=}%
+ \fi
+ \ifnum0<\moodle@fraction\relax
+ \ifnum\moodle@fraction<100\relax
+ \xdef\clozemulti@coding{\expandonce\clozemulti@coding\otherpercent\moodle@fraction\otherpercent}%
+ \fi
+ \fi
+ \xdef\clozemulti@coding{\expandonce\clozemulti@coding\expandonce\moodle@answertext}%
+ \ifx\moodle@feedback\@empty\else
+ \xdef\clozemulti@coding{\expandonce\clozemulti@coding\otherbackslash\otherhash\moodle@feedback}%
+ \fi
+}%
+% \end{macrocode}
+%
+% \subsubsection{Cloze Numerical Questions}
+%
+% \begin{macrocode}
+\NewEnviron{clozenumerical}[1][]{%
+ \bgroup
+ \expandafter\gatheritems\expandafter{\BODY}%
+ \let\moodle@questionheader=\gatheredheader
+ \setkeys{moodle}{default grade=1}%
+ \setkeys{moodle}{#1}%
+ \ifhtmlizer@active
+ %HTML version
+ \def\moodle@clozenumerical@output{}%
+ \xa\g@addto@macro\xa\moodle@clozenumerical@output\xa{\moodle@questionheader}%
+ \def\clozenumerical@coding{}%
+ \edef\clozenumerical@coding{\otherlbrace\csname moodle@default grade\endcsname:NUMERICAL:}%
+ \bgroup
+ \setkeys{moodle}{feedback={}}%
+ \loopthroughitemswithcommand{\saveclozenumericalanswer}%
+ \egroup
+ \xa\g@addto@macro\xa\clozenumerical@coding\xa{\otherrbrace}%
+ \xa\g@addto@macro\xa\moodle@clozenumerical@output\xa{\clozenumerical@coding}%
+ \xa\gdef\xa\htmlize@afteraction@hook\xa{\moodle@clozenumerical@output}%
+ \def\endclozenumerical@code{\htmlize@patchendenvironment}%
+ \else
+ %LaTeX version
+ \moodle@questionheader% %Any introductory text just continues to be typeset.
+ \def\cloze@numerical@table@text{}%
+ \loopthroughitemswithcommand{\moodle@print@clozenumerical@answer}%
+ \begin{tabular}[t]{|ll|}\firsthline
+ \cloze@numerical@table@text\hline%
+ \end{tabular}%
+ \def\endclozenumerical@code{\relax}%
+ \fi
+ \passvalueaftergroup\endclozenumerical@code%
+ \passvalueaftergroup\htmlize@afteraction@hook%
+ \egroup
+}[\endclozenumerical@code]%
+
+\def\moodle@print@clozenumerical@answer#1{%
+ \bgroup
+ \moodle@print@clozenumerical@answer@int#1\@rdelim
+ \egroup
+}%
+\newcommand\moodle@print@clozenumerical@answer@int[1][]{%
+ \setkeys{moodle}{#1}%
+ \moodle@print@clozenumerical@answer@int@int%
+}%
+\def\moodle@print@clozenumerical@answer@int@int#1\@rdelim{%
+ \ifx\moodle@fraction\@hundred
+ \def\moodle@clozenumericalprint@fraction{$\checkmark$}%
+ \else
+ \edef\moodle@clozenumericalprint@fraction{(\moodle@fraction\%)}%
+ \fi
+ \ifdim0pt=\moodle@tolerance pt\relax
+ \def\moodle@clozenumericalprint@tolerance{}%
+ \else
+ \edef\moodle@clozenumericalprint@tolerance{\noexpand\pm\moodle@tolerance}%
+ \fi
+ \xdef\moodle@clozenumericalprint@line{$#1\moodle@clozenumericalprint@tolerance$ & \moodle@clozenumericalprint@fraction}%
+ \xa\g@addto@macro\xa\cloze@numerical@table@text\xa{\moodle@clozenumericalprint@line \\}%
+}%
+
+
+
+\def\saveclozenumericalanswer#1{%
+ \bgroup
+ \saveclozenumericalanswer@int#1\moodle@answer@rdelim
+ \egroup
+}%
+\newcommand\saveclozenumericalanswer@int[1][]{%
+ \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100%
+ \saveclozenumericalanswer@int@int%
+}%
+\def\saveclozenumericalanswer@int@int#1\moodle@answer@rdelim{%
+ \ifgatherbeginningofloop\else
+ \xa\gdef\xa\clozenumerical@coding\xa{\clozenumerical@coding\clozetilde}% separator between answers
+ \fi
+ \def\moodle@answertext{#1}%
+ \trim@spaces@in\moodle@answertext
+ \ifx\moodle@fraction\@hundred
+ \g@addto@macro\clozenumerical@coding{=}%
+ \fi
+ \ifnum0<\moodle@fraction\relax
+ \ifnum\moodle@fraction<100\relax
+ \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherpercent\moodle@fraction\otherpercent}%
+ \fi
+ \fi
+ \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\moodle@answertext:\moodle@tolerance}%
+ \ifx\moodle@feedback\@empty\else
+ \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherbackslash\otherhash\moodle@feedback}%
+ \fi
+}%
+% \end{macrocode}
+%
+% \subsubsection{Cloze Short Answer Questions}
+%
+% \begin{macrocode}
+\NewEnviron{clozeshortanswer}[1][]{%
+ \bgroup
+ \expandafter\gatheritems\expandafter{\BODY}%
+ \let\moodle@questionheader=\gatheredheader
+ \setkeys{moodle}{default grade=1}%
+ \setkeys{moodle}{#1}%
+ %Because nesting conditionals built by \csname doesn't work well,
+ %we'll test '\ifmoodle@case sensitive' now and save the result in \count0.
+ \csname ifmoodle@case sensitive\endcsname
+ \count0=1\relax
+ \else
+ \count0=0\relax
+ \fi
+ \ifhtmlizer@active
+ %HTML version
+ \def\moodle@clozeshortanswer@output{}%
+ \xa\g@addto@macro\xa\moodle@clozeshortanswer@output\xa{\moodle@questionheader}%
+ \def\clozeshortanswer@coding{}%
+ \ifnum\count0=1\relax
+ \edef\clozeshortanswer@coding{\otherlbrace\csname moodle@default grade\endcsname:SHORTANSWER_C:}%
+ \else
+ \edef\clozeshortanswer@coding{\otherlbrace\csname moodle@default grade\endcsname:SHORTANSWER:}%
+ \fi
+ \bgroup
+ \setkeys{moodle}{feedback={}}%
+ \loopthroughitemswithcommand{\saveclozeshortansweranswer}%
+ \egroup
+ \xa\g@addto@macro\xa\clozeshortanswer@coding\xa{\otherrbrace}%
+ \xa\g@addto@macro\xa\moodle@clozeshortanswer@output\xa{\clozeshortanswer@coding}%
+ \xa\gdef\xa\htmlize@afteraction@hook\xa{\moodle@clozeshortanswer@output}%
+ \def\endclozeshortanswer@code{\htmlize@patchendenvironment}%
+ \else
+ %LaTeX version
+ \moodle@questionheader% %Any introductory text just continues to be typeset.
+ \def\cloze@shortanswer@table@text{}%
+ \loopthroughitemswithcommand{\moodle@print@clozeshortanswer@answer}%
+ \ifnum\count0=1\relax
+ \marginpar{\tiny\mbox{(Case-Sensitive)}}%
+ \fi
+ \begin{tabular}[t]{|ll|}\firsthline
+ \cloze@shortanswer@table@text\hline%
+ \end{tabular}%
+ \def\endclozeshortanswer@code{\relax}%
+ \fi
+ \passvalueaftergroup\endclozeshortanswer@code%
+ \passvalueaftergroup\htmlize@afteraction@hook%
+ \egroup
+}[\endclozeshortanswer@code]%
+
+\def\moodle@print@clozeshortanswer@answer#1{%
+ \bgroup
+ \moodle@print@clozeshortanswer@answer@int#1\@rdelim
+ \egroup
+}%
+\newcommand\moodle@print@clozeshortanswer@answer@int[1][]{%
+ \setkeys{moodle}{#1}%
+ \moodle@print@clozeshortanswer@answer@int@int%
+}%
+\def\moodle@print@clozeshortanswer@answer@int@int#1\@rdelim{%
+ \ifx\moodle@fraction\@hundred
+ \def\moodle@clozeshortanswerprint@fraction{$\checkmark$}%
+ \else
+ \edef\moodle@clozeshortanswerprint@fraction{(\moodle@fraction\%)}%
+ \fi
+ \xdef\moodle@clozeshortanswerprint@line{#1 & \moodle@clozeshortanswerprint@fraction}%
+ \xa\g@addto@macro\xa\cloze@shortanswer@table@text\xa{\moodle@clozeshortanswerprint@line \\}%
+}%
+
+
+
+\def\saveclozeshortansweranswer#1{%
+ \bgroup
+ \saveclozeshortansweranswer@int#1\moodle@answer@rdelim
+ \egroup
+}%
+\newcommand\saveclozeshortansweranswer@int[1][]{%
+ \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100%
+ \saveclozeshortansweranswer@int@int%
+}%
+\def\saveclozeshortansweranswer@int@int#1\moodle@answer@rdelim{%
+ \ifgatherbeginningofloop\else
+ \xa\gdef\xa\clozeshortanswer@coding\xa{\clozeshortanswer@coding\clozetilde}% separator between answers
+ \fi
+ \def\moodle@answertext{#1}%
+ \trim@spaces@in\moodle@answertext
+ \ifx\moodle@fraction\@hundred
+ \g@addto@macro\clozeshortanswer@coding{=}%
+ \fi
+ \ifnum0<\moodle@fraction\relax
+ \ifnum\moodle@fraction<100\relax
+ \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\otherpercent\moodle@fraction\otherpercent}%
+ \fi
+ \fi
+ \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\moodle@answertext}%
+ \ifx\moodle@feedback\@empty\else
+ \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\otherbackslash\otherhash\moodle@feedback}%
+ \fi
+}%
+% \end{macrocode}
+%
+% \section{Converting \LaTeX\ to HTML}
+% A lot of work must now be done to convert the \LaTeX\ code
+% of a question or answer into HTML code with embedded \TeX\ for math.
+%
+% \subsection{Catcode Setup}
+% First, we create versions of the special characters with catcode 12, ``other.''
+% \begin{macrocode}
+{\catcode`\#=12\gdef\otherhash{#}%
+ \catcode`\~=12\gdef\othertilde{~}%
+ \catcode`\&=12\gdef\otherampersand{&}%
+ \catcode`\^=12\gdef\othercaret{^}%
+ \catcode`\$=12\gdef\otherdollar{$}%
+ \catcode`\%=12\gdef\otherpercent{%}}%
+{\catcode`\ =12\gdef\otherspace{ }}%
+{\tt\catcode`\|=0\catcode`\\=12\relax|gdef|otherbackslash{\}}%
+{\catcode`\[=1\catcode`\]=2\catcode`\{=12\catcode`\}=12%
+ \gdef\otherlbrace[{]\gdef\otherrbrace[}]]
+
+
+\edef\@otherlbrace{\otherlbrace}%
+\edef\@otherrbrace{\otherrbrace}%
+\edef\@otherdollar{\otherdollar}%
+\edef\@otherbackslash{\otherbackslash}%
+\edef\@othertilde{\othertilde}%
+% \end{macrocode}
+%
+% Next, we define commands to change catcodes to a suitable verbatim mode
+% for transcription.
+%
+% \begin{macrocode}
+{ \catcode`\[=1\relax
+ \catcode`\]=2\relax
+ \catcode`\|=0\relax
+ |gdef|verbcatcodesweirdest[
+ |catcode`\{=12|relax
+ |catcode`\}=12|relax
+ |catcode`\\=12|relax
+ ]%
+}%
+\def\verbcatcodes{%
+ \catcode`\$=12\relax
+ \catcode`\&=12\relax
+ \catcode`\#=12\relax
+ \catcode`\^=12\relax
+ \catcode`\_=12\relax
+ \catcode`\~=12\relax
+ \makeatletter
+ \catcode`\%=12\relax
+ \catcode`\ =12\relax\catcode\newlinechar=12\verbcatcodesweirdest}%
+
+\def\normalcatcodes{%
+ \catcode`\\=0\relax
+ \catcode`\{=1\relax
+ \catcode`\}=2\relax
+ \catcode`\$=3\relax
+ \catcode`\&=4\relax
+ \catcode\endlinechar=5\relax
+ \catcode`\#=6\relax
+ \catcode`\^=7\relax
+ \catcode`\_=8\relax
+ \catcode`\ =10\relax
+ \makeatletter% We will be detokenizing and retokenizing internal control sequences, so we need this.
+ \catcode`\~=13\relax
+ \catcode`\%=14\relax}%
+
+\def\retokenizingcatcodes{%
+ %For rescanning previously scanned text, all true comments will already be gone,
+ %but % signs may have been inserted by Cloze questions, so we want to treat them as 'other.'
+ %
+ % TODO: #'s are more worrisome.
+ \normalcatcodes
+ \catcode`\%=12\relax
+}
+% \end{macrocode}
+%
+% \subsection{Detokenization and Retokenization}
+%
+% We will be processing a \TeX\ token list.
+% Based on its content, sometimes we will want it to be detokenized to
+% individual characters, but other times we want it retokenized so that
+% \TeX's own parsing mechanism can gather up the parameters of macros.
+% We use the e\TeX\ primitive command |\scantokens| to do this.
+%
+% The following code (catcodes, groupings and all) defines a |\scantokens@to@macro| macro.
+% That will assemble and disassemble strings of tokens
+% using any changing schemes of catcodes we desire.
+%
+% We define |^^A| to be |\gdef\stm@saved|, while |^^B| and |^^C| are substitutes for |{| and |}|, respectively.
+% This permits us to define |\scantokens@to@macro| in a peculiar catcode regime.
+% \begin{macrocode}
+\begingroup
+ \catcode`\^^A=13\gdef^^A{\gdef\stm@saved}%
+ \catcode`\^^B=1\catcode`\^^C=2\relax
+ \long\gdef\scantokens@to@macro#1#2#3{%
+ % #1 = control sequence to be defined
+ % #2 = command to change catcodes, e.g. \verbcatcodes,
+ % and define any command sequences
+ % #3 = text to be retokenized and saved into #1.
+ \bgroup
+ \def\texttorescan{#3}%
+ \catcode`\^^A=13\catcode`\^^B=1\catcode`\^^C=2\relax
+ \xa\def\xa\arg\xa{\xa^^A\xa^^B\texttorescan^^C}%
+ #2%
+ \catcode\endlinechar=9\relax%
+ %\scantokens always sees an end-of-line character at its end and converts it to a space.
+ %The catcode change sets \scantokens to ignore end-of-line chars.
+ %In practice, we're always calling \scantokens on previously scanned text anyway,
+ %so we won't miss any real end-of-line chars, since they were already converted to spaces.
+ \xa\scantokens\xa{\arg}%
+ \egroup
+ \xa\def\xa#1\xa{\stm@saved}%
+ }%
+\endgroup%
+
+\long\def\ultradetokenize@to@macro#1#2{%
+ \scantokens@to@macro#1{\verbcatcodes}{#2}%
+}%
+\def\retokenizenormal@to@macro#1#2{%
+ \scantokens@to@macro#1{\retokenizingcatcodes}{#2}%
+}%
+% \end{macrocode}
+%
+% \subsection{Level-Tracking}
+% While parsing, we'll need to keep track of whether
+% we are in math mode (and how many levels deep the math mode might be nested),
+% and also how deeply nested in \TeX\ groups we are.
+% \begin{macrocode}
+\newcount\moodle@mathmodedepth
+\moodle@mathmodedepth=0\relax
+\def\moodle@ifmathmode#1#2{%
+ \ifnum\moodle@mathmodedepth>0\relax
+ #1%
+ \else
+ #2%
+ \fi
+}
+
+\newcount\grouplevel
+
+\newif\ifhtmlizer@active
+\htmlizer@activefalse
+% \end{macrocode}
+%
+% \subsection{Separation}
+%
+% This code separates a string of tokens into two parts.
+% Its parameters, |#1#2|, consist of tokenized text,
+% plus one terminal |\@htmlize@stop|.
+% We are trying to break up the text into its first group and the remainder.
+% This |\@htmlize@stop| is needed in case |#2| has the form ``|{...}|'',
+% since we don't want \TeX\ to strip the braces off.
+% Thus |\@htmlize@remainder| will definitely end in ``|\@htmlize@stop|''.
+% \begin{macrocode}
+\long\def\htmlize@grabblock#1#2\htmlize@rdelim@ii{%
+ \long\def\htmlize@blockinbraces{#1}%
+ \long\def\htmlize@remainder{#2}%
+}%
+% \end{macrocode}
+%
+% The next line defines the macro |\@htmlize@stop@detokenized| to contain
+% the string of tokens |\@htmlize@stop|, all of category code 12 (other) or 10 (letter).
+% We'll need this for comparison purposes later.
+% \begin{macrocode}
+\ultradetokenize@to@macro\@htmlize@stop@detokenized{\@htmlize@stop}%
+% \end{macrocode}
+%
+% The next line creates the macro |\htmlize@remove@stopcode|,
+% which removes the characters ``|\@htmlize@stop |'' from the end of a
+% detokenized sequence.
+% Its syntax when called is simply |\htmlize@remove@stopcode |\meta{material},
+% with no delimiters, since the ``|\@htmlize@stop |'' is itself the delimiter.
+% \begin{macrocode}
+\xa\def\xa\htmlize@remove@stopcode\xa#\xa1\@htmlize@stop@detokenized{#1}%
+% \end{macrocode}
+%
+% \subsection{Main Code: the HTMLizer}
+%
+% \begin{macrocode}
+\newif\ifhtmlize@actioncs
+\newif\ifhtmlize@expandcs
+\newif\ifhtmlize@passcs
+
+\long\def\@@begin@cs{\begin}%
+\def\@@htmlize@stop{\@htmlize@stop}%
+
+\long\def\converttohtmlmacro#1#2{%
+ \grouplevel=0\relax
+ \def\htmlize@output{}%
+ \htmlizer@activetrue%
+ \converttohtml@int{#2}%
+ \htmlizer@activefalse%
+ \let#1=\htmlize@output\relax
+}
+
+\long\def\converttohtml@int#1{%
+ \advance\grouplevel by 1\relax
+ \bgroup
+ \ultradetokenize@to@macro\htmlize@texttoscan{#1}%
+ \xa\htmlize@recursive@i\htmlize@texttoscan\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i
+ \egroup
+ \advance\grouplevel by -1\relax
+}%
+
+\def\@lt{<}%
+\def\@gt{>}%
+
+\long\def\htmlize@recursive@i#1#2#3\htmlize@rdelim@i{%
+ % #1#2#3 is a sequence of tokens. All should be categories 11 (letter) or 12 (other).
+ % It terminates with the control sequences \@htmlize@stop\@htmlize@stop\@htmlize@stop.
+ %\long\def\ds{(#1|#2|#3)}\show\ds
+ \def\test@i{#1}%
+ \def\test@ii{#2}%
+ \ifx\test@i\@@htmlize@stop
+ \let\htmlize@next@i=\relax
+ \else
+ \ifx\test@i\@otherlbrace%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\otherlbrace}%
+ \bgroup
+ \normalcatcodes
+ %We need to rescan the input as TeX code,
+ % so TeX can automatically pull off the first group in braces.
+ % First, let's get rid of the terminal \@htmlize@stop codes.
+ {\def\@htmlize@stop{}\xdef\htmlize@scrap{#1#2#3}}%
+ \let\htmlize@text@to@rescan=\htmlize@scrap%
+ % Next, we retokenize the code.
+ \xa\retokenizenormal@to@macro\xa\htmlize@rescanned\xa{\htmlize@text@to@rescan}%
+ % Now break it up into two pieces.
+ \xa\htmlize@grabblock\htmlize@rescanned\@htmlize@stop\htmlize@rdelim@ii%
+ % The first piece, \htmlize@blockinbraces, will be passed as a unit to \converttohtml@int.
+ % The second part, \htmlize@remainder, will continue at this depth of grouping.
+ % Therefore we'll detokenize \htmlize@remainder here.
+ \xa\ultradetokenize@to@macro\xa\htmlize@remainder@detokenized\xa{\htmlize@remainder}%
+ \edef\htmlize@remainder@detokenized{\xa\htmlize@remove@stopcode\htmlize@remainder@detokenized}%
+ %
+ % Now build \htmlize@next@i.
+ % When done, should look like
+ % \converttohtml@int{\htmlize@blockinbraces}%
+ % \g@addto@macro\htmlize@output{\otherrbrace}%
+ % \htmlize@recursive@i\htmlize@remainder@detokenized\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i%
+ % but with all three arguments expanded.
+ % Note that we are running
+ \gdef\htmlize@scrap{\converttohtml@int}%
+ \xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\htmlize@blockinbraces}}%
+ \g@addto@macro\htmlize@scrap{\g@addto@macro\htmlize@output}%
+ \xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\otherrbrace}}%
+ \g@addto@macro\htmlize@scrap{\htmlize@recursive@i}%
+ \xa\g@addto@macro\xa\htmlize@scrap\xa{\htmlize@remainder@detokenized\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i}%
+ % Okay, that's done. It's stored in a global macro.
+ % Now we get it out of this group.
+ \egroup
+ \let\htmlize@next@i=\htmlize@scrap
+ \else
+ \ifx\test@i\@otherdollar%
+ % Math shift character.
+ \ifx\test@ii\@otherdollar
+ % Double dollar sign, so we're entering display math mode.
+ % We grab everything between $$...$$, sanitize it, and add it verbatim to
+ % our output.
+ \htmlize@displaymathshift@replace#1#2#3\htmlize@rdelim@iii%
+ \else
+ % Single dollar sign, so we're entering inline math mode.
+ % We grab everything between $$...$$, sanitize it, and add it verbatim to
+ % our output.
+ \htmlize@inlinemathshift@replace#1#2#3\htmlize@rdelim@iii%
+ \fi
+ % Now we resume work.
+ % The \htmlize@xxxxxxmathshift@replace macro stored the remaining text in \htmlize@remaining@text.
+ % Note that since we never detokenized and retokenized #1#2#3,
+ % \htmlize@remaining@text still includes the terminating \@htmlize@stop\@htmlize@stop\@htmlize@stop.
+ \def\htmlize@next@i{\xa\htmlize@recursive@i\htmlize@remaining@text\htmlize@rdelim@i}%
+ \else
+ \ifx\test@i\@otherbackslash%
+ % Control sequence. Oh boy.
+ % There are three possible things to do:
+ % 1. Retokenize everything, so we get a token list.
+ % Expand this control sequence, the first one in the list,
+ % to obtain a new token list. Then resume processing that list.
+ % Examples: \def\emph#1{<EM>#1</EM>}, \def\rec#1{\frac{1}{#1}}, \def\inv{^{-1}}
+ % \& --> &amp; \# --> #; etc.
+ % Environments: \begin{center}...\end{center} --> <CENTER>...</CENTER>
+ % 2. Retokenize everything, so we get a token list.
+ % Let this first command (with its parameters) ACT.
+ % This may involve work in TeX's stomach (e.g., with counters)
+ % or with external files (e.g., image processing).
+ % The command may directly add material to \htmlize@output,
+ % but it should not typeset anything and should vanish from the
+ % input stream when it is done.
+ % When it's done, we somehow need to detokenize and resume
+ % processing the remainder of the input stream.
+ % Only commands explicitly crafted (or modified) to work
+ % with moodle.sty can possibly do all this!
+ % Examples: (modified) \includegraphics
+ % Environments: \begin{clozemulti}, \begin{enumerate}
+ % 3. Ignore that it's a command. Pass it right on as a character
+ % sequence to \htmlize@output.
+ % Examples: \alpha, \frac
+ % Environments: \begin{array}
+ %
+ % #2 is only for items on a specific list.
+ % #1 is anything that runs in TeX's mouth.
+ % We could keep a list and give users a way to add to it.
+ % I could also try expanding macros, using \ifcsmacro from etoolbox.sty
+ %
+ % The first step is to figure out what control sequence we're dealing with.
+ % First, let's get rid of the terminal \@htmlize@stop codes.
+ {\def\@htmlize@stop{}\xdef\htmlize@scrap{#1#2#3}}%
+ \let\htmlize@text@to@rescan=\htmlize@scrap%
+ % Next, we retokenize the code.
+ \xa\retokenizenormal@to@macro\xa\htmlize@rescanned\xa{\htmlize@text@to@rescan}%
+ % Now break it up into two pieces.
+ \xa\htmlize@grabblock\htmlize@rescanned\@htmlize@stop\htmlize@rdelim@ii%
+ \let\@htmlize@cs\htmlize@blockinbraces%
+ \edef\htmlize@cs@string{\xa\string\@htmlize@cs}%
+ % The first piece, \htmlize@blockinbraces, will contain the single token in \@htmlize@cs.
+ % We'll need to keep the second part, \htmlize@remainder, since it probably
+ % contains arguments to the cs in \@htmlize@cs.
+ %\edef\ds{Encountered '\xa\string\@htmlize@cs'}\show\ds
+ %
+ % N.B. that \@htmlize@cs is a macro *containing* a single control sequence.
+ % This is good for testing with \ifx.
+ % \htmlize@cs@string contains the cs as a string, e.g., the characters "\emph".
+ %
+ \ifx\@htmlize@cs\@@begin@cs
+ %This is a \begin. Begin environment-handling routine.
+ %
+ % Grab the first {...} from \htmlize@remainder, which is the argument
+ % to \begin.
+ \xa\htmlize@grabblock\htmlize@remainder\@htmlize@stop\htmlize@rdelim@ii%
+ \let\htmlize@envname=\htmlize@blockinbraces%
+ %We do not need the rest, so we won't pay any attention to the new
+ %content of \htmlize@remainder.
+ %
+ %Now environments are non-expandable,
+ %so there are only two possibilities: action or pass.
+ \xa\ifinlist\xa{\htmlize@envname}{\htmlize@env@actionlist}%
+ {% Action environment!
+ %\bgroup
+ %\def\ds{Encountered active environment \string\begin\{{\htmlize@envname}\}}\show\ds
+ \def\htmlize@next@i{\xa\htmlize@do@actionenv\htmlize@rescanned\@htmlize@stop\htmlize@actionsequence@rdelim}%
+ %The \bgroup is to active the environments.
+ %The matching \egroup is found in \htmlize@do@actionenv.
+ }{%An environment to pass to the HTML
+ %We just pass the backslash from "\begin" and move on.
+ \g@addto@macro\htmlize@output{#1}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ }%
+ \else%
+ %This is not an environment. Begin macro-handling routine.
+ \htmlize@actioncsfalse
+ \htmlize@expandcsfalse
+ \htmlize@passcsfalse
+ \xa\ifinlist\xa{\htmlize@cs@string}{\htmlize@cs@actionlist}%
+ {%Action sequence!
+ \htmlize@actioncstrue}%
+ {% Not action sequence!
+ \xa\ifinlist\xa{\htmlize@cs@string}{\htmlize@cs@expandlist}%
+ {%CS to be expanded!
+ \htmlize@expandcstrue%
+ }%
+ {%CS to be transcribed to XML
+ \htmlize@passcstrue%
+ }%
+ }%
+ %Now exactly one of \ifhtmlize@actioncs, \ifhtmlize@expandcs, and \ifhtmlize@passcs is true.
+ \ifhtmlize@actioncs
+ % It's an action-sequence.
+ %\edef\ds{Must let \xa\string\@htmlize@cs\ act!}\show\ds
+ %\show\htmlize@rescanned
+ \def\htmlize@next@i{\xa\htmlize@do@actioncs\htmlize@rescanned\@htmlize@stop\htmlize@actionsequence@rdelim}%
+ %\show\htmlize@rescanned
+ % Note that \htmlize@do@actioncs should patch the command to have it
+ % restart the scanning in time.
+ \else
+ \ifhtmlize@expandcs
+ % control sequence to be expanded
+ %\edef\ds{Must expand \xa\string\@htmlize@cs}\show\ds
+ \bgroup
+ \htmlize@redefine@expansionmacros
+ %The \expandafters first expand \htmlize@rescanned,
+ %and then expand its first token just once.
+ \xa\xa\xa\gdef\xa\xa\xa\htmlize@scrap\xa\xa\xa{\htmlize@rescanned}%
+ \egroup
+ \xa\ultradetokenize@to@macro\xa\htmlize@remaining@text\xa{\htmlize@scrap}%
+ \def\htmlize@next@i{\xa\htmlize@recursive@i\htmlize@remaining@text\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i}%
+ \else
+ % control sequence to be transcribed to XML.
+ %\edef\ds{Must pass on \xa\string\@htmlize@cs}\show\ds
+ \g@addto@macro\htmlize@output{#1}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \fi
+ \fi
+ \fi
+ \else%
+ \ifx\test@i\@othertilde%
+ % The ~ becomes non-breaking space &nbsp;
+ \g@addto@macro\htmlize@output{\otherampersand nbsp;}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \else
+ \ifx\test@i\@lsinglequote%
+ \ifx\test@ii\@lsinglequote%
+ % Double left quote
+ \g@addto@macro\htmlize@output{\otherampersand ldquo;}%
+ \def\htmlize@next@i{\htmlize@recursive@i#3\htmlize@rdelim@i}%
+ \else
+ \g@addto@macro\htmlize@output{\otherampersand lsquo;}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \fi
+ \else
+ \ifx\test@i\@rsinglequote%
+ \ifx\test@ii\@rsinglequote%
+ %Double right quote
+ \g@addto@macro\htmlize@output{\otherampersand rdquo;}%
+ \def\htmlize@next@i{\htmlize@recursive@i#3\htmlize@rdelim@i}%
+ \else
+ \g@addto@macro\htmlize@output{\otherampersand rsquo;}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \fi
+ \else
+ \ifx\test@i\@doublequote
+ \g@addto@macro\htmlize@output{\otherampersand rdquo;}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \else
+ \ifx\test@i\@lt
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherampersand lt;}}%
+ {\g@addto@macro\htmlize@output{<}}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \else
+ \ifx\test@i\@gt
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherampersand gt;}}%
+ {\g@addto@macro\htmlize@output{>}}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \else
+ % Default case: write first token to output, call self on remaining tokens.
+ \g@addto@macro\htmlize@output{#1}%
+ \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \htmlize@next@i
+}%
+
+\def\@lsinglequote{`}%
+\def\@rsinglequote{'}%
+\def\@doublequote{"}%
+% \end{macrocode}
+%
+% \subsection{Math Mode handling}
+%
+% In the following, note that the |\|\meta{*}|mathrightdelim|'s gobble an argument.
+% This is so ``|$a$ is...|" can turn into
+% ``\ldots |a\|\meta{*}|mathrightdelim{} is...|"
+% and preserve a trailing space.
+% \begin{macrocode}
+\edef\inlinemathleftdelim{\otherbackslash(}%
+\def\inlinemathrightdelim#1{\advancemathmodecounter{-1}%
+ \g@addto@macro\htmlize@output{\otherbackslash)}}%
+\edef\displaymathleftdelim{<CENTER>\otherbackslash[}%
+\def\displaymathrightdelim#1{\advancemathmodecounter{-1}%
+ \g@addto@macro\htmlize@output{\otherbackslash]</CENTER>}}%
+{\catcode`\$=12\relax%
+ \gdef\htmlize@inlinemathshift@replace$#1$#2\htmlize@rdelim@iii{%
+ %\def\ds{inline math shift has '#1' and '#2'}\show\ds
+ \xa\g@addto@macro\xa\htmlize@output\xa{\inlinemathleftdelim}%
+ \advancemathmodecounter{1}%
+ \def\mathtext{#1}%
+ \def\aftertext{#2}%
+ \xdef\htmlize@remaining@text{\expandonce\mathtext%
+ \otherbackslash inlinemathrightdelim{}%
+ \expandonce\aftertext}%
+ %\show\htmlize@remaining@text
+ }%
+ \gdef\htmlize@displaymathshift@replace$$#1$$#2\htmlize@rdelim@iii{%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\displaymathleftdelim}%
+ \advancemathmodecounter{1}%
+ \def\mathtext{#1}%
+ \def\aftertext{#2}%
+ \xdef\htmlize@remaining@text{\expandonce\mathtext%
+ \otherbackslash displaymathrightdelim{}%
+ \expandonce\aftertext}%
+ }%
+}
+% \end{macrocode}
+%
+% \subsection{Engines for Control Sequences}
+%
+% There are three kinds of control sequences that need special handling:
+% \begin{enumerate}
+% \item Action environments
+% \item Action command sequences
+% \item Expansion macros
+% \end{enumerate}
+%
+% \subsubsection{Engine for running action environments}
+% \begin{macrocode}
+\long\def\htmlize@do@actionenv#1#2\@htmlize@stop\htmlize@actionsequence@rdelim{%
+ \bgroup %The corresponding \egroup is given in \htmlize@proceedwiththerest,
+ %to localize the changes to the environment definitions.
+ \htmlize@activate@environments
+ \gdef\htmlize@afteraction@hook{}%
+ #1#2\@htmlize@stop\htmlize@actionsequence@rdelim%
+}
+
+\def\htmlize@patchendenvironment{\swaptotrueendenvironment{\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook}}%
+
+\def\swaptotrueendenvironment#1#2\if@ignore\@ignorefalse\ignorespaces\fi{#2\if@ignore\@ignorefalse\ignorespaces\fi#1}%
+
+
+\long\def\htmlize@record@environment#1{%
+ \listadd{\htmlize@env@actionlist}{#1}%
+}
+\long\def\html@newenvironment#1#2{%
+ \listadd{\htmlize@env@actionlist}{#1}%
+ \g@addto@macro\htmlize@activate@environments{%
+ \xa\let\csname #1\endcsname\relax%
+ \xa\let\csname end#1\endcsname\relax%
+ \NewEnviron{#1}{%
+ #2%
+ }[\htmlize@patchendenvironment]%
+ }%
+}
+
+
+\def\htmlize@activate@environments{}%
+% \end{macrocode}
+%
+% \subsubsection{Engine for running action command sequences}
+%
+% The following automatically adds the ``engine'' to do the command
+% and then resume processing the \LaTeX\ into HTML.
+% It uses the |xpatch| package, which says it works with anything
+% defined using |\newcommand| etc. and |\newenvironment| etc.
+% \begin{macrocode}
+\gdef\htmlize@afteraction@hook{}%
+
+\long\def\htmlize@do@actioncs#1#2\htmlize@actionsequence@rdelim{%
+ % #1#2 contains the current string to be rendered into HTML;
+ % N.B. it has been tokenized at this point,
+ % so TeX can process it directly.
+ % #1 = the command sequence we need to execute
+ % #2 = the rest of the string
+ %
+ % First, we patch the desired command so that, when it is over,
+ % it calls \htmlize@proceedwiththerest.
+ % We do this within the group, so as not to permanently change the command.
+ \bgroup
+ % The matching \egroup is issued in \htmlize@proceedwiththerest,
+ % so that the changes made by \htmlize@activate@css are localized to just the command itself.
+ \gdef\htmlize@afteraction@hook{}%
+ \htmlize@activate@css%
+ \def\test@i{#1}%
+ \ifx\test@i\@relax
+ \def#1{\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook}%
+ \else
+ \xapptocmd#1{\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook}{}{\PackageError{Could not patch the command \string#1!}}%
+ \fi
+ % Now we call that patched command.
+ #1#2\htmlize@actionsequence@rdelim%
+ %The matching \egroup now is built into the command #1.
+}
+\long\def\htmlize@proceedwiththerest#1\htmlize@actionsequence@rdelim{%
+ % The action cs has done its work.
+ % Now we gather up the remaining tokens, detokenize them,
+ % remove the \@htmlize@stop, and get back to work transcribing it.
+ \egroup %This \egroup matches the \bgroup that was issued either in \htmlize@do@actioncs or in \htmlize@do@actionenv
+ \ultradetokenize@to@macro\htmlize@remainder@detokenized{#1}%
+ %This will contain an extra \@htmlize@stop, so we remove it.
+ \xa\xa\xa\def\xa\xa\xa\htmlize@remainder@detokenized\xa\xa\xa{\xa\htmlize@remove@stopcode\htmlize@remainder@detokenized}%
+ %Now we get back to work transcribing the remainder.
+ \xa\htmlize@recursive@i\htmlize@remainder@detokenized\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i%
+}
+
+\long\def\htmlize@record@action#1{%
+ \xa\listadd\xa\htmlize@cs@actionlist\xa{\string#1}%
+}
+
+\def\htmlize@activate@css{}%
+\def\html@action@def#1{%
+ \htmlize@record@action{#1}%
+ \xa\def\xa\htmlize@scrap\xa{\xa\let\xa#1\csname html@\string#1\endcsname}%
+ \xa\g@addto@macro\xa\htmlize@activate@css\xa{\htmlize@scrap}%
+ \xa\def\csname html@\string#1\endcsname% %And this \def\html@\oldcsname is follows by the remainder of the definition.
+}
+% \end{macrocode}
+%
+% \subsubsection{Engine for expansion control sequences}
+%
+% Calling |\htmlize@redefine@expansionmacros| will redefine
+% the macros for us. It starts out empty.
+% \begin{macrocode}
+\def\htmlize@redefine@expansionmacros{}%
+% \end{macrocode}
+% If |\mymacro| needs no changes to be suited for expansion,
+% you can simply call |\htmlize@record@expand{\mymacro}|
+% or |\htmlregister{\mymacro}|
+% to record that it should be expanded on its way to the HTML.
+% Examples would be user-built macros such as |\inv|$\to$|^{-1}|
+% or |\N|$\to$|\mathbb{N}|.
+% \begin{macrocode}
+\long\def\htmlize@record@expand#1{%
+ \xa\listadd\xa\htmlize@cs@expandlist\xa{\string#1}%
+}
+\let\htmlregister=\htmlize@record@expand
+% \end{macrocode}
+% On the other hand, if an alternate version of the macro is
+% needed for HTML purposes, you can define its HTML version with
+% |\html@def\mymacro...|
+% Parameters are okay.
+% An example would be
+% |\html@def\emph#1{<EM>#1</EM>}|.
+% \begin{macrocode}
+\long\def\html@def#1{%
+ \htmlize@record@expand{#1}%
+ \xa\def\xa\htmlize@scrap\xa{\xa\let\xa#1\csname html@\string#1\endcsname}%
+ \xa\g@addto@macro\xa\htmlize@redefine@expansionmacros\xa{\htmlize@scrap}%
+ \xa\def\csname html@\string#1\endcsname%
+}
+% \end{macrocode}
+% Note that when |\html@def| expands out, it ends with |\def\html@\oldcsname|
+% which abuts directly on the remainder of the definition.
+%
+% \subsection{Specific Control Sequences for Action and Expansion}
+%
+% Now that we have that machinery in place,
+% we define specific environments, action control sequences, and macros to
+% expand to accomplish our purposes.
+%
+% \subsubsection{Action Environments}
+% \begin{macrocode}
+\htmlize@record@environment{clozemulti}
+\htmlize@record@environment{multi}
+\htmlize@record@environment{clozenumerical}
+\htmlize@record@environment{numerical}
+\htmlize@record@environment{clozeshortanswer}
+\htmlize@record@environment{shortanswer}
+
+\html@newenvironment{center}{\xdef\htmlize@afteraction@hook{<CENTER>\expandonce\BODY</CENTER>}}%
+\html@newenvironment{enumerate}{%
+ \xa\gatheritems\xa{\BODY}%
+ \gdef\htmlize@afteraction@hook{<OL>}%
+ \loopthroughitemswithcommand{\moodle@itemtoLI}%
+ \g@addto@macro\htmlize@afteraction@hook{</OL>}%
+}%
+\html@newenvironment{itemize}{%
+ \xa\gatheritems\xa{\BODY}%
+ \gdef\htmlize@afteraction@hook{<UL>}%
+ \loopthroughitemswithcommand{\moodle@itemtoLI}%
+ \g@addto@macro\htmlize@afteraction@hook{</UL>}%
+}%
+\def\moodle@itemtoLI#1{%
+ \g@addto@macro\htmlize@afteraction@hook{<LI>#1</LI>}%
+}%
+
+% \end{macrocode}
+%
+% \subsubsection{Action Control Sequences}
+%
+% \begin{macrocode}
+\def\advancemathmodecounter#1{%
+ \global\advance\moodle@mathmodedepth by #1\relax
+}
+\htmlize@record@action{\advancemathmodecounter}%
+
+
+
+
+\htmlize@record@action{\relax}%
+
+\html@action@def\#{\g@addto@macro\htmlize@output{\otherhash}}%
+\html@action@def\&{\g@addto@macro\htmlize@output{\otherampersand}}%
+\html@action@def\\{\moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherbackslash}}%
+ {\g@addto@macro\htmlize@output{<BR/>}}}%
+\html@action@def\{{%
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherlbrace}}%
+ {\g@addto@macro\htmlize@output{\otherlbrace}}%
+ }%
+\html@action@def\}{%
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherrbrace}}%
+ {\g@addto@macro\htmlize@output{\otherrbrace}}%
+ }%
+\html@action@def\ldots{%
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\string\ldots}}%
+ {\g@addto@macro\htmlize@output{...}}%
+ }%
+\html@action@def\dots{%
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\string\dots}}%
+ {\g@addto@macro\htmlize@output{...}}%
+ }%
+\html@action@def\ {%
+ \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherspace}}%
+ {\g@addto@macro\htmlize@output{\otherspace}}%
+ }%
+\html@action@def\${%
+ \g@addto@macro\htmlize@output{\otherdollar}%
+ }%
+
+\html@action@def\clozetilde{%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\othertilde}%
+ }%
+
+
+
+%Diacritical marks over vowels
+{\catcode`|=3\relax
+ \gdef\htmlize@vowels{a|e|i|o|u|A|E|I|O|U|}}
+\def\htmlize@define@diacritic#1#2{%
+ \htmlize@record@action{#1}%
+ \g@addto@macro\htmlize@activate@css{%
+ \def#1##1{%
+ \ifinlist{##1}{\htmlize@vowels}%
+ {\g@addto@macro\htmlize@output{\otherampersand##1#2;}}%
+ {\xa\g@addto@macro\htmlize@output\xa{\string#1##1}}%
+ }%
+ }%
+}
+\htmlize@define@diacritic{\^}{circ}%
+\htmlize@define@diacritic{\'}{acute}%
+\htmlize@define@diacritic{\"}{uml}%
+\htmlize@define@diacritic{\`}{grave}%
+
+%Hungarian long-umlaut diacritics
+\def\@o{o}\def\@O{O}\def\@u{u}\def\@U{U}%
+\html@action@def\H#1{%
+ \bgroup
+ \def\test@i{#1}%
+ \ifx\test@i\@O
+ \def\toadd{\otherampersand\otherhash337;}%
+ \else
+ \ifx\test@i\@o
+ \def\toadd{\otherampersand\otherhash337;}%
+ \else
+ \ifx\test@i\U
+ \def\toadd{\otherampersand\otherhash368;}%
+ \else
+ \ifx\test@i\u
+ \def\toadd{\otherampersand\otherhash369;}%
+ \else
+ \def\toadd{\otherbackslash\otherlbrace#1\otherrbrace}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \xa\g@addto@macro\xa\htmlize@output\xa{\toadd}%
+ \egroup
+}%
+
+
+%Tilde over a, n, o
+{\catcode`|=3\relax
+ \gdef\htmlize@tilde{A|N|O|a|n|o|}}
+\html@action@def\~#1{%
+ \ifinlist{#1}{\htmlize@tilde}%
+ {\g@addto@macro\htmlize@output{\otherampersand#1tilde;}}%
+ {\xa\g@addto@macro\htmlize@output\xa{\string\~#1}}%
+ }%
+% \end{macrocode}
+%
+% \subsubsection{Command sequences for Expansion}
+%
+% \begin{macrocode}
+\html@def\underline#1{<SPAN STYLE="text-decoration: underline;">#1</SPAN>}
+\html@def\emph#1{<EM>#1</EM>}%
+\html@def\textbf#1{<B>#1</B>}%
+\html@def\blank{____________}%
+\html@def\par{</P><P>}%
+\html@def\aa{\&aring;}%
+\html@def\AA{\&Aring;}%
+\html@def\ae{\&aelig;}%
+\html@def\AE{\&AElig;}%
+\html@def\S{\&sect;}%
+\html@def\euro{\&euro;}%
+\html@def\texteuro{\&euro;}%
+\html@def\o{\&oslash;}%
+\html@def\O{\&Oslash;}%
+\html@def\ss{\&szlig;}%
+\html@def\l{\&lstrok;}%
+\html@def\L{\&Lstrok;}%
+
+% AH CUSTOM MACROS TO EXPAND --- remove these before publishing!
+\htmlize@record@expand{\inv}%
+\htmlize@record@expand{\rec}%
+
+\htmlize@record@action\inlinemathrightdelim
+\htmlize@record@action\displaymathrightdelim
+
+
+% \end{macrocode}
+%
+% \subsection{Graphics via {\tt\string\includegraphics}}
+%
+% \subsubsection{External program command lines}
+% We first set up commands for the external programs.
+% \begin{macrocode}
+\def\htmlize@setexecutable#1{%
+ % Defines macro #1 to be #2 in a verbatim mode suitable for filenames
+ \def\htmlize@executable@macro{#1}%
+ \bgroup\catcode`\|=0\catcode`\\=12\relax%
+ \htmlize@setexecutable@int
+}
+\def\htmlize@setexecutable@int#1{%
+ \egroup
+ \expandafter\def\htmlize@executable@macro{#1}%
+}
+
+\def\ghostscriptcommand{\htmlize@setexecutable\gs}
+\def\opensslcommand{\htmlize@setexecutable\openssl}
+\def\imagemagickcommand{\htmlize@setexecutable\htmlize@imagemagick@convert}
+
+\ifwindows%
+ \ghostscriptcommand{gswin64c.exe}%
+\else%
+ \ghostscriptcommand{gs}%
+\fi%
+
+\opensslcommand{openssl}%
+\imagemagickcommand{convert}%
+% \end{macrocode}
+%
+% \subsubsection{Graphics key-handling}
+% Next, we get ready to handle keys like |height=4cm| or |width=3cm| or |ppi=72|.
+% \begin{macrocode}
+\define@cmdkeys{moodle@includegraphics}[moodle@graphics@]{ppi}
+\define@cmdkey{moodle}[moodle@graphics@]{ppi}{}% This is so the ppi key can be set at the document, quiz, or question level.
+\define@cmdkeys{Gin}{ppi}% This is so the original \includegraphics will not object to a key of ppi.
+\setkeys{moodle@includegraphics}{ppi=103}
+
+\newdimen\moodle@graphics@temp@dimen
+\newcount\moodle@graphics@height@pixels
+\newcount\moodle@graphics@width@pixels
+\def\moodle@graphics@dimentopixels#1#2{%
+ \moodle@graphics@temp@dimen=#2\relax
+ \moodle@graphics@temp@dimen=0.013837\moodle@graphics@temp@dimen
+ \xa\moodle@graphics@temp@dimen\xa=\moodle@graphics@ppi\moodle@graphics@temp@dimen
+ #1=\moodle@graphics@temp@dimen
+ \divide #1 by 65536\relax
+}
+\define@key{moodle@includegraphics}{height}[]{%
+ \moodle@graphics@dimentopixels{\moodle@graphics@height@pixels}{#1}%
+}
+\define@key{moodle@includegraphics}{width}[]{%
+ \moodle@graphics@dimentopixels{\moodle@graphics@width@pixels}{#1}%
+}
+\setkeys{moodle@includegraphics}{height=0pt,width=0pt}
+% \end{macrocode}
+%
+% \subsubsection{Graphics conversion to HTML}
+% \begin{macrocode}
+\html@action@def\includegraphics{\moodle@includegraphics@int}%
+ % Note that \htmlize@do@actioncs will 'patch' this by putting
+ % '\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook'
+ % at the end. We want those 3 tokens to occur instead after
+ % the graphics filename.
+\def\moodle@includegraphics@int#1#2#3{\moodle@includegraphics@int@int}%
+ % This gobbles up those three spurious tokens,
+ % which we will re-insert after our work is done.
+\newcommand\moodle@includegraphics@int@int[2][]{%
+ \bgroup% The grouping is to localize the changes caused by \setkeys.
+ \message{moodle.sty: Processing \string\includegraphics[#1]{#2} for HTML...^^J}
+ \setkeys*{moodle@includegraphics}{#1}%
+ % Height or width should be given in TeX dimensions like cm or pt or in,
+ % and are converted to pixels for web use using the ppi key.
+ % TO DO: Can we modify \includegraphics to accept height or width in
+ % pixels?
+ % TO DO: What about \includegraphics[scale=0.7] ?
+ % Other keys: keepaspectratio=true|false, angle (rotation), clip & trim
+ \ifnum\moodle@graphics@height@pixels=0\relax
+ \ifnum\moodle@graphics@width@pixels=0\relax
+ % No size specified. Default to height of 200 pixels.
+ \def\moodle@graphics@geometry{x200}%
+ \def\moodle@graphics@htmlgeometry{}%
+ \else
+ % Width only specified.
+ \edef\moodle@graphics@geometry{\number\moodle@graphics@width@pixels}%
+ \edef\moodle@graphics@htmlgeometry{width=\number\moodle@graphics@width@pixels}%
+ \fi
+ \else
+ \ifnum\moodle@graphics@width@pixels=0\relax
+ % Height only specified. The `x' is part of the syntax.
+ \edef\moodle@graphics@geometry{x\number\moodle@graphics@height@pixels}%
+ \edef\moodle@graphics@htmlgeometry{height=\number\moodle@graphics@height@pixels}%
+ \else
+ % Height and width both specified. The `!' is part of the syntax.
+ \edef\moodle@graphics@geometry{\number\moodle@graphics@width@pixels x\number\moodle@graphics@height@pixels!}%
+ \edef\moodle@graphics@htmlgeometry{width=\number\moodle@graphics@width@pixels\otherspace height=\number\moodle@graphics@height@pixels}%
+ \fi
+ \fi
+ %First, convert it to PNG
+ \edef\cmdline{\htmlize@imagemagick@convert\otherspace #2 -resize \moodle@graphics@geometry\otherspace #2.png}%
+ \message{moodle.sty: Converting '#2' to PNG...^^J}%
+ \expandafter\immediate\expandafter\write18\expandafter{\cmdline}%
+ %Next, convert the PNG to base64 encoding
+ \def\cmdline{\openssl\otherspace enc -base64 -in #2.png -out #2.enc}%
+ \message{moodle.sty: Converting '#2.png' to base64...^^J}%
+ \expandafter\immediate\expandafter\write18\expandafter{\cmdline}%
+ %Now, save that base64 encoding in a TeX macro
+ \def\moodle@newpic@baselxiv{}%
+ \message{moodle.sty: Reading base64 file '#2.enc'...^^J}%
+ \openin\baseLXIVdatafile=#2.enc\relax
+ \savebaselxivdata@recursive
+ \closein\baseLXIVdatafile
+ \xa\global\xa\let\csname picbaselxiv@graphics@#2\endcsname=\moodle@newpic@baselxiv%
+ \edef\htmlize@imagetag{<IMG \moodle@graphics@htmlgeometry\otherspace SRC="data:image/png;base64,\csname picbaselxiv@graphics@#2\endcsname">}%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}%
+ \message{moodle.sty: <IMG> tag inserted.^^J}%
+ \egroup
+ % Now we re-insert the code to get the HTMLizing going again.
+ \xa\htmlize@proceedwiththerest\htmlize@afteraction@hook
+}
+% \end{macrocode}
+% The following code accomplishes the reading of an |.enc| file into memory.
+% It is also used by the \TikZ\ code below.
+% \begin{macrocode}
+\newread\baseLXIVdatafile
+\def\savebaselxivdata@recursive{%
+ \ifeof\baseLXIVdatafile
+ \let\baselxiv@next=\relax
+ \else
+ \read\baseLXIVdatafile to \datalinein
+ %\message{<<\datalinein>>^^J}
+ \ifx\datalinein\@moodle@par
+ \let\baselxiv@next=\relax
+ \else
+ %We add tokens manually, rather than with \g@addto@macro, to save time.
+ \xa\xa\xa\gdef\xa\xa\xa\moodle@newpic@baselxiv\xa\xa\xa{\xa\moodle@newpic@baselxiv\datalinein^^J}%
+ \let\baselxiv@next=\savebaselxivdata@recursive
+ \fi
+ \fi
+ \baselxiv@next
+}
+% \end{macrocode}
+%
+% \subsection{\TikZ\ Picture Handling}
+% If the user is not using the \TikZ\ package, there is no need to waste time
+% loading it. Without \TikZ\ loaded, however, many of the following commands
+% are undefined.
+% Our solution is to wait until |\AtBeginDocument| and then test whether
+% \TikZ\ is loaded. If so, we make the appropriate definitions.
+% \begin{macrocode}
+\newif\ifmoodle@tikzloaded
+\moodle@tikzloadedfalse
+\AtBeginDocument{
+ \ifx\tikzpicture\@undefined
+ \moodle@tikzloadedfalse
+ \else
+ \moodle@tikzloadedtrue
+ \fi
+ \ifmoodle@tikzloaded
+ \usetikzlibrary{external}
+ \tikzexternalize%
+ \tikzset{external/force remake}%
+
+ \ifpdf
+ \def\pdftopng{\edef\gscmdline{\gs\otherspace -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png -r200 \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.pdf}%
+ \expandafter\immediate\expandafter\write18\expandafter{\gscmdline}}%
+ \else
+ \def\pstopng{\edef\gscmdline{\gs\otherspace -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png -r200 \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.ps}%
+ \expandafter\immediate\expandafter\write18\expandafter{\gscmdline}}%
+ \fi
+ \def\pngtobaselxiv{\edef\opensslcmdline{\openssl\otherspace enc -base64 -in \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png -out \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.enc}%
+ \expandafter\immediate\expandafter\write18\expandafter{\opensslcmdline}}%
+
+ \let\moodle@oldtikzpicture=\tikzpicture
+
+ %The following code lets us run things *before* the normal \begin{tikzpicture}.
+ \renewenvironment{tikzpicture}{%
+ \global\advance\numconvertedpictures by 1\relax
+ %\jobnamewithsuffixtomacro{\htmlize@picbasename}{-tikztemp-\the\numconvertedpictures}%
+ %\xa\tikzsetnextfilename\xa{\htmlize@picbasename}%
+ \tikzsetnextfilename{\tikzexternalrealjob-tikztemp-\the\numconvertedpictures}%
+ \moodle@oldtikzpicture%
+ }{}%
+ % However, the tikz externalize library does *not* run \end{tikzpicture}.
+ % In order to run commands after the tikz picture is done compiling, we need to
+ % use a hook into \tikzexternal@closeenvironments.
+
+ \g@addto@macro{\tikzexternal@closeenvironments}{%
+ \moodle@endtikzpicture@hook
+ }
+ \def\moodle@endtikzpicture@hook{%
+ \@moodle@ifgeneratexml{%
+ \ifpdf
+ \message{moodle.sty: Converting picture '\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.pdf' to PNG...^^J}%
+ \pdftopng
+ \else
+ \pstopng
+ \fi
+ \message{moodle.sty: Converting '\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png' to base64...^^J}%
+ \pngtobaselxiv
+ \message{moodle.sty: Reading base64 file '\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.enc'...^^J}%
+ \savebaselxivdata
+ \message{moodle.sty: base64 data saved.^^J}%
+ }{}%
+ }
+ \tikzset{external/optimize=true}
+ \tikzset{external/optimize command away={\VerbatimInput}{1}}
+ %
+ % The HTMLizer version of the tikzpicture environment,
+ % which writes an <IMG> tag to the XML file.
+ \htmlize@record@environment{tikzpicture}
+ \g@addto@macro\htmlize@activate@environments{%
+ \let\tikzpicture\relax\let\endtikzpicture\relax
+ \NewEnviron{tikzpicture}[1][]{%
+ \global\advance\numpicturesread by 1\relax
+ \edef\htmlize@imagetag{<IMG SRC="data:image/png;base64,\csname picbaselxiv@\the\numpicturesread\endcsname">}%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}%
+ }[\htmlize@patchendenvironment]%
+ }%
+ \else
+ %TikZ not loaded. Provide dummy definitions for commands.
+ \long\def\tikzifexternalizing#1#2{#2}%
+ \fi
+}
+
+\newcount\numconvertedpictures
+\numconvertedpictures=0\relax
+\newcount\numpicturesread
+\numpicturesread=0\relax
+
+\def\savebaselxivdata{%
+ \def\moodle@newpic@baselxiv{}%
+ \openin\baseLXIVdatafile=\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.enc\relax
+ \savebaselxivdata@recursive
+ \closein\baseLXIVdatafile
+ \xa\global\xa\let\csname picbaselxiv@\the\numconvertedpictures\endcsname=\moodle@newpic@baselxiv%
+}
+
+\def\@moodle@par{\par}%
+% \end{macrocode}
+% Finally, we clean up our mess by deleting the temporary PDF, PNG, and ENC
+% files we created.
+% \begin{macrocode}
+\AtEndDocument{%
+ \ifmoodle@tikzloaded
+ \@moodle@ifgeneratexml{%
+ \ifwindows
+ \immediate\write18{del \tikzexternalrealjob-tikztemp-*.*}%
+ \else
+ \immediate\write18{rm \tikzexternalrealjob-tikztemp-*.*}%
+ \fi
+ }{}%
+ \fi
+}
+
+% TO DO:
+% * sizing options for TikZ pictures?
+% * In cloze multi, how to handle HTML or TeX in answers? In particular, what about ~?
+% \end{macrocode}
+%
+% \Finale
+\endinput
diff --git a/macros/latex/contrib/moodle/moodle.ins b/macros/latex/contrib/moodle/moodle.ins
new file mode 100644
index 0000000000..16afd4503b
--- /dev/null
+++ b/macros/latex/contrib/moodle/moodle.ins
@@ -0,0 +1,57 @@
+%% moodle.ins
+%% Copyright 2016 by Anders O.F. Hendrickson
+%%
+%% This work may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3
+%% 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.3 or later is part of all distributions of LaTeX
+%% version 2005/12/01 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%%
+%% The Current Maintainer of this work is Anders O.F. Hendrickson.
+%%
+%% This work consists of the files moodle.dtx and moodle.ins
+%% and the derived file moodle.sty.
+
+\input docstrip.tex
+\keepsilent
+
+\usedir{tex/latex/moodle}
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2016 by Anders Hendrickson <anders.hendrickson@snc.edu>
+
+This work may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3
+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.3 or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+
+\endpreamble
+
+\generate{\file{moodle.sty}{\from{moodle.dtx}{package}}}
+
+\obeyspaces
+\Msg{*************************************************************}
+\Msg{* *}
+\Msg{* To finish the installation you have to move the following *}
+\Msg{* file into a directory searched by TeX: *}
+\Msg{* *}
+\Msg{* moodle.sty *}
+\Msg{* *}
+\Msg{* To produce the documentation run the file moodle.dtx *}
+\Msg{* through LaTeX. *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{*************************************************************}
+
+\endbatchfile
diff --git a/macros/latex/contrib/moodle/moodle.pdf b/macros/latex/contrib/moodle/moodle.pdf
new file mode 100644
index 0000000000..f5dd6cae3c
--- /dev/null
+++ b/macros/latex/contrib/moodle/moodle.pdf
Binary files differ