summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/stex/source/extensions/problem.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/stex/source/extensions/problem.dtx')
-rw-r--r--macros/latex/contrib/stex/source/extensions/problem.dtx910
1 files changed, 910 insertions, 0 deletions
diff --git a/macros/latex/contrib/stex/source/extensions/problem.dtx b/macros/latex/contrib/stex/source/extensions/problem.dtx
new file mode 100644
index 0000000000..b21b1c493d
--- /dev/null
+++ b/macros/latex/contrib/stex/source/extensions/problem.dtx
@@ -0,0 +1,910 @@
+% \iffalse meta-comment
+% An Infrastructure for Problems
+% Copyright (c) 2019 Michael Kohlhase, all rights reserved
+% this file is released under the
+% LaTeX Project Public License (LPPL)
+% The original of this file is in the public repository at
+% http://github.com/sLaTeX/sTeX/
+% \fi
+%
+% \iffalse
+%
+%<*driver>
+\def\bibfolder{../../lib/bib}
+\input{../../doc/docheader}
+\RequirePackage[hints,solutions,notes]{problem}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \iffalse\CheckSum{318}\fi
+%
+% ^^A\changes{v0.9}{2006/09/18}{First Version with Documentation}
+%
+% \GetFileInfo{problem.sty}
+%
+% \MakeShortVerb{\|}
+%
+% \title{\texttt{problem.sty}: An Infrastructure for formatting Problems\thanks{Version {\fileversion} (last revised
+% {\filedate})}}
+% \author{Michael Kohlhase\\
+% FAU Erlangen-N\"urnberg\\
+% \url{http://kwarc.info/kohlhase}}
+% \maketitle
+%
+%\ifinfulldoc\else
+% This is the documentation for the \pkg{problem} package.
+% For a more high-level introduction,
+% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the
+% \href{\basedocurl/stex.pdf}{full \sTeX documentation}.
+%
+% \input{../../doc/packages/problem}
+% \fi
+%
+% \begin{documentation}
+% The |problem| package supplies an infrastructure that allows specify problems and to
+% reuse them efficiently in multiple environments.
+%
+%\section{Introduction}\label{sec:intro}
+%
+% The |problem| package supplies an infrastructure that allows specify problem. Problems
+% are text fragments that come with auxiliary functions: hints, notes, and
+% solutions\footnote{for the moment multiple choice problems are not supported, but may
+% well be in a future version}. Furthermore, we can specify how long the solution to a
+% given problem is estimated to take and how many points will be awarded for a perfect
+% solution.
+%
+% Finally, the |problem| package facilitates the management of problems in small files,
+% so that problems can be re-used in multiple environment.
+%
+% \section{The User Interface}\label{sec:ui}
+%
+% \subsection{Package Options}
+% The |problem| package takes the options \DescribeMacro{solutions}|solutions| (should
+% solutions be output?), \DescribeMacro{notes}|notes| (should the problem notes be
+% presented?), \DescribeMacro{hints}|hints| (do we give the hints?),
+% \DescribeMacro{gnotes}|gnotes| (do we show grading notes?), \DescribeMacro{pts}|pts| (do
+% we display the points awarded for solving the problem?), \DescribeMacro{min}|min| (do we
+% display the estimated minutes for problem soling). If theses are specified, then the
+% corresponding auxiliary parts of the problems are output, otherwise, they remain
+% invisible.
+%
+% The \DescribeMacro{boxed}|boxed| option specifies that problems should be formatted in
+% framed boxes so that they are more visible in the text. Finally, the
+% \DescribeMacro{test}|test| option signifies that we are in a test situation, so this
+% option does not show the solutions (of course), but leaves space for the students to
+% solve them.
+%
+% The \DescribeMacro{mh}|mh| option turns on MathHub support; see \cite{Kohlhase:mss}.
+%
+% Finally, if the \DescribeMacro{showmeta}|showmeta| is set, then the metadata keys are
+% shown (see~\cite{Kohlhase:metakeys} for details and customization options).
+%
+% \subsection{Problems and Solutions}\label{sec:user:probsols}
+%
+% \DescribeEnv{problem} The main environment provided by the |problem| package is
+% (surprise surprise) the |problem| environment. It is used to mark up problems and
+% exercises. The environment takes an optional KeyVal argument with the keys
+% \DescribeMacro{id}|id| as an identifier that can be reference later,
+% \DescribeMacro{pts}|pts| for the points to be gained from this exercise in homework or
+% quiz situations, \DescribeMacro{min}|min| for the estimated minutes needed to solve the
+% problem, and finally \DescribeMacro{title}|title| for an informative title of the
+% problem. For an example of a marked up problem see Figure~\ref{fig:problem} and the
+% resulting markup see Figure~\ref{fig:result}.
+%
+%\begin{exfig}
+% \begin{verbatim}
+% \usepackage[solutions,hints,pts,min]{problem}
+% \begin{document}
+% \begin{sproblem}[id=elefants,pts=10,min=2,title=Fitting Elefants]
+% How many Elefants can you fit into a Volkswagen beetle?
+% \begin{hint}
+% Think positively, this is simple!
+% \end{hint}
+% \begin{exnote}
+% Justify your answer
+% \end{exnote}
+% \begin{solution}[for=elefants,height=3cm]
+% Four, two in the front seats, and two in the back.
+% \begin{gnote}
+% if they do not give the justification deduct 5 pts
+% \end{gnote}
+% \end{solution}
+% \end{sproblem}
+% \end{document}
+% \end{verbatim}
+% \caption{A marked up Problem}\label{fig:problem}
+% \end{exfig}
+%
+% \DescribeEnv{solution} The |solution| environment can be to specify a solution to a
+% problem. If the \DescribeMacro{solutions}|solutions| option is set or |\solutionstrue|
+% is set in the text, then the solution will be presented in the output. The |solution|
+% environment takes an optional KeyVal argument with the keys \DescribeMacro{id}|id| for
+% an identifier that can be reference \DescribeMacro{for}|for| to specify which problem
+% this is a solution for, and \DescribeMacro{height}|height| that allows to specify the
+% amount of space to be left in test situations (i.e. if the \DescribeMacro{test}|test|
+% option is set in the |\usepackage| statement).
+%
+%\begin{exfig}
+% \begin{minipage}{.9\linewidth}
+% \begin{sproblem}[id=elefants.prob,title=Fitting Elefants]
+% How many Elefants can you fit into a Volkswagen beetle?
+% \begin{hint}
+% Think positively, this is simple!
+% \end{hint}
+% \begin{exnote}
+% Justify your answer
+% \end{exnote}
+% \smallskip\noindent\hrule\textbf{Solution:}
+% Four, two in the front seats, and two in the back.
+% \hrule
+% \end{sproblem}
+% \end{minipage}
+% \caption{The Formatted Problem from Figure~\ref{fig:problem}}\label{fig:result}
+% \end{exfig}
+%
+% \DescribeEnv{hint}\DescribeEnv{exnote} The |hint| and |exnote| environments can be used
+% in a |problem| environment to give hints and to make notes that elaborate certain
+% aspects of the problem.
+%
+% \DescribeEnv{gnote} The |gnote| (grading notes) environment can be used to document
+% situtations that may arise in grading.
+%
+% Sometimes we would like to locally override the |solutions| option we have given to the
+% package. To turn on solutions we use the
+% \DescribeMacro{\startsolutions}|\startsolutions|, to turn them off,
+% \DescribeMacro{\stopsolutions}|\stopsolutions|. These two can be used at any point in
+% the documents.
+%
+% Also, sometimes, we want content (e.g. in an exam with master solutions) conditional on
+% whether solutions are shown. This can be done with the
+% \DescribeMacro{\ifsolutions}|\ifsolutions| conditional.
+%
+% \subsection{Multiple Choice Blocks}\label{sec:user:mcq}
+%
+% Multiple choice blocks can be formatted using the \DescribeMacro{mcb}|mcb| environment,
+% in which single choices are marked up with
+% \DescribeMacro{\mcc}|\mcc[|\meta{keyvals}|]{|\meta{text}|}| macro, which takes an
+% optional key/value argument \meta{keyvals} for choice metadata and a required argument
+% \meta{text} for the proposed answer text. The following keys are supported
+% \begin{itemize}
+% \item \DescribeMacro{T}|T| for true answers, \DescribeMacro{F}|F| for false ones,
+% \item \DescribeMacro{Ttext}|Ttext| the verdict for true answers,
+% \DescribeMacro{Ftext}|Ftext| for false ones, and
+% \item \DescribeMacro{feedback}|feedback| for a short feedback text given to the student.
+% \end{itemize}
+% See Figure~\ref{fig: mcq} for an example
+%\begin{exfig}
+% \begin{verbatim}
+% \begin{sproblem}[title=Functions]
+% What is the keyword to introduce a function definition in python?
+% \begin{mcb}
+% \mcc[T]{def}
+% \mcc[F,feedback=that is for C and C++]{function}
+% \mcc[F,feedback=that is for Standard ML]{fun}
+% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void}
+% \end{mcb}
+% \end{sproblem}
+% \end{verbatim}
+% \solutionsfalse\hrule
+% \begin{sproblem}[title=Functions]
+% What is the keyword to introduce a function definition in python?
+% \begin{mcb}
+% \mcc[T]{def}
+% \mcc[F,feedback=that is for C and C++]{function}
+% \mcc[F,feedback=that is for Standard ML]{fun}
+% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void}
+% \end{mcb}
+% \end{sproblem}
+% \solutionstrue\hrule
+% \begin{sproblem}[title=Functions]
+% What is the keyword to introduce a function definition in python?
+% \begin{mcb}
+% \mcc[T]{def}
+% \mcc[F,feedback=that is for C and C++]{function}
+% \mcc[F,feedback=that is for Standard ML]{fun}
+% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void}
+% \end{mcb}
+% \end{sproblem}
+% \caption{A Problem with a multiple choice block}\label{fig:mcq}
+% \end{exfig}
+%
+% \subsection{Including Problems}\label{sec:user:includeproblem}
+%
+% The \DescribeMacro{\includeproblem}|\includeproblem| macro can be used to include a
+% problem from another file. It takes an optional KeyVal argument and a second argument
+% which is a path to the file containing the problem (the macro assumes that there is only
+% one problem in the include file). The keys \DescribeMacro{title}|title|,
+% \DescribeMacro{min}|min|, and \DescribeMacro{pts}|pts| specify the problem title, the
+% estimated minutes for solving the problem and the points to be gained, and their values
+% (if given) overwrite the ones specified in the |problem| environment in the included
+% file.
+%
+% \subsection{Reporting Metadata}\label{sec:user:reporting}
+%
+% The sum of the points and estimated minutes (that we specified in the |pts| and |min|
+% keys to the |problem| environment or the |\includeproblem| macro) to the log file and
+% the screen after each run. This is useful in preparing exams, where we want to make sure
+% that the students can indeed solve the problems in an allotted time period.
+%
+% The |\min| and |\pts| macros allow to specify (i.e. to print to the margin) the
+% distribution of time and reward to parts of a problem, if the |pts| and |pts| package
+% options are set. This allows to give students hints about the estimated time and the
+% points to be awarded.
+%
+% \section{Limitations}\label{sec:limitations}
+%
+% In this section we document known limitations. If you want to help alleviate them,
+% please feel free to contact the package author. Some of them are currently discussed in
+% the \sTeX GitHub repository~\cite{sTeX:github:on}.
+% \begin{enumerate}
+% \item none reported yet
+% \end{enumerate}
+%
+% \end{documentation}
+% \begin{implementation}
+%
+% \section{The Implementation}\label{sec:implementation}
+%
+% \subsection{Package Options}\label{sec:impl:options}
+%
+% The first step is to declare (a few) package options that handle whether certain
+% information is printed or not. They all come with their own conditionals that are set by
+% the options.
+%
+% \begin{macrocode}
+%<*package>
+%<@@=problems>
+\ProvidesExplPackage{problem}{2022/02/24}{3.0.0}{Semantic Markup for Problems}
+\RequirePackage{l3keys2e}
+
+\keys_define:nn { problem / pkg }{
+ notes .default:n = { true },
+ notes .bool_set:N = \c_@@_notes_bool,
+ gnotes .default:n = { true },
+ gnotes .bool_set:N = \c_@@_gnotes_bool,
+ hints .default:n = { true },
+ hints .bool_set:N = \c_@@_hints_bool,
+ solutions .default:n = { true },
+ solutions .bool_set:N = \c_@@_solutions_bool,
+ pts .default:n = { true },
+ pts .bool_set:N = \c_@@_pts_bool,
+ min .default:n = { true },
+ min .bool_set:N = \c_@@_min_bool,
+ boxed .default:n = { true },
+ boxed .bool_set:N = \c_@@_boxed_bool,
+ unknown .code:n = {}
+}
+\newif\ifsolutions
+
+\ProcessKeysOptions{ problem / pkg }
+\bool_if:NTF \c_@@_solutions_bool {
+ \solutionstrue
+}{
+ \solutionsfalse
+}
+% \end{macrocode}
+%
+% Then we make sure that the necessary packages are loaded (in the right versions).
+% \begin{macrocode}
+\RequirePackage{comment}
+% \end{macrocode}
+%
+% The next package relies on the \LaTeX3 kernel, which \latexml only partially
+% supports. As it is purely presentational, we only load it when the |boxed| option is
+% given and we run {\latexml}.
+%
+% \begin{macrocode}
+\bool_if:NT \c_@@_boxed_bool { \RequirePackage{mdframed} }
+% \end{macrocode}
+%
+% \begin{macro}{\prob@*@kw}
+% For multilinguality, we define internal macros for keywords that can be specialized in
+% |*.ldf| files.
+% \begin{macrocode}
+\def\prob@problem@kw{Problem}
+\def\prob@solution@kw{Solution}
+\def\prob@hint@kw{Hint}
+\def\prob@note@kw{Note}
+\def\prob@gnote@kw{Grading}
+\def\prob@pt@kw{pt}
+\def\prob@min@kw{min}
+% \end{macrocode}
+% \end{macro}
+%
+% For the other languages, we set up triggers
+% \begin{macrocode}
+\AddToHook{begindocument}{
+ \ltx@ifpackageloaded{babel}{
+ \makeatletter
+ \clist_set:Nx \l_tmpa_clist {\bbl@loaded}
+ \clist_if_in:NnT \l_tmpa_clist {ngerman}{
+ \input{problem-ngerman.ldf}
+ }
+ \clist_if_in:NnT \l_tmpa_clist {finnish}{
+ \input{problem-finnish.ldf}
+ }
+ \clist_if_in:NnT \l_tmpa_clist {french}{
+ \input{problem-french.ldf}
+ }
+ \clist_if_in:NnT \l_tmpa_clist {russian}{
+ \input{problem-russian.ldf}
+ }
+ \makeatother
+ }{}
+}
+% \end{macrocode}
+%
+% \subsection{Problems and Solutions}\label{sec:impl:probsols}
+%
+% We now prepare the KeyVal support for problems. The key macros just set appropriate
+% internal macros.
+%
+% \begin{macrocode}
+\keys_define:nn{ problem / problem }{
+ id .str_set_x:N = \l_@@_prob_id_str,
+ pts .tl_set:N = \l_@@_prob_pts_tl,
+ min .tl_set:N = \l_@@_prob_min_tl,
+ title .tl_set:N = \l_@@_prob_title_tl,
+ type .tl_set:N = \l_@@_prob_type_tl,
+ refnum .int_set:N = \l_@@_prob_refnum_int
+}
+\cs_new_protected:Nn \_@@_prob_args:n {
+ \str_clear:N \l_@@_prob_id_str
+ \tl_clear:N \l_@@_prob_pts_tl
+ \tl_clear:N \l_@@_prob_min_tl
+ \tl_clear:N \l_@@_prob_title_tl
+ \tl_clear:N \l_@@_prob_type_tl
+ \int_zero_new:N \l_@@_prob_refnum_int
+ \keys_set:nn { problem / problem }{ #1 }
+ \int_compare:nNnT \l_@@_prob_refnum_int = 0 {
+ \let\l_@@_prob_refnum_int\undefined
+ }
+}
+% \end{macrocode}
+%
+% Then we set up a counter for problems.
+% \begin{macro}{\numberproblemsin}
+% \begin{macrocode}
+\newcounter{problem}
+\newcommand\numberproblemsin[1]{\@addtoreset{problem}{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prob@label}
+% We provide the macro |\prob@label| to redefine later to get context involved.
+% \begin{macrocode}
+\newcommand\prob@label[1]{#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prob@number}
+% We consolidate the problem number into a reusable internal macro
+% \begin{macrocode}
+\newcommand\prob@number{
+ \int_if_exist:NTF \l_@@_inclprob_refnum_int {
+ \prob@label{\int_use:N \l_@@_inclprob_refnum_int }
+ }{
+ \int_if_exist:NTF \l_@@_prob_refnum_int {
+ \prob@label{\int_use:N \l_@@_prob_refnum_int }
+ }{
+ \prob@label\theproblem
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prob@title}
+% We consolidate the problem title into a reusable internal macro as well. |\prob@title|
+% takes three arguments the first is the fallback when no title is given at all, the
+% second and third go around the title, if one is given.
+% \begin{macrocode}
+\newcommand\prob@title[3]{%
+ \tl_if_exist:NTF \l_@@_inclprob_title_tl {
+ #2 \l_@@_inclprob_title_tl #3
+ }{
+ \tl_if_exist:NTF \l_@@_prob_title_tl {
+ #2 \l_@@_prob_title_tl #3
+ }{
+ #1
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% With these the problem header is a one-liner
+%
+% \begin{macro}{\prob@heading}
+% We consolidate the problem header line into a separate internal macro that can be
+% reused in various settings.
+% \begin{macrocode}
+\def\prob@heading{
+ {\prob@problem@kw}\ \prob@number\prob@title{~}{~(}{)\strut}
+ %\sref@label@id{\prob@problem@kw~\prob@number}{}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% With this in place, we can now define the |problem| environment. It comes in two shapes,
+% depending on whether we are in boxed mode or not. In both cases we increment the problem
+% number and output the points and minutes (depending) on whether the respective options
+% are set.
+% \begin{environment}{sproblem}
+% \begin{macrocode}
+\newenvironment{sproblem}[1][]{
+ \_@@_prob_args:n{#1}%\sref@target%
+ \@in@omtexttrue% we are in a statement (for inline definitions)
+ \stepcounter{problem}\record@problem
+ \def\current@section@level{\prob@problem@kw}
+ \tl_if_exist:NTF \l_@@_inclprob_type_tl {
+ \tl_set_eq:NN \sproblemtype \l_@@_inclprob_type_tl
+ }{
+ \tl_set_eq:NN \sproblemtype \l_@@_prob_type_tl
+ }
+ \str_if_exist:NTF \l_@@_inclprob_id_str {
+ \str_set_eq:NN \sproblemid \l_@@_inclprob_id_str
+ }{
+ \str_set_eq:NN \sproblemid \l_@@_prob_id_str
+ }
+
+
+ \clist_set:No \l_tmpa_clist \sproblemtype
+ \tl_clear:N \l_tmpa_tl
+ \clist_map_inline:Nn \l_tmpa_clist {
+ \tl_if_exist:cT {_@@_sproblem_##1_start:}{
+ \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproblem_##1_start:}}
+ }
+ }
+ \tl_if_empty:NTF \l_tmpa_tl {
+ \_@@_sproblem_start:
+ }{
+ \l_tmpa_tl
+ }
+ \stex_ref_new_doc_target:n \sproblemid
+}{
+ \clist_set:No \l_tmpa_clist \sproblemtype
+ \tl_clear:N \l_tmpa_tl
+ \clist_map_inline:Nn \l_tmpa_clist {
+ \tl_if_exist:cT {_@@_sproblem_##1_end:}{
+ \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproblem_##1_end:}}
+ }
+ }
+ \tl_if_empty:NTF \l_tmpa_tl {
+ \_@@_sproblem_end:
+ }{
+ \l_tmpa_tl
+ }
+
+
+ \smallskip
+}
+
+
+\cs_new_protected:Nn \_@@_sproblem_start: {
+ \par\noindent\textbf\prob@heading\show@pts\show@min\\\ignorespacesandpars
+}
+\cs_new_protected:Nn \_@@_sproblem_end: {\par\smallskip}
+
+\newcommand\stexpatchproblem[3][] {
+ \str_set:Nx \l_tmpa_str{ #1 }
+ \str_if_empty:NTF \l_tmpa_str {
+ \tl_set:Nn \_@@_sproblem_start: { #2 }
+ \tl_set:Nn \_@@_sproblem_end: { #3 }
+ }{
+ \exp_after:wN \tl_set:Nn \csname _@@_sproblem_#1_start:\endcsname{ #2 }
+ \exp_after:wN \tl_set:Nn \csname _@@_sproblem_#1_end:\endcsname{ #3 }
+ }
+}
+
+
+\bool_if:NT \c_@@_boxed_bool {
+ \surroundwithmdframed{problem}
+}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{macro}{\record@problem}
+% This macro records information about the problems in the |*.aux| file.
+% \begin{macrocode}
+\def\record@problem{
+ \protected@write\@auxout{}
+ {
+ \string\@problem{\prob@number}
+ {
+ \tl_if_exist:NTF \l_@@_inclprob_pts_tl {
+ \l_@@_inclprob_pts_tl
+ }{
+ \l_@@_prob_pts_tl
+ }
+ }%
+ {
+ \tl_if_exist:NTF \l_@@_inclprob_min_tl {
+ \l_@@_inclprob_min_tl
+ }{
+ \l_@@_prob_min_tl
+ }
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@problem}
+% This macro acts on a problem's record in the |*.aux| file. It does not have any
+% functionality here, but can be redefined elsewhere (e.g. in the |assignment|
+% package).
+% \begin{macrocode}
+\def\@problem#1#2#3{}
+% \end{macrocode}
+% \end{macro}
+%
+% The \DescribeEnv{solution}|solution| environment is similar to the |problem|
+% environment, only that it is independent of the boxed mode. It also has it's own keys
+% that we need to define first.
+%
+% \begin{macrocode}
+\keys_define:nn { problem / solution }{
+ id .str_set_x:N = \l_@@_solution_id_str ,
+ for .tl_set:N = \l_@@_solution_for_tl ,
+ height .dim_set:N = \l_@@_solution_height_dim ,
+ creators .clist_set:N = \l_@@_solution_creators_clist ,
+ contributors .clist_set:N = \l_@@_solution_contributors_clist ,
+ srccite .tl_set:N = \l_@@_solution_srccite_tl
+}
+\cs_new_protected:Nn \_@@_solution_args:n {
+ \str_clear:N \l_@@_solution_id_str
+ \tl_clear:N \l_@@_solution_for_tl
+ \tl_clear:N \l_@@_solution_srccite_tl
+ \clist_clear:N \l_@@_solution_creators_clist
+ \clist_clear:N \l_@@_solution_contributors_clist
+ \dim_zero:N \l_@@_solution_height_dim
+ \keys_set:nn { problem / solution }{ #1 }
+}
+% \end{macrocode}
+% the next step is to define a helper macro that does what is needed to start a solution.
+% \begin{macrocode}
+\newcommand\@startsolution[1][]{
+ \_@@_solution_args:n { #1 }
+ \@in@omtexttrue% we are in a statement.
+ \bool_if:NF \c_@@_boxed_bool { \hrule }
+ \smallskip\noindent
+ {\textbf\prob@solution@kw :\enspace}
+ \begin{small}
+ \def\current@section@level{\prob@solution@kw}
+ \ignorespacesandpars
+}
+% \end{macrocode}
+%
+% \begin{macro}{\startsolutions}
+% for the |\startsolutions| macro we use the |\specialcomment| macro from the |comment|
+% package. Note that we use the |\@startsolution| macro in the start codes, that parses
+% the optional argument.
+% \begin{macrocode}
+\newcommand\startsolutions{
+ \specialcomment{solution}{\@startsolution}{
+ \bool_if:NF \c_@@_boxed_bool {
+ \hrule\medskip
+ }
+ \end{small}%
+ }
+ \bool_if:NT \c_@@_boxed_bool {
+ \surroundwithmdframed{solution}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\stopsolutions}
+% \begin{macrocode}
+\newcommand\stopsolutions{\excludecomment{solution}}
+% \end{macrocode}
+% \end{macro}
+%
+% so it only remains to start/stop solutions depending on what option was specified.
+%
+% \begin{macrocode}
+\ifsolutions
+ \startsolutions
+\else
+ \stopsolutions
+\fi
+% \end{macrocode}
+%
+% \begin{environment}{exnote}
+% \begin{macrocode}
+\bool_if:NTF \c_@@_notes_bool {
+ \newenvironment{exnote}[1][]{
+ \par\smallskip\hrule\smallskip
+ \noindent\textbf{\prob@note@kw : }\small
+ }{
+ \smallskip\hrule
+ }
+}{
+ \excludecomment{exnote}
+}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{hint}
+% \begin{macrocode}
+\bool_if:NTF \c_@@_notes_bool {
+ \newenvironment{hint}[1][]{
+ \par\smallskip\hrule\smallskip
+ \noindent\textbf{\prob@hint@kw :~ }\small
+ }{
+ \smallskip\hrule
+ }
+ \newenvironment{exhint}[1][]{
+ \par\smallskip\hrule\smallskip
+ \noindent\textbf{\prob@hint@kw :~ }\small
+ }{
+ \smallskip\hrule
+ }
+}{
+ \excludecomment{hint}
+ \excludecomment{exhint}
+}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{gnote}
+% \begin{macrocode}
+\bool_if:NTF \c_@@_notes_bool {
+ \newenvironment{gnote}[1][]{
+ \par\smallskip\hrule\smallskip
+ \noindent\textbf{\prob@gnote@kw : }\small
+ }{
+ \smallskip\hrule
+ }
+}{
+ \excludecomment{gnote}
+}
+% \end{macrocode}
+% \end{environment}
+%
+% \subsection{Multiple Choice Blocks}\label{sec:impl:mcq}
+%
+% \begin{environment}{mcb}
+% \ednote{MK: maybe import something better here from a dedicated MC package}
+% \begin{macrocode}
+\newenvironment{mcb}{
+ \begin{enumerate}
+}{
+ \end{enumerate}
+}
+% \end{macrocode}
+% \end{environment}
+% we define the keys for the |mcc| macro
+% \begin{macrocode}
+\cs_new_protected:Nn \_@@_do_yes_param:Nn {
+ \exp_args:Nx \str_if_eq:nnTF { \str_lowercase:n{ #2 } }{ yes }{
+ \bool_set_true:N #1
+ }{
+ \bool_set_false:N #1
+ }
+}
+\keys_define:nn { problem / mcc }{
+ id .str_set_x:N = \l_@@_mcc_id_str ,
+ feedback .tl_set:N = \l_@@_mcc_feedback_tl ,
+ T .default:n = { true } ,
+ T .bool_set:N = \l_@@_mcc_t_bool ,
+ F .default:n = { true } ,
+ F .bool_set:N = \l_@@_mcc_f_bool ,
+ Ttext .code:n = {
+ \_@@_do_yes_param:Nn \l_@@_mcc_Ttext_bool { #1 }
+ } ,
+ Ftext .code:n = {
+ \_@@_do_yes_param:Nn \l_@@_mcc_Ftext_bool { #1 }
+ }
+}
+\cs_new_protected:Nn \l_@@_mcc_args:n {
+ \str_clear:N \l_@@_mcc_id_str
+ \tl_clear:N \l_@@_mcc_feedback_tl
+ \bool_set_true:N \l_@@_mcc_t_bool
+ \bool_set_true:N \l_@@_mcc_f_bool
+ \bool_set_true:N \l_@@_mcc_Ttext_bool
+ \bool_set_false:N \l_@@_mcc_Ftext_bool
+ \keys_set:nn { problem / mcc }{ #1 }
+}
+% \end{macrocode}
+%
+% \begin{macro}{\mcc}
+% \begin{macrocode}
+\newcommand\mcc[2][]{
+ \l_@@_mcc_args:n{ #1 }
+ \item #2
+ \ifsolutions
+ \\
+ \bool_if:NT \l_@@_mcc_t_bool {
+ % TODO!
+ % \ifcsstring{mcc@T}{T}{}{\mcc@Ttext}%
+ }
+ \bool_if:NT \l_@@_mcc_f_bool {
+ % TODO!
+ % \ifcsstring{mcc@F}{F}{}{\mcc@Ftext}%
+ }
+ \tl_if_empty:NTF \l_@@_mcc_feedback_tl {
+ !
+ }{
+ \l_@@_mcc_feedback_tl
+ }
+ \fi
+} %solutions
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Including Problems}\label{sec:impl:includeproblem}
+%
+% \begin{macro}{\includeproblem}
+% The |\includeproblem| command is essentially a glorified |\input| statement, it sets
+% some internal macros first that overwrite the local points. Importantly, it resets the
+% |inclprob| keys after the input.
+% \begin{macrocode}
+
+\keys_define:nn{ problem / inclproblem }{
+ id .str_set_x:N = \l_@@_inclprob_id_str,
+ pts .tl_set:N = \l_@@_inclprob_pts_tl,
+ min .tl_set:N = \l_@@_inclprob_min_tl,
+ title .tl_set:N = \l_@@_inclprob_title_tl,
+ refnum .int_set:N = \l_@@_inclprob_refnum_int,
+ type .tl_set:N = \l_@@_inclprob_type_tl,
+ mhrepos .str_set_x:N = \l_@@_inclprob_mhrepos_str
+}
+\cs_new_protected:Nn \_@@_inclprob_args:n {
+ \str_clear:N \l_@@_prob_id_str
+ \tl_clear:N \l_@@_inclprob_pts_tl
+ \tl_clear:N \l_@@_inclprob_min_tl
+ \tl_clear:N \l_@@_inclprob_title_tl
+ \tl_clear:N \l_@@_inclprob_type_tl
+ \int_zero_new:N \l_@@_inclprob_refnum_int
+ \str_clear:N \l_@@_inclprob_mhrepos_str
+ \keys_set:nn { problem / inclproblem }{ #1 }
+ \tl_if_empty:NT \l_@@_inclprob_pts_tl {
+ \let\l_@@_inclprob_pts_tl\undefined
+ }
+ \tl_if_empty:NT \l_@@_inclprob_min_tl {
+ \let\l_@@_inclprob_min_tl\undefined
+ }
+ \tl_if_empty:NT \l_@@_inclprob_title_tl {
+ \let\l_@@_inclprob_title_tl\undefined
+ }
+ \tl_if_empty:NT \l_@@_inclprob_type_tl {
+ \let\l_@@_inclprob_type_tl\undefined
+ }
+ \int_compare:nNnT \l_@@_inclprob_refnum_int = 0 {
+ \let\l_@@_inclprob_refnum_int\undefined
+ }
+}
+
+\cs_new_protected:Nn \_@@_inclprob_clear: {
+ \let\l_@@_inclprob_id_str\undefined
+ \let\l_@@_inclprob_pts_tl\undefined
+ \let\l_@@_inclprob_min_tl\undefined
+ \let\l_@@_inclprob_title_tl\undefined
+ \let\l_@@_inclprob_type_tl\undefined
+ \let\l_@@_inclprob_refnum_int\undefined
+ \let\l_@@_inclprob_mhrepos_str\undefined
+}
+\_@@_inclprob_clear:
+
+\newcommand\includeproblem[2][]{
+ \_@@_inclprob_args:n{ #1 }
+ \str_if_empty:NTF \l_@@_inclprob_mhrepos_str {
+ \input{#2}
+ }{
+ \stex_in_repository:nn{\l_@@_inclprob_mhrepos_str}{
+ \input{\mhpath{\l_@@_inclprob_mhrepos_str}{#2}}
+ }
+ }
+ \_@@_inclprob_clear:
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Reporting Metadata}
+%
+% For messages it is OK to have them in English as the whole documentation is, and we can
+% therefore assume authors can deal with it.
+%
+% \begin{macrocode}
+\AddToHook{enddocument}{
+ \bool_if:NT \c_@@_pts_bool {
+ \message{Total:~\arabic{pts}~points}
+ }
+ \bool_if:NT \c_@@_min_bool {
+ \message{Total:~\arabic{min}~minutes}
+ }
+}
+% \end{macrocode}
+%
+% The margin pars are reader-visible, so we need to translate
+%
+% \begin{macrocode}
+\def\pts#1{
+ \bool_if:NT \c_@@_pts_bool {
+ \marginpar{#1~\prob@pt@kw}
+ }
+}
+\def\min#1{
+ \bool_if:NT \c_@@_min_bool {
+ \marginpar{#1~\prob@min@kw}
+ }
+}
+% \end{macrocode}
+%
+% \begin{macro}{\show@pts}
+% The |\show@pts| shows the points: if no points are given from the outside and also no
+% points are given locally do nothing, else show and add. If there are outside points
+% then we show them in the margin.
+% \begin{macrocode}
+\newcounter{pts}
+\def\show@pts{
+ \tl_if_exist:NTF \l_@@_inclprob_pts_tl {
+ \bool_if:NT \c_@@_pts_bool {
+ \marginpar{\l_@@_inclprob_pts_tl\ \prob@pt@kw\smallskip}
+ \addtocounter{pts}{\l_@@_inclprob_pts_tl}
+ }
+ }{
+ \tl_if_exist:NT \l_@@_prob_pts_tl {
+ \bool_if:NT \c_@@_pts_bool {
+ \marginpar{\l_@@_prob_pts_tl\ \prob@pt@kw\smallskip}
+ \addtocounter{pts}{\l_@@_prob_pts_tl}
+ }
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% and now the same for the minutes
+% \begin{macro}{\show@min}
+% \begin{macrocode}
+\newcounter{min}
+\def\show@min{
+ \tl_if_exist:NTF \l_@@_inclprob_min_tl {
+ \bool_if:NT \c_@@_min_bool {
+ \marginpar{\l_@@_inclprob_pts_tl\ min}
+ \addtocounter{min}{\l_@@_inclprob_min_tl}
+ }
+ }{
+ \tl_if_exist:NT \l_@@_prob_min_tl {
+ \bool_if:NT \c_@@_min_bool {
+ \marginpar{\l_@@_prob_min_tl\ min}
+ \addtocounter{min}{\l_@@_prob_min_tl}
+ }
+ }
+ }
+}
+%</package>
+% \end{macrocode}
+% \end{macro}
+% \end{implementation}
+\endinput
+% LocalWords: GPL structuresharing STR dtx pts keyval xcomment CPERL DefKeyVal iffalse
+%%% Local Variables:
+%%% mode: doctex
+%%% TeX-master: t
+%%% End:
+% \fi
+% LocalWords: RequirePackage Semiverbatim DefEnvironment OptionalKeyVals soln texttt baz
+% LocalWords: exnote DefConstructor inclprob NeedsTeXFormat omd.sty textbackslash exfig
+% LocalWords: stopsolution fileversion filedate maketitle setcounter tocdepth newpage
+% LocalWords: tableofcontents showmeta showmeta solutionstrue usepackage minipage hrule
+% LocalWords: linewidth elefants.prob Elefants smallskip noindent textbf startsolutions
+% LocalWords: startsolutions stopsolutions stopsolutions includeproblem includeproblem
+% LocalWords: textsf HorIacJuc cscpnrr11 includemhproblem includemhproblem importmodule
+% LocalWords: importmhmodule foobar ldots latexml mhcurrentrepos mh-variants mh-variant
+% LocalWords: compactenum langle rangle langle rangle ltxml metakeys newif ifexnotes rm
+% LocalWords: exnotesfalse exnotestrue ifhints hintsfalse hintstrue ifsolutions ifpts
+% LocalWords: solutionsfalse ptsfalse ptstrue ifmin minfalse mintrue ifboxed boxedfalse
+% LocalWords: boxedtrue sref mdframed marginpar prob srefaddidkey addmetakey refnum kv
+% LocalWords: newcounter ifx thesection theproblem hfill newenvironment metasetkeys ltx
+% LocalWords: stepcounter currentsectionlevel xspace ignorespaces surroundwithmdframed
+% LocalWords: omdoc autoopen autoclose solvedinminutes kvi qw vals newcommand exhint
+% LocalWords: specialcomment excludecomment mhrepos xref marginpar addtocounter doctex
+% LocalWords: mh@currentrepos endinput
+