% \iffalse meta-comment
% An Infrastructure for marking up Assignments
% 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{hwexam} Package}{hwexam}
\docmodule{chapter}
%</driver>
% \fi
%
% \begin{stexmanual}
%    \begin{sfragment}{HWExam Manual}
%      \input{\stexdocpath/packages/stex-hwexam}
%    \end{sfragment}
% \end{stexmanual}
%
% \begin{documentation}
%    \begin{sfragment}{HWExam Documentation}
%       TODO
%    \end{sfragment}
% \end{documentation}
%
%\begin{implementation}
% 
% \section{Implementation: The hwexam Package} 
%
% \subsection{Package Options}
%
% The first step is to declare (a few) package options that handle whether certain
% information is printed or not. Some come with their own conditionals that are set by the
% options, the rest is just passed on to the |problems| package.
%
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage{hwexam}{2025/11/11}{4.0.0}{homework assignments and exams}
\RequirePackage{l3keys2e}

\keys_define:nn {hwexam / pkg}{
	multiple  .default:n 		= { false },
	multiple	.bool_set:N 	= \c_hwexam_multiple_bool,
	qrcode		.default:n 	  = { false },
	qrcode		.bool_set:N 	= \c_hwexam_qrcode_bool,
	unknown   .code:n 			= {
		\PassOptionsToPackage{\CurrentOption}{problem}
	}
}
\ProcessKeysOptions{ hwexam /pkg }
\RequirePackage{problem}
%    \end{macrocode}
%
%
% \begin{macro}{\hwexam_kw_*}
%   For multilinguality, we define internal macros for keywords that can be specialized in
%   |*.ldf| files.
%    \begin{macrocode}
\AddToHook{begindocument}{
	\ExplSyntaxOn\makeatletter
	\input{hwexam-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{hwexam-ngerman.ldf}
			}
			\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{finnish}}{
				\input{hwexam-finnish.ldf}
			}
			\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{french}}{
				\input{hwexam-french.ldf}
			}
			\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{russian}}{
				\input{hwexam-russian.ldf}
			}
	}{}
	\makeatother\ExplSyntaxOff
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{QR Codes}
%    \begin{macrocode}
\group_begin:
  \escapechar=-1
  \xdef\_@@_qr_backslash{\string\\}
\group_end:

