% \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}
%</driver>
% \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}
      }
    }
  }
}
%</package>
%    \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

