% \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\libfolder#1{../../lib/#1} \input{../../doc/stex-docheader} \RequirePackage[hints,solutions,notes]{problem} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \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 % \begin{documentation} % \begin{abstract} % 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}. % % The |problem| package supplies an infrastructure that allows specify problems (for % homework assignments, exams, or quizzes) and to reuse them efficiently in multiple % environments. % \end{abstract} % % \tableofcontents % \begin{sfragment}{User Interface} % \input{../../doc/packages/stex-problem} % \ednote{MK: the input does not work! it includes the commented stuff as well. } % \end{sfragment} % \end{documentation} % \fi % % \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/09/14}{3.2.0}{Semantic Markup for Problems} \RequirePackage{l3keys2e} \RequirePackage{amssymb}% for \Box \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, test .default:n = { true }, test .bool_set:N = \c_@@_test_bool, unknown .code:n = { \PassOptionsToPackage{\CurrentOption}{stex} } } \newif\ifsolutions \ProcessKeysOptions{ problem / pkg } \bool_if:NTF \c_@@_solutions_bool { \solutionstrue }{ \solutionsfalse } \RequirePackage{stex} % \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} \def\prob@correct@kw{Correct} \def\prob@wrong@kw{Wrong} % \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} \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{ngerman}}{ \input{problem-ngerman.ldf} } \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{finnish}}{ \input{problem-finnish.ldf} } \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{french}}{ \input{problem-french.ldf} } \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{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, imports .tl_set:N = \l_@@_prob_imports_tl, name .str_set_x:N = \l_@@_prob_name_str, refnum .int_set:N = \l_@@_prob_refnum_int } \cs_new_protected:Nn \_@@_prob_args:n { \str_clear:N \l_@@_prob_id_str \str_clear:N \l_@@_prob_name_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 \tl_clear:N \l_@@_prob_imports_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{sproblem}[section] \newcommand\numberproblemsin[1]{\@addtoreset{sproblem}{#1}} \def\theplainsproblem{\arabic{sproblem}} \def\thesproblem{\thesection.\theplainsproblem} % \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]{\thesection.#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\theplainsproblem } } } \def\sproblemautorefname{\prob@problem@kw} % \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_empty:NTF \l_@@_prob_title_tl { #1 }{ #2 \l_@@_prob_title_tl #3 } } } % \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) \refstepcounter{sproblem}\record@problem \def\current@section@level{\prob@problem@kw} \str_if_empty:NT \l_@@_prob_name_str { \seq_get_right:NN \g_stex_currentfile_seq \l_tmpa_str \seq_set_split:NnV \l_tmpa_seq . \l_tmpa_str \seq_get_left:NN \l_tmpa_seq \l_@@_prob_name_str } \stex_if_do_html:T{ \tl_if_empty:NF \l_@@_prob_title_tl { \exp_args:No \stex_document_title:n \l_@@_prob_title_tl } } \exp_args:Nno\stex_module_setup:nn{type=problem}\l_@@_prob_name_str \stex_reactivate_macro:N \STEXexport \stex_reactivate_macro:N \importmodule \stex_reactivate_macro:N \symdecl \stex_reactivate_macro:N \notation \stex_reactivate_macro:N \symdef \stex_if_do_html:T{ \begin{stex_annotate_env} {problem} { \l_stex_module_ns_str ? \l_stex_module_name_str } \stex_annotate_invisible:nnn{header}{} { \stex_annotate:nnn{language}{ \l_stex_module_lang_str }{} \stex_annotate:nnn{signature}{ \l_stex_module_sig_str }{} \str_if_eq:VnF \l_stex_module_meta_str {NONE} { \stex_annotate:nnn{metatheory}{ \l_stex_module_meta_str }{} } } } \stex_csl_to_imports:No \importmodule \l_@@_prob_imports_tl \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 } \stex_if_smsmode:F { \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 \stex_if_smsmode:TF \stex_smsmode_do: \ignorespacesandpars }{ \__stex_modules_end_module: \stex_if_smsmode:F{ \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 } } \stex_if_do_html:T{ \end{stex_annotate_env} } \smallskip } \seq_put_right:Nx\g_stex_smsmode_allowedenvs_seq{\tl_to_str:n{sproblem}} \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 .str_set_x:N = \l_@@_solution_for_str , type .str_set_x:N = \l_@@_solution_type_str , title .tl_set:N = \l_@@_solution_title_tl } \cs_new_protected:Nn \_@@_solution_args:n { \str_clear:N \l_@@_solution_id_str \str_clear:N \l_@@_solution_type_str \str_clear:N \l_@@_solution_for_str \tl_clear:N \l_@@_solution_title_tl \keys_set:nn { problem / solution }{ #1 } } % \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} \box_new:N \l_@@_solution_box \newenvironment{solution}[1][]{ \_@@_solution_args:n{#1} \stex_html_backend:TF{ \stex_if_do_html:T{ \begin{stex_annotate_env}{solution}{} \str_if_empty:NF \l_@@_solution_type_str { \par\noindent \stex_annotate_invisible:nnn{typestrings}{\sexampletype}{} } \noindent\textbf{Solution\tl_if_empty:NF\l_@@_solution_title_tl{~(\l_@@_solution_title_tl)}: }~ } }{ \setbox\l_@@_solution_box\vbox\bgroup \par\smallskip\hrule\smallskip \noindent\textbf{Solution\tl_if_empty:NF\l_@@_solution_title_tl{~(\l_@@_solution_title_tl)}: }~ } }{ \stex_html_backend:TF{ \stex_if_do_html:T{ \end{stex_annotate_env} } }{ \smallskip\hrule \egroup \bool_if:NT \c_@@_solutions_bool { \strut\par\noindent \box\l_@@_solution_box } } } \newcommand\startsolutions{ \bool_set_true:N \c_@@_solutions_bool \solutionstrue % \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{\bool_set_false:N \c_@@_solutions_bool \solutionsfalse}%\excludecomment{solution}} % \end{macrocode} % \end{macro} % % % \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{Markup for Added Value Services}\label{sec:impl:avs} % % \subsubsection{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 = { false } , T .bool_set:N = \l_@@_mcc_t_bool , F .default:n = { false } , F .bool_set:N = \l_@@_mcc_f_bool , Ttext .tl_set:N = \l_@@_mcc_Ttext_tl , Ftext .tl_set:N = \l_@@_mcc_Ftext_tl } \cs_new_protected:Nn \l_@@_mcc_args:n { \str_clear:N \l_@@_mcc_id_str \tl_clear:N \l_@@_mcc_feedback_tl \bool_set_false:N \l_@@_mcc_t_bool \bool_set_false:N \l_@@_mcc_f_bool \tl_clear:N \l_@@_mcc_Ttext_tl \tl_clear:N \l_@@_mcc_Ftext_tl \str_clear:N \l_@@_mcc_id_str \keys_set:nn { problem / mcc }{ #1 } } % \end{macrocode} % % \begin{macro}{\mcc} % \begin{macrocode} \def\mccTrueText{\textbf{\prob@correct@kw!~}} \def\mccFalseText{\textbf{\prob@wrong@kw!~}} \newcommand\mcc[2][]{ \l_@@_mcc_args:n{ #1 } \item[$\Box$] #2 \bool_if:NT \c_@@_solutions_bool{ \\ \bool_if:NT \l_@@_mcc_t_bool { \tl_if_empty:NTF\l_@@_mcc_Ttext_tl\mccTrueText\l_@@_mcc_Ttext_tl } \bool_if:NT \l_@@_mcc_f_bool { \tl_if_empty:NTF\l_@@_mcc_Ttext_tl\mccFalseText\l_@@_mcc_Ftext_tl } \tl_if_empty:NF \l_@@_mcc_feedback_tl { \emph{\l_@@_mcc_feedback_tl} } } } %solutions % \end{macrocode} % \end{macro} % % \subsubsection{Filling in Concrete Solutions} % % \begin{macro}{\includeproblem} % This is embarrasingly simple, but can grow over time. % \begin{macrocode} \newcommand\fillinsol[2][]{% \def\@test{#1} \quad% \ifsolutions\textcolor{red}{#1!}\else% \fbox{\ifx\@test\@empty\phantom{\huge{21}}\else\hspace{#1}\fi}% \fi} % \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 } \exp_args:No \stex_in_repository:nn\l_@@_inclprob_mhrepos_str{ \stex_html_backend:TF { \str_clear:N \l_tmpa_str \prop_get:NnNF \l_stex_current_repository_prop { narr } \l_tmpa_str { \prop_get:NnNF \l_stex_current_repository_prop { ns } \l_tmpa_str {} } \stex_annotate_invisible:nnn{includeproblem}{ \l_tmpa_str / #2 }{} }{ \begingroup \inputreftrue \tl_if_empty:nTF{ ##1 }{ \input{#2} }{ \input{ \c_stex_mathhub_str / ##1 / source / #2 } } \endgroup } } \_@@_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 { \tl_if_empty:NT\l_@@_prob_pts_tl{ \tl_set:Nn \l_@@_prob_pts_tl {0} } \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 { \tl_if_empty:NT\l_@@_prob_min_tl{ \tl_set:Nn \l_@@_prob_min_tl {0} } \marginpar{\l_@@_prob_min_tl\ min} \addtocounter{min}{\l_@@_prob_min_tl} } } } } % % \end{macrocode} % \end{macro} % % \subsection{Testing and Spacing} % % \begin{macro}{\testspace} % \begin{macrocode} \newcommand\testspace[1]{\bool_if:NT \c_@@_boxed_bool {\vspace*{#1}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\testnewpage} % \begin{macrocode} \newcommand\testnewpage{\bool_if:NT \c_@@_boxed_bool {\newpage}} % \end{macrocode} % \end{macro} % % \begin{macro}{\testemptypage} % \begin{macrocode} \newcommand\testemptypage[1][]{% \bool_if:NT \c_@@_boxed_bool {\begin{center}\hwexam@testemptypage@kw\end{center}\vfill\eject\else}} % \end{macrocode} % \end{macro} % % \begin{macro}{\test*space} % \begin{macrocode} \newcommand\testsmallspace{\testspace{1cm}} \newcommand\testmedspace{\testspace{2cm}} \newcommand\testbigspace{\testspace{3cm}} % \end{macrocode} % \end{macro} % % \end{implementation} % \ifinfulldoc\else\printbibliography\fi \endinput %%% Local Variables: %%% mode: doctex %%% TeX-master: t %%% End: % \fi % LocalWords: GPL structuresharing STR dtx pts keyval xcomment CPERL DefKeyVal iffalse % 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