\bool_if:NT \c_hwexam_qrcode_bool {
	\RequirePackage{qrcode}
	\RequirePackage{marginnote}
	\str_new:N \g_@@_qr_json_str
	\bool_new:N \g_@@_qr_in_problems_json_bool
	\bool_set_false:N \g_@@_qr_in_problems_json_bool
	\bool_new:N \g_@@_qr_in_subproblems_json_bool
	\bool_set_false:N \g_@@_qr_in_subproblems_json_bool
	\bool_new:N \g_@@_qr_in_anscls_json_bool
	\bool_set_false:N \g_@@_qr_in_anscls_json_bool
	\bool_if:NTF \c__problems_gnotes_bool {
  	\gdef \qrjson { \str_gput_right:Nx \g_@@_qr_json_str}
	}{
		\gdef \qrjson #1 {}
	}
	\qrjson{[}
	\AtEndDocument{\qrjson{]}}
	\def\_@@_qr_escape_char:n #1 {
		#1\exp_args:Nno\use:nn{\if_charcode:w#1}\_@@_qr_backslash#1\fi
	}

	\gdef\_@@_qr_escape:n #1{\exp_args:Ne\str_map_function:nN{\tl_to_str:n{#1}}\_@@_qr_escape_char:n}
	\gdef \_@@_qr_escape:o #1{\exp_args:No\_@@_qr_escape:n#1}

	\def\qrschema{TO:DO:\examnumber}

	\bool_if:NTF \c__problems_test_bool {
		\def\doproblemqr{
			\ifstexhtml\else{
				\reversemarginpar\marginnote{\qrcode[height=1.5cm]{\qrschema}}
				\normalmarginpar
			}\fi
		}
		\def\insertexamnumber{
			\ifstexhtml\else
				\tl_if_exist:NTF \examnumber {
					{\Large\bfseries ID:~\examnumber}
				}{
					{\color{red}\Large\bfseries!!!~ WARNING:~NO~{\string\examnumber}~SET~!!!}\gdef\examnumber{0}
				}
				\global\def\insertexamnumber{}
			\fi
		}
	}{
		\def\doproblemqr{}
		\def\insertexamnumber{}
	}

	\stexstyleproblem[noqr]{
		\par\noindent\problemheader \xdef\qrid{\thesproblem}
		\bool_if:NT \c__problems_pts_bool {
			\tl_if_eq:NnF \l__problems_pts_tl {0}{
				\marginpar{\l__problems_pts_tl{}~\problem@kw@points\smallskip}
			}
		}
		\bool_if:NT \c__problems_min_bool {
			\tl_if_eq:NnF \l__problems_min_tl {0} {
				\marginpar{\l__problems_min_tl{}~\problem@kw@minutes\smallskip}
			}
		}
		\par
		\stex_ignore_spaces_and_pars:
	}{
		\par\bigskip
	}

	\stexstyleproblem{
		\par\noindent\problemheader \xdef\qrid{\thesproblem}
		\doproblemqr
		\bool_if:NT \c__problems_pts_bool {
			\tl_if_eq:NnF \l__problems_pts_tl {0}{
				\marginpar{\l__problems_pts_tl{}~\problem@kw@points\smallskip}
			}
		}
		\bool_if:NT \c__problems_min_bool {
			\tl_if_eq:NnF \l__problems_min_tl {0} {
				\marginpar{\l__problems_min_tl{}~\problem@kw@minutes\smallskip}
			}
		}

		\bool_if:NTF \g_@@_qr_in_problems_json_bool {
			\qrjson{,}
		}{
			\bool_gset_true:N \g_@@_qr_in_problems_json_bool
		}

		\qrjson {
			\c_left_brace_str
				"id":"\_@@_qr_escape:o\l_stex_key_id_str","title":"\_@@_qr_escape:o\l_stex_key_title_tl",
				"number":"\thesproblem"
		}

		\tl_if_eq:NnF \l__problems_pts_tl {0}{
			\qrjson {
				,"pts":\l__problems_pts_tl
			}
		}
		\par
		\stex_ignore_spaces_and_pars:
	}{
		\bool_if:NT \g_@@_qr_in_subproblems_json_bool {
			\qrjson {]}
		}
		\bool_gset_false:N \g_@@_qr_in_subproblems_json_bool
		\qrjson {\c_right_brace_str}
		\par\bigskip
	}

	\stexstylesubproblem[noqr]{
		\begin{list}{}{
			\setlength\topsep{0pt}
			\setlength\parsep{0pt}
			\setlength\rightmargin{0pt}
		}\item[\int_use:N \g__problems_subproblem_int .]
		\xdef\qrid{\thesproblem.\int_use:N \g__problems_subproblem_int}
		\bool_if:NT \c__problems_pts_bool {
			\bool_if:NF \l__problems_has_pts_bool {
				\marginpar{\smallskip\l_stex_key_pts_tl{}~\problem@kw@points}
			}
		}
		\bool_if:NT \c__problems_min_bool {
			\bool_if:NF \l__problems_has_min_bool{
				\marginpar{\smallskip\l_stex_key_min_tl{}~\problem@kw@minutes}
			}
		}
	}{\end{list}}

	\stexstylesubproblem{
		\begin{list}{}{
			\setlength\topsep{0pt}
			\setlength\parsep{0pt}
			\setlength\rightmargin{0pt}
		}\item[\int_use:N \g__problems_subproblem_int .]
		\xdef\qrid{\thesproblem.\int_use:N \g__problems_subproblem_int}
		\doproblemqr
		\bool_if:NT \c__problems_pts_bool {
			\bool_if:NF \l__problems_has_pts_bool {
				\marginpar{\smallskip\l_stex_key_pts_tl{}~\problem@kw@points}
			}
		}
		\bool_if:NT \c__problems_min_bool {
			\bool_if:NF \l__problems_has_min_bool{
				\marginpar{\smallskip\l_stex_key_min_tl{}~\problem@kw@minutes}
			}
		}
		\bool_if:NTF \g_@@_qr_in_subproblems_json_bool {
			\qrjson {,}
		}{
			\qrjson {
				,"subproblems":[
			}
			\bool_gset_true:N \g_@@_qr_in_subproblems_json_bool
		}
		\qrjson {
			\c_left_brace_str
				"id":"\_@@_qr_escape:o\l_stex_key_id_str","title":"\_@@_qr_escape:o\l_stex_key_title_tl",
				"number":"\thesproblem.\int_use:N \g__problems_subproblem_int"
		}
		\bool_if:NF \l__problems_has_pts_bool {
			\qrjson {
				,"pts":\l_stex_key_pts_tl
			}
		}
	}{
		\qrjson {\c_right_brace_str}
		\end{list}
	}

	\stexstylegnote{
		\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
		} :~}
		\qrjson {
			,"gnote": \c_left_brace_str
			"id":"\_@@_qr_escape:o\l_stex_key_id_str","title":"\_@@_qr_escape:o\l_stex_key_title_tl",
			"anscls":[
		}
	}{
		\qrjson {
			]\c_right_brace_str
		}
		\par\rule[.3em]{\linewidth}{0.4pt}\newline
	}

	\renewcommand \anscls [2][] {
		\stex_keys_set:nn{ anscls }{#1}
		\str_if_empty:NT \l_stex_key_id_str {
			\int_incr:N \l__problems_anscls_int
			\str_set:Nx \l_stex_key_id_str {
				AC\int_use:N \l__problems_anscls_int
			}
		}
		\bool_if:NTF \g_@@_qr_in_anscls_json_bool {
			\qrjson{,}
		}{
			\bool_set_true:N \g_@@_qr_in_anscls_json_bool
		}
		\qrjson{
			\c_left_brace_str
				"id":"\_@@_qr_escape:o\l_stex_key_id_str","description":"\_@@_qr_escape:n{#2}",
				"feedback":"\_@@_qr_escape:o\l_stex_key_feedback_tl",
				"pts":"\l_stex_key_pts_str"
			\c_right_brace_str
		}
		\begin{list}{}{
			\setlength\topsep{0pt}
			\setlength\parsep{0pt}
			\setlength\rightmargin{0pt}
		}\item[\l_stex_key_id_str] 
			\stex_if_do_html:TF{
				\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_invisible:nn{
							data-ftml-answerclass-feedback={true}
						}{\l_stex_key_feedback_tl}
					}
				}
			}{#2}
			\str_if_empty:NF \l_stex_key_pts_str {\par
				~ \problem@kw@points :~\l_stex_key_pts_str
			}
			\str_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}

	\AtEndDocument{
		\message{^^J^^J\g_@@_qr_json_str^^J^^J}
		\bool_if:NT \c__problems_gnotes_bool {
			\iow_new:N \c_@@_qr_json_iow
			\iow_open:Nn \c_@@_qr_json_iow {\jobname-vollkorn.json}
			\iow_now:Nx \c_@@_qr_json_iow {\g_@@_qr_json_str}
			\iow_close:N \c_@@_qr_json_iow
		}
	}

	\renewcommand\testemptypage[1][]{%
		\bool_if:NT \c__problems_test_bool {\ 
		\xdef\qrid{P\thepage}
		\doproblemqr
		\vfill\begin{center}\hwexam@kw@testemptypage\end{center}\eject
		}
	}
}
%    \end{macrocode}
%
% \subsection{Assignments}
%
% Then we set up a counter for problems and make the problem counter inherited from
% |problem.sty| depend on it. Furthermore, we specialize the |\prob@label| macro to take
% the assignment counter into account.
%
% \begin{environment}{assignment}
%    \begin{macrocode}
\stex_keys_define:nnnn{ assignment }{
  \tl_clear:N \l_stex_key_number_tl 
	\tl_clear:N \l_stex_key_given_tl 
	\tl_clear:N \l_stex_key_due_tl
}{
  number  .tl_set:N     = \l_stex_key_number_tl,
  given   .tl_set:N     = \l_stex_key_given_tl,
  due     .tl_set:N     = \l_stex_key_due_tl,
	unknown .code:n = {}
}{id,title,style}

