% \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\stexdocpath{../doc} \input{\stexdocpath/stex-docheader} \stextoptitle{The \texttt{problem} Package}{problem} \docmodule % % \fi % % \begin{stexmanual} % \begin{sfragment}{Problem Manual} % \input{\stexdocpath/packages/stex-problem} % \end{sfragment} % \end{stexmanual} % % \begin{documentation} % \begin{sfragment}{Problem Documentation} % TODO % \end{sfragment} % \end{documentation} % % \begin{implementation} % % \section{Implementation: The problem Package} % % \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}{2025/11/11}{4.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, 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 } \newif\ifintest \bool_if:NTF \c_@@_test_bool { \intesttrue }{ \intestfalse } \RequirePackage{stex} \newcommand\precondition[2]{ \stex_get_symbol:n{#2} \tl_if_empty:NF \l_stex_get_symbol_uri { \str_case:nnTF {#1}{ {remember}{} {understand}{} {analyze}{} {evaluate}{} {apply}{} {create}{} }{ \ifstexhtml\else\bool_if:NT\c_stex_metadata_bool { \marginpar{\tiny \textbf{Precondition:}~#1~ \exp_args:Ne\symrefemph@uri{\stex_symbol_uri_name:N \l_stex_get_symbol_uri}{\l_stex_get_symbol_uri} } }\fi \stex_annotate_invisible:nn{ data-ftml-preconditionsymbol={\stex_use_symbol_uri:N \l_stex_get_symbol_uri}, data-ftml-preconditiondimension={#1} }{} }{\errmessage{Unknown~cognitive~dimension~#1}} } } \newcommand\objective[2]{ \stex_get_symbol:n{#2} \tl_if_empty:NF \l_stex_get_symbol_uri { \str_case:nnTF {#1}{ {remember}{} {understand}{} {analyze}{} {evaluate}{} {apply}{} {create}{} }{ \ifstexhtml\else\bool_if:NT\c_stex_metadata_bool { \marginpar{\tiny \textbf{Objective:}~#1~ \exp_args:Ne\symrefemph@uri{\stex_symbol_uri_name:N \l_stex_get_symbol_uri}{\l_stex_get_symbol_uri} } }\fi \stex_annotate_invisible:nn{ data-ftml-objectivesymbol={\stex_use_symbol_uri:N \l_stex_get_symbol_uri}, data-ftml-objectivedimension={#1} }{} }{\errmessage{Unknown~cognitive~dimension~#1}} } } % \end{macrocode} % % \begin{macro}{\problem@kw@*} % For multilinguality, we define internal macros for keywords that can be specialized in % |*.ldf| files. % \begin{macrocode} \AddToHook{begindocument}{ \ExplSyntaxOn\makeatletter \input{problem-english.ldf} \ltx@ifpackageloaded{babel}{ \clist_set:Nx \l_tmpa_clist {\exp_args:No \tl_to_str:n \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\ExplSyntaxOff } % \end{macrocode} % \end{macro} % % \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} \bool_new:N \l_stex_key_autogradable_bool \stex_keys_define:nnnn{ problem }{ \tl_clear:N \l_stex_key_pts_tl \tl_set:Nn \l_stex_key_min_tl 0 \str_clear:N \l_stex_key_name_str \str_clear:N \l_stex_key_mhrepos_str \bool_set_false:N \l_stex_key_autogradable_bool }{ pts .tl_set:N = \l_stex_key_pts_tl, min .tl_set:N = \l_stex_key_min_tl, name .str_set:N = \l_stex_key_name_str, autogradable .bool_set:N = \l_stex_key_autogradable_bool, archive .code:n = {}, %archive .str_set:N = \l_stex_key_mhrepos_str, %creators .code:n = {} %imports .tl_set:N = \l_@@_prob_imports_tl, %refnum .int_set:N = \l_@@_prob_refnum_int, }{id,title,style,uses} % \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\thesproblem{\arabic{#1}.\arabic{sproblem}} } \numberproblemsin{section} %\def\theplainsproblem{\arabic{sproblem}} %\def\thesproblem{\thesection.\theplainsproblem} % \end{macrocode} % \end{macro} % % \begin{environment}{sproblem} % \begin{macrocode} \cs_new:Nn \_@@_activate_macros: { \stex_reactivate_macro:N \solution \stex_reactivate_macro:N \mcb \stex_reactivate_macro:N \scb \stex_reactivate_macro:N \fillinsol \stex_reactivate_macro:N \hint \stex_reactivate_macro:N \exnote \stex_reactivate_macro:N \gnote } \fp_new:N \g_problem_total_pts_fp \fp_new:N \g_problem_total_min_fp \bool_new:N \l_@@_in_problem_bool \bool_new:N \l_@@_has_pts_bool \bool_new:N \l_@@_has_min_bool \bool_set_false:N \l_@@_in_problem_bool \stex_new_stylable_env:nnnnnnn {problem} {O{}}{ \bool_if:NT \l_@@_in_problem_bool { \msg_error:nn{stex}{error/nestedproblem} } \cs_if_exist:NTF \l_problem_inputproblem_keys_tl { \tl_put_left:Nn \l_problem_inputproblem_keys_tl {#1,} \exp_args:Nno \stex_keys_set:nn{problem}{ \l_problem_inputproblem_keys_tl } }{ \stex_keys_set:nn{problem}{#1} } \refstepcounter{sproblem} \stex_if_do_html:T { \str_if_empty:NT \l_stex_key_name_str { \stex_file_split_off_lang:NN \l_@@_path_seq \g_stex_current_file \seq_get_right:NN \l_@@_path_seq \l_stex_key_name_str } \exp_args:Nne \begin{stex_annotate_env} { data-ftml-problem={\l_stex_key_name_str}, %data-ftml-language={ \l_stex_current_language_str}, data-ftml-autogradable={\bool_if:NTF \l_stex_key_autogradable_bool {true}{false}} \tl_if_empty:NF \l_stex_key_pts_tl{,data-ftml-problempoints={\l_stex_key_pts_tl}} } \noindent \stex_annotate:nn{data-ftml-title={}}{\_stex_annotate_force_break:n{\l_stex_key_title_tl}} \tl_if_empty:NF \l_stex_key_title_tl { \exp_args:No \stexdoctitle \l_stex_key_title_tl } \_stex_annotate_force_break:n{} } \tl_set_eq:NN \thistitle \l_stex_key_title_tl \tl_if_empty:NT \l_stex_key_pts_tl { \tl_set:Nn \l_stex_key_pts_tl{0} } \bool_set_true:N \l_@@_in_problem_bool \tl_set_eq:NN \l_@@_pts_tl \l_stex_key_pts_tl \tl_set_eq:NN \l_@@_min_tl \l_stex_key_min_tl \tl_if_eq:NnTF \l_@@_pts_tl {0} {\bool_set_false:N \l_@@_has_pts_bool} {\bool_set_true:N \l_@@_has_pts_bool} \tl_if_eq:NnTF \l_@@_min_tl {0} {\bool_set_false:N \l_@@_has_min_bool} {\bool_set_true:N \l_@@_has_min_bool} \int_gzero:N \g_@@_subproblem_int \stex_if_do_html:F\stex_style_apply: \_stex_do_id: \_@@_activate_macros: }{ \fp_gadd:Nn \g_problem_total_pts_fp { \l_@@_pts_tl} \fp_gadd:Nn \g_problem_total_min_fp { \l_@@_min_tl} \_@@_record_problem: \stex_if_do_html:F\stex_style_apply: \stex_if_do_html:T{ \end{stex_annotate_env} } }{ \par\noindent\problemheader \stex_if_do_html:F{ \bool_if:NT \c_@@_pts_bool { \tl_if_eq:NnF \l_@@_pts_tl {0}{ \marginpar{\l_@@_pts_tl{}~\problem@kw@pts\smallskip} } } \bool_if:NT \c_@@_min_bool { \tl_if_eq:NnF \l_@@_min_tl {0} { \marginpar{\l_@@_min_tl{}~\problem@kw@minutes\smallskip} } } } \par \stex_ignore_spaces_and_pars: }{ \par\bigskip % \bool_if:NT \c_@@_test_bool \pagebreak }{s} \tl_set:Nn \problemheader { \stex_if_do_html:TF{ \tl_if_empty:NF \thistitle { \stex_annotate:nn{data-ftml-title={}}{\textbf{\thistitle}} } }{ \textbf{\sproblemautorefname{~}\thesproblem \tl_if_empty:NF \thistitle { {~}(\thistitle) } } } } \cs_new_protected:Nn \_@@_record_problem: { \exp_args:NNe \iow_now:Nn \@auxout { \problem@restore {\thesproblem}{\l_@@_pts_tl}{\l_@@_min_tl} } } \cs_new_protected:Npn \problem@restore #1 #2 #3 {} % \end{macrocode} % \end{environment} % % \begin{environment}{subproblem} % \begin{macrocode} \int_new:N \g_@@_subproblem_int \stex_new_stylable_env:nnnnnnn {subproblem} {O{}}{ \stex_keys_set:nn{problem}{#1} \bool_if:NF \l_@@_in_problem_bool{ \ifstexhtml\else \par{\bfseries WARNING~subproblem~to~be~used~in~some~problem}\par \fi \_@@_activate_macros: \bool_set_true:N \l_@@_in_problem_bool \tl_set:Nn \l_@@_pts_tl{0} \tl_set:Nn \l_@@_min_tl{0} } \str_if_empty:NT \l_stex_key_name_str { \stex_file_split_off_lang:NN \l_@@_path_seq \g_stex_current_file \seq_get_right:NN \l_@@_path_seq \l_stex_key_name_str } \stex_if_do_html:T { \str_if_empty:NT \l_stex_key_name_str { \stex_file_split_off_lang:NN \l_@@_path_seq \g_stex_current_file \seq_get_right:NN \l_@@_path_seq \l_stex_key_name_str } \exp_args:Nne \begin{stex_annotate_env} { data-ftml-subproblem={\l_stex_key_name_str}, %data-ftml-language={ \l_stex_current_language_str}, data-ftml-autogradable={\bool_if:NTF \l_stex_key_autogradable_bool {true}{false}} \tl_if_empty:NF \l_stex_key_pts_tl{,data-ftml-problempoints={\l_stex_key_pts_tl}} } \noindent \stex_annotate:nn{data-ftml-title={}}{\_stex_annotate_force_break:n{\l_stex_key_title_tl}} \tl_if_empty:NF \l_stex_key_title_tl { \exp_args:No \stexdoctitle \l_stex_key_title_tl } \tl_if_empty:NF \l_stex_key_title_tl { \exp_args:No \stexdoctitle \l_stex_key_title_tl } \_stex_annotate_force_break:n{} } \tl_if_empty:NT \l_stex_key_pts_tl { \tl_set:Nn \l_stex_key_pts_tl{0} } \int_gincr:N \g_@@_subproblem_int \bool_if:NF \l_@@_has_pts_bool { \tl_gset:Ne \l_@@_pts_tl {\fp_to_decimal:n {\l_@@_pts_tl + \l_stex_key_pts_tl}} } \bool_if:NF \l_@@_has_min_bool { \tl_gset:Ne \l_@@_min_tl {\fp_to_decimal:n {\l_@@_min_tl + \l_stex_key_min_tl}} } \stex_if_smsmode:F {\stex_if_do_html:F \stex_style_apply: } }{ \stex_if_do_html:TF{ \end{stex_annotate_env} }{\stex_if_smsmode:F\stex_style_apply:} }{ \begin{list}{}{ \setlength\topsep{0pt} \setlength\parsep{0pt} \setlength\rightmargin{0pt} }\item[\int_use:N \g_@@_subproblem_int .] \bool_if:NT \c_@@_pts_bool { \bool_if:NF \l_@@_has_pts_bool { \marginpar{\smallskip\l_stex_key_pts_tl{}~\problem@kw@pts} } } \bool_if:NT \c_@@_min_bool { \bool_if:NF \l_@@_has_min_bool{ \marginpar{\smallskip\l_stex_key_min_tl{}~\problem@kw@minutes} } } \ignorespaces }{ \end{list} }{} % \end{macrocode} % \end{environment} % % \begin{macro}{\includeproblem} % \begin{macrocode} \stex_keys_define:nnnn{ includeproblem }{ \str_clear:N \l_stex_key_mhrepos_str }{ archive .str_set:N = \l_stex_key_mhrepos_str, unknown .code:n = {} }{} \NewDocumentCommand\includeproblem{O{} m}{ \group_begin: \tl_set:Nn \l_problem_inputproblem_keys_tl {#1} \stex_keys_set:nn{includeproblem}{#1} \exp_args:Nno \use:nn{\inputref[}\l_stex_key_mhrepos_str]{#2} \group_end: } % \end{macrocode} % \end{macro} % % \begin{environment}{solution} % \begin{macrocode} \int_new:N \g_problem_id_counter \dim_new:N \l_stex_key_testspace_dim \stex_keys_define:nnnn{ solution }{ \str_clear:N \l_stex_key_answerclass_str \dim_zero:N \l_stex_key_testspace_dim }{ testspace .dim_set:N = \l_stex_key_testspace_dim, answerclass .str_set:N = \l_stex_key_answerclass_str }{id,title,style} \cs_new_protected:Nn \_@@_solution_start:n { \stex_keys_set:nn{ solution }{#1} \str_if_empty:NT \l_stex_key_id_str { \int_gincr:N \g_problem_id_counter \str_set:Nx \l_stex_key_id_str { SOLUTION_\int_use:N \g_problem_id_counter } } \stex_if_do_html:T{ \begin{stex_annotate_env}{ data-ftml-solution=\l_stex_key_id_str, data-ftml-answerclass={\l_stex_key_answerclass_str} } } } \stex_new_stylable_env:nnnnnnn { solution }{ O{} }{ \stex_if_do_html:TF{ \_@@_solution_start:n{#1} }{ \ifsolutions \_@@_solution_start:n{#1} \stex_style_apply: \else \stex_keys_set:nn{ solution }{#1} \testspace{\l_stex_key_testspace_dim} \setbox\l_tmpa_box\vbox\bgroup \fi } }{ \stex_if_do_html:TF{ \end{stex_annotate_env} }{ \ifsolutions \stex_style_apply: \stex_if_do_html:T{ \end{stex_annotate_env} } \else \egroup \fi } }{ \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip \noindent\emph{\problem@kw@solution\tl_if_empty:NF \l_stex_key_title_tl{ {~}\l_stex_key_title_tl \str_if_empty:NF \l_stex_key_answerclass_str { (Answer Class: \l_stex_key_answerclass_str) } } :~} }{ \par\rule[.3em]{\linewidth}{0.4pt}\newline }{} \stex_deactivate_macro:Nn \solution {sproblem~environments} % \end{macrocode} % \end{environment} % % \begin{macro}{\startsolutions,\stopsolutions} % \begin{macrocode} \cs_new_protected:Npn \startsolutions{ \global\solutionstrue } \cs_new_protected:Npn \stopsolutions{ \global\solutionsfalse } % \end{macrocode} % \end{macro} % % \begin{environment}{hint} % \begin{macrocode} \stex_keys_define:nnnn{ problemenv }{}{}{id,title,style} \cs_new_protected:Nn \_@@_hint_start:n { \stex_keys_set:nn{ problemenv }{#1} \str_if_empty:NT \l_stex_key_id_str { \int_gincr:N \g_problem_id_counter \str_set:Nx \l_stex_key_id_str { HINT_\int_use:N \g_problem_id_counter } } \stex_if_do_html:T{ \begin{stex_annotate_env}{ data-ftml-problemhint=\l_stex_key_id_str } } } \stex_new_stylable_env:nnnnnnn { hint }{ O{} }{ \stex_if_do_html:TF{ \_@@_hint_start:n{#1} }{ \bool_if:NTF \c_@@_hints_bool { \_@@_hint_start:n{#1} \stex_style_apply: }{ \setbox\l_tmpa_box\vbox\bgroup } } }{ \stex_if_do_html:TF{ \end{stex_annotate_env} }{ \bool_if:NTF \c_@@_hints_bool { \stex_style_apply: \stex_if_do_html:T{ \end{stex_annotate_env} } }{ \egroup } } }{ \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip \noindent\emph{\problem@kw@hint\tl_if_empty:NF \l_stex_key_title_tl{ {~}\l_stex_key_title_tl } :~} }{ \par\rule[.3em]{\linewidth}{0.4pt}\newline }{} \stex_deactivate_macro:Nn \hint {sproblem~environments} % \end{macrocode} % \end{environment} % % \begin{environment}{exnote} % \begin{macrocode} \cs_new_protected:Nn \_@@_exnote_start:n { \stex_keys_set:nn{ problemenv }{#1} \str_if_empty:NT \l_stex_key_id_str { \int_gincr:N \g_problem_id_counter \str_set:Nx \l_stex_key_id_str { EXNOTE_\int_use:N \g_problem_id_counter } } \stex_if_do_html:T{ \begin{stex_annotate_env}{ data-ftml-problemnote=\l_stex_key_id_str } } } \stex_new_stylable_env:nnnnnnn { exnote }{ O{} }{ \stex_if_do_html:TF{ \_@@_exnote_start:n{#1} }{ \bool_if:NTF \c_@@_notes_bool { \_@@_exnote_start:n{#1} \stex_style_apply: }{ \setbox\l_tmpa_box\vbox\bgroup } } }{ \stex_if_do_html:TF{ \end{stex_annotate_env} }{ \bool_if:NTF \c_@@_notes_bool { \stex_style_apply: \stex_if_do_html:T{ \end{stex_annotate_env} } }{ \egroup } } }{ \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip \noindent\emph{\problem@kw@note\tl_if_empty:NF \l_stex_key_title_tl{ {~}\l_stex_key_title_tl } :~} }{ \par\rule[.3em]{\linewidth}{0.4pt}\newline }{} \stex_deactivate_macro:Nn \exnote {sproblem~environments} % \end{macrocode} % \end{environment} %% \begin{environment}{gnote} % \begin{macrocode} \int_new:N \l_@@_anscls_int \cs_new_protected:Nn \_@@_gnote_start:n { \stex_keys_set:nn{ problemenv }{#1} \str_if_empty:NT \l_stex_key_id_str { \int_gincr:N \g_problem_id_counter \str_set:Nx \l_stex_key_id_str { GNOTE_\int_use:N \g_problem_id_counter } } \stex_if_do_html:TF{ \begin{stex_annotate_env}{ data-ftml-problemgnote=\l_stex_key_id_str } } \stex_style_apply: } \stex_new_stylable_env:nnnnnnn { gnote }{ O{} }{ \stex_if_do_html:TF{ \_@@_gnote_start:n{#1} }{ \bool_if:NTF \c_@@_gnotes_bool { \_@@_gnote_start:n{#1} }{ \setbox\l_tmpa_box\vbox\bgroup } } \stex_reactivate_macro:N \anscls }{ \stex_if_do_html:TF{ \end{stex_annotate_env} }{ \bool_if:NTF \c_@@_gnotes_bool { \stex_style_apply: \stex_if_do_html:T{ \end{stex_annotate_env} } }{ \egroup } } }{ \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip \noindent\emph{\problem@kw@grading\str_if_empty:NF \l_stex_key_title_tl{ {~}\l_stex_key_title_tl } :~} }{ \par\rule[.3em]{\linewidth}{0.4pt}\newline }{} \stex_deactivate_macro:Nn \gnote {sproblem~environments} \stex_keys_define:nnnn{ anscls }{ \str_clear:N \l_stex_key_pts_str \tl_clear:N \l_stex_key_feedback_tl }{ pts .str_set:N = \l_stex_key_pts_str, feedback .tl_set:N = \l_stex_key_feedback_tl, update .code:n = {} }{id} \newcommand \anscls [2][] { \stex_keys_set:nn{ anscls }{#1} \str_if_empty:NT \l_stex_key_id_str { \int_incr:N \l_@@_anscls_int \str_set:Nx \l_stex_key_id_str { AC\int_use:N \l_@@_anscls_int } } \stex_if_do_html:TF{ \begin{list}{}{ \setlength\topsep{0pt} \setlength\parsep{0pt} \setlength\rightmargin{0pt} }\item[] \exp_args:Ne \stex_annotate:nn{ data-ftml-answerclass={\l_stex_key_id_str} \str_if_empty:NF \l_stex_key_pts_str{ ,data-ftml-answerclass-pts={\l_stex_key_pts_str} } }{ #2~ \tl_if_empty:NF \l_stex_key_feedback_tl{ \stex_annotate:nn{ data-ftml-answerclass-feedback={} }{\l_stex_key_feedback_tl} } } \end{list} }{ \begin{list}{}{ \setlength\topsep{0pt} \setlength\parsep{0pt} \setlength\rightmargin{0pt} }\item[\l_stex_key_id_str] #2 \str_if_empty:NF \l_stex_key_pts_str {\par ~ \problem@kw@points :~\l_stex_key_pts_str } \tl_if_empty:NF \l_stex_key_feedback_tl {\par ~ \problem@kw@feedback :~\l_stex_key_feedback_tl } \end{list} } } \stex_deactivate_macro:Nn \anscls {gnote~environments} % \end{macrocode} % \end{environment} % % The margin pars are reader-visible, so we need to translate % % \begin{macrocode} \def\pts#1{ \bool_if:NT \c_@@_pts_bool { \stex_annotate:nn{data-ftml-problempoints={#1}}{\marginpar{#1~\problem@kw@pts}} }\hbox_unpack:N\c_empty_box } \def\min#1{ \bool_if:NT \c_@@_min_bool { \stex_annotate:nn{data-ftml-problemminutes={}}{\marginpar{#1~\problem@kw@minutes}} }\hbox_unpack:N\c_empty_box } % \end{macrocode} % % \begin{environment}{mcb} % % \begin{macrocode} \stex_new_stylable_env:nnnnnnn{mcb}{O{}}{ \stex_keys_set:nn{style}{#1} \cs_set:Nn \_@@_mccline:n{ \begin{list}{}{ \setlength\topsep{0pt} \setlength\parsep{0pt} \setlength\rightmargin{0pt} }\item[\problem_mcc_box_tl] ##1 \end{list} } \stex_if_do_html:T{ \tl_set:Nn\problem_mcc_box_tl{} \_@@_maybe_inline:n{ \exp_args:Nne \begin{stex_annotate_env}{ data-ftml-multiple-choice-block={} \clist_if_empty:NF \l_stex_key_style_clist {, data-ftml-styles={\l_stex_key_style_clist} } } } \clist_if_in:NnTF \l_stex_key_style_clist {inline} { \cs_set:Nn \_@@_mccline:n {##1} }{ \clist_if_in:NnT \l_stex_key_style_clist {dropdown} { \cs_set:Nn \_@@_mccline:n {##1} } } } \stex_deactivate_macro:Nn \mcb {sproblem~environments} \stex_deactivate_macro:Nn \scb {sproblem~environments} \stex_deactivate_macro:Nn \solution {sproblem~environments} \stex_deactivate_macro:Nn \hint {sproblem~environments} \stex_deactivate_macro:Nn \exnote {sproblem~environments} \stex_deactivate_macro:Nn \gnote {sproblem~environments} \stex_reactivate_macro:N \mcc \stex_if_do_html:F \stex_style_apply: }{ \stex_if_do_html:TF{ \_@@_maybe_inline:n{\end{stex_annotate_env}} }\stex_style_apply: }{\par}{}{} \stexstylemcb[inline]{ {\Large[}\cs_set:Nn \_@@_mccline:n{\problem_mcc_box_tl{~} #1} }{{\Large]}} \stexstylemcb[dropdown]{ {\Large[}\cs_set:Nn \_@@_mccline:n{\problem_mcc_box_tl{~} #1} }{{\Large]}} \stex_deactivate_macro:Nn \mcb {sproblem~environments} % \end{macrocode} % % 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 } } \stex_keys_define:nnnn{mcc}{ \tl_clear:N \l_stex_key_feedback_tl \bool_set_false:N \l_stex_key_T_bool \tl_clear:N \l_stex_key_Ttext_tl \tl_clear:N \l_stex_key_Ftext_tl }{ feedback .tl_set:N = \l_stex_key_feedback_tl , T .code:n = {\bool_set_true:N \l_stex_key_T_bool} , F .code:n = {\bool_set_false:N \l_stex_key_T_bool} , Ttext .tl_set:N = \l_stex_key_Ttext_tl , Ftext .tl_set:N = \l_stex_key_Ftext_tl , }{id} % \end{macrocode} % % \begin{macro}{\mcc} % \begin{macrocode} \cs_set:Nn \_@@_maybe_newline: { \\ } \stex_if_html_backend:TF{ \tl_set:Nn \problem_mcc_box_tl { \ltx@ifpackageloaded{amssymb}{$\square$}{ \hbox{\vrule\vbox{\hrule width 6 pt\vskip 6pt\hrule}\vrule} } } \newcommand\mcc[2][]{ \stex_keys_set:nn{mcc}{#1} \_@@_mccline:n{ \stex_if_do_html:T{ \stex_annotate:nn{data-ftml-problem-choice={ \bool_if:NTF \l_stex_key_T_bool {true}{false} }}{ #2~ \stex_annotate:nn{data-ftml-problem-choice-verdict={}}{ \bool_if:NTF \l_stex_key_T_bool { \tl_if_empty:NTF \l_stex_key_Ttext_tl \problem@kw@correct \l_stex_key_Ttext_tl }{ \tl_if_empty:NTF \l_stex_key_Ftext_tl \problem@kw@wrong \l_stex_key_Ftext_tl } } \tl_if_empty:NF \l_stex_key_feedback_tl { \stex_annotate:nn{data-ftml-problem-choice-feedback={}}{ \l_stex_key_feedback_tl } } } } } } }{ \tl_set:Nn \problem_mcc_box_default_tl { \ltx@ifpackageloaded{amssymb}{$\square$}{ \hbox{\vrule\vbox{\hrule width 6 pt\vskip 6pt\hrule}\vrule} } } \tl_set:Nn \problem_mcc_box_tl { \ifsolutions \bool_if:NTF \l_stex_key_T_bool { \makebox[0pt][l]{\problem_mcc_box_default_tl} \hspace{0.1em}$\cs_if_exist:NTF\checkmark{ \raisebox{.15ex}{\checkmark} } X$ }{\problem_mcc_box_default_tl} \else \problem_mcc_box_default_tl \fi } \newcommand\mcc[2][]{ \stex_keys_set:nn{mcc}{#1} \ifsolutions \tl_set:Nx \l_tmpa_tl{ \bool_if:NTF \l_stex_key_T_bool { \tl_if_empty:NF \l_stex_key_Ttext_tl {\exp_not:N \l_stex_key_Ttext_tl} }{ \tl_if_empty:NF \l_stex_key_Ftext_tl {\exp_not:N \l_stex_key_Ftext_tl} } \tl_if_empty:NF \l_stex_key_feedback_tl { \exp_not:n{\\\emph{\l_stex_key_feedback_tl}} } } \fi \_@@_mccline:n{ #2 \ifsolutions \tl_if_empty:NF \l_tmpa_tl { \footnote{\l_tmpa_tl} } \fi } } } \stex_deactivate_macro:Nn \mcc {mcb~environments} % \end{macrocode} % \end{macro} % \end{environment} % % \begin{environment}{scb} % % \begin{macrocode} \cs_new_protected:Nn \_@@_maybe_inline:n { \clist_if_in:NnTF \l_stex_key_style_clist {inline} { \let\_@@_oldpar:\stex_par: \cs_set:Nn\stex_par:{~} \cs_set:Nn\_@@_maybe_newline:{} #1 \let\stex_par:\_@@_oldpar: }{ \clist_if_in:NnTF \l_stex_key_style_clist {dropdown} { \let\_@@_oldpar:\stex_par: \cs_set:Nn\stex_par:{~} \cs_set:Nn\_@@_maybe_newline:{} #1 \let\stex_par:\_@@_oldpar: }{\par #1} } } \stex_new_stylable_env:nnnnnnn{scb}{O{}}{ \stex_keys_set:nn{style}{#1} \cs_set:Nn \_@@_sccline:n{ \begin{list}{}{ \setlength\topsep{0pt} \setlength\parsep{0pt} \setlength\rightmargin{0pt} }\item[\problem_scc_box_tl] ##1 \end{list} } \stex_if_do_html:T{ \_@@_maybe_inline:n{ \exp_args:Ne\stex_annotate_env{ data-ftml-single-choice-block={} \clist_if_empty:NF \l_stex_key_style_clist {, data-ftml-styles={\l_stex_key_style_clist} } } } \tl_set:Nn\problem_scc_box_tl{} \clist_if_in:NnTF \l_stex_key_style_clist {inline} { \cs_set:Nn \_@@_sccline:n {##1} }{ \clist_if_in:NnT \l_stex_key_style_clist {dropdown} { \cs_set:Nn \_@@_sccline:n {##1} } } } \stex_deactivate_macro:Nn \mcb {sproblem~environments} \stex_deactivate_macro:Nn \scb {sproblem~environments} \stex_deactivate_macro:Nn \solution {sproblem~environments} \stex_deactivate_macro:Nn \hint {sproblem~environments} \stex_deactivate_macro:Nn \exnote {sproblem~environments} \stex_deactivate_macro:Nn \gnote {sproblem~environments} \stex_reactivate_macro:N \scc \stex_if_do_html:F \stex_style_apply: }{ \stex_if_do_html:TF{ \_@@_maybe_inline:n { \endstex_annotate_env } }\stex_style_apply: }{\par}{}{} \stexstylescb[inline]{ {\Large[}\cs_set:Nn \_@@_sccline:n{\problem_scc_box_tl{~} #1} }{{\Large]}} \stexstylescb[dropdown]{ {\Large[}\cs_set:Nn \_@@_sccline:n{\problem_scc_box_tl{~} #1} }{{\Large]}} \stex_deactivate_macro:Nn \scb {sproblem~environments} % \end{macrocode} % % \begin{macro}{\scc} % \begin{macrocode} \stex_if_html_backend:TF{ \tl_set:Nn\problem_scc_box_tl{$\bigcirc$} \newcommand\scc[2][]{ \stex_keys_set:nn{mcc}{#1} \_@@_sccline:n{ \stex_if_do_html:T{ \stex_annotate:nn{data-ftml-problem-choice={ \bool_if:NTF \l_stex_key_T_bool {true}{false} }}{ #2~ \stex_annotate:nn{data-ftml-problem-choice-verdict={}}{ \bool_if:NTF \l_stex_key_T_bool { \tl_if_empty:NTF \l_stex_key_Ttext_tl \problem@kw@correct \l_stex_key_Ttext_tl }{ \tl_if_empty:NTF \l_stex_key_Ftext_tl \problem@kw@wrong \l_stex_key_Ftext_tl } } \tl_if_empty:NF \l_stex_key_feedback_tl { \stex_annotate:nn{data-ftml-problem-choice-feedback={}}{ \l_stex_key_feedback_tl } } } } } } }{ \tl_set:Nn\problem_scc_box_default_tl{$\bigcirc$} \tl_set:Nn\problem_scc_box_tl{ \ifsolutions \bool_if:NTF \l_stex_key_T_bool { \makebox[0pt][l]{\problem_scc_box_default_tl} \hspace{0.1em}$\cs_if_exist:NTF\checkmark{ \raisebox{.15ex}{\checkmark} } X$ }{\problem_scc_box_default_tl} \else \problem_scc_box_default_tl \fi } \newcommand\scc[2][]{ \stex_keys_set:nn{mcc}{#1} \ifsolutions \tl_set:Nx \l_tmpa_tl{ \bool_if:NTF \l_stex_key_T_bool { \tl_if_empty:NF \l_stex_key_Ttext_tl {\exp_not:N \l_stex_key_Ttext_tl} }{ \tl_if_empty:NF \l_stex_key_Ftext_tl {\exp_not:N \l_stex_key_Ftext_tl} } \tl_if_empty:NF \l_stex_key_feedback_tl { \exp_not:n{ \\\emph{\l_stex_key_feedback_tl} } } } \fi \_@@_sccline:n{ #2 \ifsolutions \tl_if_empty:NF \l_tmpa_tl { \footnote{\l_tmpa_tl} } \fi } } } \stex_deactivate_macro:Nn \scc {scb~environments} \newcommand\yesTnoF{ \begin{scb}[style=inline] \scc[T]{yes}~\scc[F]{no} \end{scb} } \newcommand\yesFnoT{ \begin{scb}[style=inline] \scc[F]{yes}~\scc[T]{no} \end{scb} } \newcommand\trueTfalseF{ \begin{scb}[style=inline] \scc[T]{true}~\scc[F]{false} \end{scb} } \newcommand\trueFfalseT{ \begin{scb}[style=inline] \scc[F]{true}~\scc[T]{false} \end{scb} } % \end{macrocode} % \end{macro} % \end{environment} % % \begin{macro}{\fillinsol} % \begin{macrocode} \stex_keys_define:nnnn{fillinsol}{ \tl_clear:N \l_@@_fillin_solution_tl \dim_zero:N \l_stex_key_testspace_dim }{ testspace .dim_set:N = \l_stex_key_testspace_dim, exact .code:n = {\_@@_parse_fillin_arg:nnnn{exact}#1 }, numrange .code:n = {\_@@_parse_fillin_arg:nnnn{numrange}#1 }, regex .code:n = {\_@@_parse_fillin_arg:nnnn{regex}#1 } }{} \tl_const:Nn \c_@@_true_tl{T} \tl_const:Nn \c_@@_false_tl{F} \msg_set:nnn{problem}{error/neither-true-nor-false}{ Fillinsol~verdict~#1~is~neither~T~nor~F! } \stex_if_html_backend:TF{ \cs_new:Nn \_@@_parse_fillin_arg:nnnn { \tl_set:Nn \l_tmpa_tl{#3} \tl_if_eq:NNF \l_tmpa_tl\c_@@_true_tl{ \tl_if_eq:NNF \l_tmpa_tl\c_@@_false_tl { \msg_error:nnn{problem}{error/neither-true-nor-false}{#3} } } \tl_put_right:Ne \l_@@_fillin_solution_tl { \stex_annotate:nn{ data-ftml-fillin-case={#1}, data-ftml-fillin-case-value={\tl_to_str:n{#2}}, data-ftml-fillin-case-verdict={ \tl_if_eq:NNTF\l_tmpa_tl\c_@@_true_tl{true}{false} }, }{\_stex_annotate_force_break:n{\exp_not:n{#4}}} } } }{ \cs_new:Nn \_@@_parse_fillin_arg:nnnn { \tl_put_right:Nn \l_@@_fillin_solution_tl { #1 & \tl_to_str:n{#2} & #3 & #4 \crcr } } } \newcommand\fillinsol[2][]{ \stex_if_do_html:F \quad \mode_if_math:TF{ \hbox{\_@@_fillinsol:nn{#1}{#2}} }{ \_@@_fillinsol:nn{#1}{#2} } \stex_if_do_html:F \quad } \stex_if_html_backend:TF{ \cs_new_protected:Nn \_@@_fillinsol:nn { \stex_keys_set:nn{fillinsol}{#1} \tl_if_empty:nF{#2}{ \_@@_parse_fillin_arg:nnnn{exact}{#2}{T}{} } \hbox_set:Nn \l_tmpa_box{\fbox{\huge{\texttt{\tl_to_str:n{#2}}}\hskip\l_stex_key_testspace_dim}} \exp_args:Ne \stex_annotate:nn{ data-ftml-fillinsol={}, data-ftml-fillinsol-width={\dim_to_decimal:n{1.5 \box_wd:N \l_tmpa_box }} }{ \_stex_annotate_force_break:n{ \l_@@_fillin_solution_tl #2 } } } }{ \cs_new_protected:Nn \_@@_fillinsol:nn { \stex_keys_set:nn{fillinsol}{#1} \ifsolutions \cs_if_exist:NT\textcolor{\textcolor{red}}{\fbox{\texttt{\tl_to_str:n{#2}}}} \tl_if_empty:NF \l_@@_fillin_solution_tl { \footnote{ \halign{ ~##~\hfil & ~##~\hfil & ~##~\hfil & ~##~\hfil \cr \textbf{type}&\textbf{case}&\textbf{verdict}&\textbf{feedback}\cr \tl_if_empty:nF{#2}{ exact & #2 & T & \cr } \l_@@_fillin_solution_tl } } } \else \fbox{\dim_compare:nNnTF\l_stex_key_testspace_dim={0pt}{ \phantom{\huge{\tl_to_str:n{#2}}} }{ \hspace{\l_stex_key_testspace_dim}\vphantom{\huge{A \tl_to_str:n{#2}}} }} \fi } } \stex_deactivate_macro:Nn \fillinsol {sproblem~environments} % \end{macrocode} % \end{macro} % % % \begin{macro}{\testemptypage} % \begin{macrocode} \newcommand\testemptypage[1][]{% \bool_if:NT \c_@@_test_bool {\ \vfill\begin{center}\hwexam@kw@testemptypage\end{center}\eject} } % \end{macrocode} % \end{macro} % % \begin{macro}{\testspace} % \begin{macrocode} \newcommand\testspace[1]{\bool_if:NT \c_@@_test_bool {\vspace*{#1}}} \newcommand\testsmallspace{\testspace{1cm}} \newcommand\testmedspace{\testspace{2cm}} \newcommand\testbigspace{\testspace{3cm}} % \end{macrocode} % \end{macro} % % \begin{macro}{\testnewpage} % \begin{macrocode} \newcommand\testnewpage{\bool_if:NT \c_@@_test_bool {\newpage}} % \end{macrocode} % \end{macro} % % \begin{macro}{\testnewpage} % \begin{macrocode} \newcommand{\testnewpageInProblem}% {\ifintest\vfill\begin{center}\emph{continued on next page}\end{center}\testnewpage\fi}% % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % ^^A \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