\newcounter{assignment}
\stex_new_stylable_env:nnnnnnn {assignment}{O{}}{
  \cs_if_exist:NTF \l_hwexam_includeassignment_keys_tl {
    \tl_put_left:Nn \l_hwexam_includeassignment_keys_tl {#1,}
    \exp_args:Nno \stex_keys_set:nn{assignment}{
      \l_hwexam_includeassignment_keys_tl
    }
  }{
    \stex_keys_set:nn{assignment}{#1}
  }
	\tl_if_empty:NF \l_stex_key_number_tl {
		\global\setcounter{assignment}{\int_eval:n{\l_stex_key_number_tl-1}}
	}
	\global\refstepcounter{assignment}
	\setcounter{sproblem}{0}
	\def\thesproblem{\theassignment.\arabic{sproblem}}
	\stex_if_do_html:T{
		\tl_if_empty:NF \l_stex_key_title_tl {
			\stexdoctitle \l_stex_key_title_tl
		}
	}
	\stex_style_apply:
	\_stex_do_id:
}{
	\stex_style_apply:
}{
	\par\begin{center}
	\textbf{\Large\assignmentautorefname~\theassignment
		\tl_if_empty:NF \l_stex_key_title_tl {
			{~}--~\l_stex_key_title_tl
		}
	}\par\smallskip
	\textbf{
		\tl_if_empty:NF \l_stex_key_given_tl {
			\hwexam@kw@given :~\l_stex_key_given_tl\quad
		}
		\tl_if_empty:NF \l_stex_key_due_tl {
			\hwexam@kw@due :~\l_stex_key_due_tl\quad
		}
	}
	\end{center}
	\par\bigskip
}{
	\par\pagebreak
}{}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\includeassignment}
%    \begin{macrocode}
\NewDocumentCommand\includeassignment{O{} m}{
	\group_begin:
	\tl_set:Nn \l_hwexam_includeassignment_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}
%
% Restoring information about problems:
%
%    \begin{macrocode}
\prop_new:N \c_@@_problems_prop
\tl_set:Nn \c_@@_total_mins_tl {0pt}
\tl_set:Nn \c_@@_total_pts_tl {0pt}
\int_new:N \c_@@_total_problems_int
\cs_set_protected:Npn \problem@restore #1 #2 #3 {
	\int_gincr:N \c_@@_total_problems_int
	\prop_gput:Nnn \c_@@_problems_prop {#1}{{#2}{#3}}
	\tl_gset:Ne \c_@@_total_pts_tl { \dim_eval:n { \c_@@_total_pts_tl + #2pt }}
	\tl_gset:Ne \c_@@_total_mins_tl { \dim_eval:n { \c_@@_total_mins_tl + #2pt }}
}
%    \end{macrocode}
%
% \begin{macro}{\correction@table}
%   This macro generates the correction table
%    \begin{macrocode}
\newcommand\correction@table{
	\int_compare:nNnT \c_@@_total_problems_int = 0 {
		\int_incr:N \c_@@_total_problems_int
		\prop_put:Nnn \c_@@_problems_prop {~}{{~}{~}}
	}
	\tl_clear:N \l_tmpa_tl
	\tl_clear:N \l_tmpb_tl
	\tl_clear:N \l_tmpc_tl
	\prop_map_inline:Nn \c_@@_problems_prop {
		\tl_put_right:Nn \l_tmpa_tl { ##1 & }
		\tl_put_right:Nx \l_tmpb_tl { \use_i:nn ##2 & }
		\tl_put_right:Nn \l_tmpc_tl { & }
	}
	\resizebox{\textwidth}{!}{%
\exp_args:Nne \begin{tabular}{|l|*{\int_use:N \c_@@_total_problems_int}{c|}c||l|}\hline
&\exp_args:Ne \multicolumn{\int_eval:n{ \c_@@_total_problems_int + 1}}{c||}
{\footnotesize\hwexam@kw@forgrading} &\\\hline
\hwexam@kw@probs & \l_tmpa_tl \hwexam@kw@sum & \hwexam@kw@grade\\\hline
\hwexam@kw@pts & \l_tmpb_tl \dim_to_decimal:n\c_@@_total_pts_tl & \\\hline
\hwexam@kw@reached & \l_tmpc_tl & \\[.7cm]\hline
\end{tabular}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\testheading}
%    \begin{macrocode}
\def\hwexamheader{\input{hwexam-default.header}}

\def\hwexamminutes{
	\tl_if_empty:NTF \hwexam@duration {
		{\hwexam@min}~\hwexam@minutes@kw
	}{
		\hwexam@duration
	}
}

\stex_keys_define:nnnn{ hwexam / testheading }{
	\tl_clear:N \hwexam@min
	\tl_clear:N \hwexam@duration
	\tl_clear:N \hwexam@reqpts
	\tl_clear:N \hwexam@tools
}{
	min 		.tl_set:N 	= \hwexam@min,
	duration	.tl_set:N 	= \hwexam@duration,
	reqpts		.tl_set:N 	= \hwexam@reqpts,
	tools		.tl_set:N 	= \hwexam@tools 
}{}

\newenvironment{testheading}[1][]{
	\stex_keys_set:nn { hwexam / testheading}{#1}

	\tl_set:Nx \hwexam@totalpts {\dim_to_decimal:n \c_@@_total_pts_tl}
	\tl_set:Nx \hwexam@totalmin {\dim_to_decimal:n \c_@@_total_mins_tl}
	\tl_set:Nx \hwexam@checktime {\dim_to_decimal:n { \hwexam@min pt - \hwexam@totalmin pt }}

	\newif\if@bonuspoints
	\tl_if_empty:NTF \hwexam@reqpts {
		\@bonuspointsfalse
	}{
		\tl_set:Nx \hwexam@bonuspts {
			\dim_to_decimal:n{\hwexam@totalpts pt - \hwexam@reqpts pt}
		}
		\@bonuspointstrue
	}

	\makeatletter\hwexamheader\makeatother
}{
	\newpage
}
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{examdata,quizdata,homeworkdata}
% 
%    \begin{macrocode}
\bool_new:N \g_@@_allow_data_bool
\bool_gset_true:N \g_@@_allow_data_bool
\AtBeginDocument{
	\bool_gset_false:N \g_@@_allow_data_bool
}

\msg_set:nnn{stex}{hwexam/doubledata}{
  Exam/Homework/Quiz~Data~already~set
}

\msg_set:nnn{stex}{hwexam/nodate}{
  Exam/Homework/Quiz~Data~missing~date~value
}

\msg_set:nnn{stex}{hwexam/nocourse}{
  Exam/Homework/Quiz~Data~missing~course~value
}

\stex_keys_define:nnnn{ hwexam / commondata }{
	% https://docs.rs/dateparser/latest/dateparser/#accepted-date-formats
	\str_clear:N \l_@@_key_exam_date_str
	\str_clear:N \l_@@_key_exam_course_id_str
	\str_clear:N \l_@@_key_exam_term_str
	\int_set:Nn \l_@@_key_exam_num_int {1}
}{
	date     .str_set:N = \l_@@_key_exam_date_str,
	course   .str_set:N = \l_@@_key_exam_course_id_str,
	term     .str_set:N = \l_@@_key_exam_term_str,
	num      .int_set:N = \l_@@_key_exam_num_int
}{}

\stex_keys_define:nnnn{ hwexam / examdata }{
	\bool_set_false:N \l_@@_key_exam_retake_bool
}{
	retake   .bool_set:N = \l_@@_key_exam_retake_bool
}{hwexam/commondata}

\cs_set_protected:Nn \_@@_do_metadata:nnnn {
	\bool_if:NF \g_@@_allow_data_bool {
		\msg_fatal:nn{stex}{hwexam/doubledata}
	}
	\bool_gset_false:N \g_@@_allow_data_bool
	\stex_keys_set:nn { hwexam / #1}{#2}
	\str_set:Nn \g_stex_document_kind_str{#4}
	\str_if_empty:NT\l_@@_key_exam_date_str{
		\msg_fatal:nn{stex}{hwexam/nodate}
	}
	\str_if_empty:NT\l_@@_key_exam_course_id_str{
		\msg_fatal:nn{stex}{hwexam/nocourse}
	}
	\cs_if_exist:NT \date {
		\exp_args:No \date \l_@@_key_exam_date_str
	}

	\tl_set:Ne \g_stex_document_kind_parameters_tl{
		,data-ftml-document-kind-date={\l_@@_key_exam_date_str}
		,data-ftml-document-kind-num=\int_use:N \l_@@_key_exam_num_int 
		,data-ftml-document-kind-course=\l_@@_key_exam_course_id_str
		\str_if_empty:NF \l_@@_key_exam_term_str{
			,data-ftml-document-kind-term=\l_@@_key_exam_term_str
		}
		#3
	}
}

\newcommand\examdata[1]{
	\_@@_do_metadata:nnnn{examdata}{#1}{
		,data-ftml-document-kind-retake=\bool_if:NTF \l_@@_key_exam_retake_bool{true}{false}
	}{exam}
}

\newcommand\homeworkdata[1]{
	\_@@_do_metadata:nnnn{commondata}{#1}{}{homework}
}

\newcommand\quizdata[1]{
	\_@@_do_metadata:nnnn{commondata}{#1}{}{quiz}
}

%    \end{macrocode}
% 
% \end{macro}
%
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% 
% \subsection{Leftovers}
%
% at some point, we may want to reactivate the logos font, then we use
% \begin{verbatim}
% here we define the logos that characterize the assignment
% \font\bierfont=../assignments/bierglas
% \font\denkerfont=../assignments/denker
% \font\uhrfont=../assignments/uhr
% \font\warnschildfont=../assignments/achtung
%
% \newcommand\bierglas{{\bierfont\char65}}
% \newcommand\denker{{\denkerfont\char65}}
% \newcommand\uhr{{\uhrfont\char65}}
% \newcommand\warnschild{{\warnschildfont\char 65}}
% \newcommand\hardA{\warnschild}
% \newcommand\longA{\uhr}
% \newcommand\thinkA{\denker}
% \newcommand\discussA{\bierglas}
% \end{verbatim}
% \end{implementation}
\endinput
% \iffalse

%%% Local Variables: 
%%% mode: doctex
%%% TeX-master: t
%%% End: 
% \fi
%  LocalWords:  texttt scsys sc latexml fileversion filedate maketitle setcounter newpage
%  LocalWords:  tocdepth tableofcontents pts showmeta showmeta showignores omdoc extrefs
%  LocalWords:  testspace testnewpage testemptypage testheading testheading reqpts reqpts
%  LocalWords:  exfig makeatletter makeatother vspace hrule vspace vspace noindent textsf
%  LocalWords:  includeassignment includeassignment HorIacJuc cscpnrr11 importmodule baz
%  LocalWords:  includemhassignment includemhassignment importmhmodule foobar ldots sref
%  LocalWords:  mhcurrentrepos mh-variants mh-variant compactenum printbibliography Cwd
%  LocalWords:  langle rangle langle rangle ltxml.cls ltxml.sty respetively metakeys qw
%  LocalWords:  cwd stex graphicx amssymb amstext amsmath newif iftest testfalse testtrue
%  LocalWords:  ifsolutions solutionsfalse ifmultiple multiplefalse multipletrue keyval
%  LocalWords:  ltxml assig srefaddidkey addmetakey ifx assignment@titleblock stepcounter
%  LocalWords:  document@hwexamtype importmodules metasetkeys inclassig@title inclassig
%  LocalWords:  inclassig@title inclassig@type inclassig@type inclassig@number xspace kv
%  LocalWords:  inclassig@number inclassig@due inclassig@due inclassig@given ignorespaces
%  LocalWords:  inclassig@given newenvironment currentsectionlevel OptionalKeyVals kvi
%  LocalWords:  omgroup vals hwexamtype ednote textbackslash newcommand inputassignment
%  LocalWords:  unlist quizheading tas hspace hfill textbf newcount vfill addtocounter
%  LocalWords:  theassignment@totalmin theassignment@totalpts assignment@probs xdef hline
%  LocalWords:  assignment@totalpts assignment@totalmin correction@probs correction@probs
%  LocalWords:  newcounter theassignment@probs footnotesize mh@currentrepos endinput
%  LocalWords:  inclassig@mhrepos inclassig@mhrepos doctex inputmhassignment
%  LocalWords:  GPL structuresharing STR iffalse cls NeedsTeXFormat hwexam hwexam.dtx sc 
