diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/exsheets |
Initial commit
Diffstat (limited to 'macros/latex/contrib/exsheets')
-rw-r--r-- | macros/latex/contrib/exsheets/README | 38 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets-listings.sty | 147 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets.sty | 3238 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets_configurations.cfg | 32 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets_en.pdf | bin | 0 -> 665754 bytes | |||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets_en.tex | 2650 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets_headings.cfg | 361 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/exsheets_headings.def | 474 | ||||
-rw-r--r-- | macros/latex/contrib/exsheets/grading-table.pdf | bin | 0 -> 26255 bytes | |||
-rw-r--r-- | macros/latex/contrib/exsheets/grading-table.tex | 48 |
10 files changed, 6988 insertions, 0 deletions
diff --git a/macros/latex/contrib/exsheets/README b/macros/latex/contrib/exsheets/README new file mode 100644 index 0000000000..d6ca6030ca --- /dev/null +++ b/macros/latex/contrib/exsheets/README @@ -0,0 +1,38 @@ +-------------------------------------------------------------------------- +EXSHEETS 2017/02/08 v0.21i +bundled packages: +the EXSHEETS package + Yet another package for the creation of exercise sheets +the EXSHEETS-LISTINGS package + Using listings in exsheets + +-------------------------------------------------------------------------- +Clemens Niederberger +Web: https://bitbucket.org/cgnieder/exsheets/ +E-Mail: contact@mychemistry.eu +-------------------------------------------------------------------------- +Copyright 2011-2017 Clemens Niederberger + +This work may be distributed and/or modified under the +conditions of the LaTeX Project Public License, either version 1.3 +of this license or (at your option) any later version. +The latest version of this license is in + http://www.latex-project.org/lppl.txt +and version 1.3 or later is part of all distributions of LaTeX +version 2005/12/01 or later. + +This work has the LPPL maintenance status `maintained'. + +The Current Maintainer of this work is Clemens Niederberger. +-------------------------------------------------------------------------- +The exsheets bundle consists of the files + - exsheets.sty, exsheets-listings.sty, + exsheets_headings.def, exsheets_headings.cfg, + exsheets_configurations.cfg, + exsheets_en.tex, exsheets_en.pdf + + - README +-------------------------------------------------------------------------- +If you have any ideas, questions, suggestions or bugs to report, please +feel free to contact me. +-------------------------------------------------------------------------- diff --git a/macros/latex/contrib/exsheets/exsheets-listings.sty b/macros/latex/contrib/exsheets/exsheets-listings.sty new file mode 100644 index 0000000000..8e77c4aff4 --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets-listings.sty @@ -0,0 +1,147 @@ +% ---------------------------------------------------------------------------- +% the EXSHEETS-LISTINGS package +% +% Using listings with exsheets +% +% ---------------------------------------------------------------------------- +% Clemens Niederberger +% Web: https://bitbucket.org/cgnieder/exsheets/ +% E-Mail: contact@mychemistry.eu +% ---------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% ---------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% ---------------------------------------------------------------------------- +\RequirePackage{exsheets,listings} +% we need this loaded before expl3 syntax is activated: +\lst@RequireAspects{writefile} +\ExplSyntaxOn +\ProvidesExplPackage{exsheets-listings} + {\c_exsheets_date_tl} + {\c_exsheets_version_tl} + {listings~ in~ exsheets} + +% ---------------------------------------------------------------------------- +% variables: +\int_new:N \g__exsheets_listings_question_int +\int_new:N \g__exsheets_listings_solution_int + +\tl_new:N \l__exsheets_listings_question_pre_tl +\tl_new:N \l__exsheets_listings_question_post_tl +\tl_new:N \l__exsheets_listings_question_options_tl +\tl_new:N \l__exsheets_listings_question_code_tl +\tl_new:N \l__exsheets_listings_solution_pre_tl +\tl_new:N \l__exsheets_listings_solution_post_tl +\tl_new:N \l__exsheets_listings_solution_options_tl +\tl_new:N \l__exsheets_listings_solution_code_tl +\tl_new:N \l__exsheets_listings_question_points_tl + +% ---------------------------------------------------------------------------- +% listings style for questions and solutions: +\keys_define:nn {exsheets} + { + question / listings .tl_set:N = \l__exsheets_listings_question_code_tl , + solution / listings .tl_set:N = \l__exsheets_listings_solution_code_tl + } + +% ---------------------------------------------------------------------------- +% expansion help: +\cs_new:Npn \__exsheets_question_expandopt:Nnnnn #1#2#3#4#5 + { #1{#2}[#3]{#4}#5 } +\cs_generate_variant:Nn \__exsheets_question_expandopt:Nnnnn { NnVox } + +\cs_new:Npn \__exsheets_question_expand_opt_and_body:Nnnn #1#2#3#4 + { #1{#2}[#3]#4 } +\cs_generate_variant:Nn \__exsheets_question_expand_opt_and_body:Nnnn { NnVx } + +% ---------------------------------------------------------------------------- +% lstquestion environment: +\keys_define:nn { exsheets / listings / question } + { + pre .tl_set:N = \l__exsheets_listings_question_pre_tl , + post .tl_set:N = \l__exsheets_listings_question_post_tl , + options .tl_set:N = \l__exsheets_listings_question_options_tl , + points .tl_set:N = \l__exsheets_listings_question_points_tl , + listings .tl_set:N = \l__exsheets_listings_question_code_tl , + } + +\keys_define:nn { exsheets / listings / solution } + { + pre .tl_set:N = \l__exsheets_listings_solution_pre_tl , + post .tl_set:N = \l__exsheets_listings_solution_post_tl , + options .tl_set:N = \l__exsheets_listings_solution_options_tl , + listings .tl_set:N = \l__exsheets_listings_solution_code_tl , + } + +\cs_new:Npn \exsheets_listings_new_lstenvironment:nnnnnnn #1#2#3#4#5#6#7 + { + \lstnewenvironment{#2}[1][] + { + \keys_set:nn {exsheets/listings/question} {#1,#4,##1} + \int_gincr:N \g__exsheets_listings_question_int + \lst@BeginWriteFile + { \c_sys_jobname_str - ex \int_use:N \g__exsheets_listings_question_int . lst } + } + { + \lst@EndWriteFile + \__exsheets_question_expandopt:NnVox + \begin {#3} + \l__exsheets_listings_question_options_tl + { \l__exsheets_listings_question_points_tl } + { + \exp_not:V \l__exsheets_listings_question_pre_tl + \exp_not:N \lstinputlisting + [ \exp_not:V \l__exsheets_listings_question_code_tl ] + { \c_sys_jobname_str - ex \int_use:N \g__exsheets_listings_question_int . lst } + \exp_not:V \l__exsheets_listings_question_post_tl + } + \end {#3} + } + \lstnewenvironment{#5}[1][] + { + \keys_set:nn { exsheets / listings / solution } { #1,#7,##1 } + \int_gincr:N \g__exsheets_listings_solution_int + \lst@BeginWriteFile + { \c_sys_jobname_str - sol \int_use:N \g__exsheets_listings_solution_int . lst } + } + { + \lst@EndWriteFile + \__exsheets_question_expand_opt_and_body:NnVx + \begin {#6} + \l__exsheets_listings_solution_options_tl + { + \exp_not:V \l__exsheets_listings_solution_pre_tl + \exp_not:N \lstinputlisting + [ \exp_not:V \l__exsheets_listings_solution_code_tl ] + { \c_sys_jobname_str - sol \int_use:N \g__exsheets_listings_solution_int . lst } + \exp_not:V \l__exsheets_listings_solution_post_tl + } + \end {#6} + } + } + +\NewDocumentCommand \NewLstQuSolPair { O{}mmO{}mmO{} } + { \exsheets_listings_new_lstenvironment:nnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7} } + +\NewLstQuSolPair{lstquestion}{question}{lstsolution}{solution} + +\tex_endinput:D + +HISTORY +2013/09/18 - first draft, see http://tex.stackexchange.com/a/133969/5049 +2013/10/11 - first official version bundled with ExSheets +2017/02/08 - change deprecated \c_job_name_tl into the new \c_sys_jobname_str + diff --git a/macros/latex/contrib/exsheets/exsheets.sty b/macros/latex/contrib/exsheets/exsheets.sty new file mode 100644 index 0000000000..73136dadac --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets.sty @@ -0,0 +1,3238 @@ +% ---------------------------------------------------------------------------- +% the EXSHEETS package +% +% Yet another package for the creation of exercise sheets +% +% ---------------------------------------------------------------------------- +% Clemens Niederberger +% Web: http://www.mychemistry.eu/forums/forum/exsheets +% E-Mail: contact@mychemistry.eu +% ---------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% ---------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% ---------------------------------------------------------------------------- +\RequirePackage { expl3 , xparse } +\ExplSyntaxOn + +\tl_const:Nn \c_exsheets_date_tl {2017/02/08} +\tl_const:Nn \c_exsheets_version_tl {0.21i} +\tl_const:Nn \c_exsheets_info_tl + {Yet~ another~ package~ for~ the~ creation~ of~ exercise~ sheets~ and~ exams.} + +\ProvidesExplPackage + {exsheets} + {\c_exsheets_date_tl} + {\c_exsheets_version_tl} + {\c_exsheets_info_tl} + +% ---------------------------------------------------------------------------- +% variants of kernel functions: +\cs_generate_variant:Nn \prop_get:NnN { NV , Nx , cV , cx } +\cs_generate_variant:Nn \prop_get:NnNF { NV , Nx , cV , cx } +\cs_generate_variant:Nn \prop_get:NnNT { NV , Nx , cV , cx } +\cs_generate_variant:Nn \prop_get:NnNTF { NV , Nx , cV , cx } +\cs_generate_variant:Nn \prop_gput:Nnn { Nf , Nff , Nfx , Nx , Nxx , NxV , cx , cxx } +\cs_generate_variant:Nn \prop_gput_if_new:Nnn { Nxx } +\cs_generate_variant:Nn \tl_if_blank:nTF { x } +\cs_generate_variant:Nn \tl_if_eq:nnF { x } +\cs_generate_variant:Nn \int_to_arabic:n { V } +\cs_generate_variant:Nn \seq_set_split:Nnn { NnV } +\cs_generate_variant:Nn \quark_if_no_value:nTF { V } + +% ---------------------------------------------------------------------------- +% temporary variables +\tl_new:N \l__exsheets_tmpa_tl +\tl_new:N \l__exsheets_tmpb_tl +\tl_new:N \l__exsheets_tmpc_tl +\int_new:N \l__exsheets_tmpa_int +\int_new:N \l__exsheets_tmpb_int +\int_new:N \l__exsheets_tmpc_int +\int_new:N \l__exsheets_tmpd_int +\int_new:N \l__exsheets_tmpe_int +\int_new:N \g__exsheets_tmpa_int +\dim_new:N \l__exsheets_tmpa_dim +\dim_new:N \l__exsheets_tmpb_dim +\seq_new:N \l__exsheets_tmpa_seq +\fp_new:N \l__exsheets_tmpa_fp +\clist_new:N \l__exsheets_tmpa_clist +\bool_new:N \l__exsheets_tmpa_bool + +% ---------------------------------------------------------------------------- +% messages +\msg_new:nnn {exsheets} {file-not-found} + { + You've~ requested~ the~ file~ `\tl_to_str:n {#1}'~ but~ I~ cannot~ find~ + it~ \msg_line_context: . + } + +\msg_new:nnn {exsheets} {totalpoints} + { + You~ need~ to~ activate~ `points/parse'~ if~ you~ want~ to~ use~ + \token_to_str:N \totalpoints .~ I~ will~ do~ nothing~ instead. + } + +\msg_new:nnn {exsheets} {parse-points} + { + You~ need~ to~ activate~ `points/parse'~ if~ you~ want~ to~ use~ + \token_to_str:N #1 .~ I~ will~ do~ nothing~ instead. + } + +\msg_new:nnn {exsheets} {headings} + { + You~ requested~ the~ headings~ instance~ `#1'~ \msg_line_context: \c_space_tl + which~ is~ not~ defined.~ Is~ this~ a~ typo?~ Anyway,~ I~ will~ use~ the~ + instance~ `block'~ instead~ and~pretend~ nothing~ happened. + } + +\msg_new:nnn {exsheets} {random-file} + { + You~ asked~ me~ to~ select~ #1~ questions~ from~ file~ #2~ which~ + contains~ #3~ questions.~ I'll~ select~ all~ of~ them. + } + +\msg_new:nnn {exsheets} {random-selectable} + { + You~ asked~ me~ to~ select~ #1~ questions~ from~ file~ #2~ which~ + contains~ #3~ questions.~ #4~ of~ these~ are~ selectable,~ so~ I'll~ + select~ all~ of~ them. + } + +\msg_new:nnn {exsheets} {only-inside-question} + { + The~ command~ `~ \token_to_str:N #1 \c_space_tl'~ can~ only~ be~ used~ + inside~ the~ question~ environment. + } + +\msg_new:nnn {exsheets} {loading-configurations} + { Loading~ custom~ configurations~ file~ `exsheets_configurations.cgf'. } + +\msg_new:nnn {exsheets} {deprecated-command} + { + The~ command~ `#1'~ is~ deprecated.~ Use~ `#2'~ instead. + } + +\msg_new:nnn {exsheets} {dropped-option} + { The~ option~ `#1'~ has~ been~ dropped. } + +\msg_new:nnn {exsheets} {grade-missing} + { The~ grade~ `#1'~ has~ never~ been~ declared. } + +\msg_new:nnn {exsheets} {grade-parse} + { + I~ cannot~ calculate~ the~ points~ for~ grade~ `#1'~ since~ you're~ using~ + the~ option~ `points/parse=false'. + } + +\msg_new:nnn {exsheets} {variations} + { + The~ number~ of~ variations~ must~ at~ least~ be~ `2'.~ You~ chose~ `#1'~ + hence~ I'm~ doing~ nothing. + } + +\msg_new:nnn {exsheets} {variant} + { + You~ must~ choose~ an~ integer~ between~ `1'~ and~ `#1'.~ You~ chose~ + `#2'~ hence~ I'm~ doing~ nothing. + } + +\cs_new_protected:Npn \exsheets_deprecate_cs:Npnn #1#2# + { \__exsheets_deprecate_cs:Nnnn #1 {#2} } +\cs_new_protected:Npn \__exsheets_deprecate_cs:Nnnn #1#2#3#4 + { + \cs_new_protected:Npn #1 #2 + { + \tl_if_blank:nTF {#3} + { \msg_warning:nnnn {exsheets} { deprecated-command } {#1} {#4} } + { \msg_warning:nnnn {exsheets} { deprecated-command } {#1} {#3} } + #4 + } + } + +\cs_new_protected:Npn \exsheets_option_dropped:n #1 + { \msg_warning:nnn {exsheets} {dropped-option} {#1} } + +% ---------------------------------------------------------------------------- +\RequirePackage + { xtemplate , l3keys2e , etoolbox , environ , pgfcore } + +% ---------------------------------------------------------------------------- +% write to aux file: +\cs_new_protected:Npn \exsheets_write_to_aux_x:n #1 + { \if@filesw \iow_now:Nx \@auxout {#1} \fi } + +% prevent compilatin errors when exsheets is removed from a document: +\AtBeginDocument{ + \exsheets_write_to_aux_x:n + { + \exp_not:N \providecommand \exp_not:N \exsheets@question@property[3]{} ^^J + \exp_not:N \providecommand \exp_not:N \exsheets@save@number[2]{} ^^J + \exp_not:N \providecommand \exp_not:N \exsheets@sum@of@points[1]{} ^^J + \exp_not:N \providecommand \exp_not:N \exsheets@sum@of@bonus[1]{} ^^J + \exp_not:N \providecommand \exp_not:N \exsheets@used@id[2]{} ^^J + } +} + +% ---------------------------------------------------------------------------- +% variables: +\bool_new:N \l__exsheets_print_number_bool +\bool_set_true:N \l__exsheets_print_number_bool +\bool_new:N \l__exsheets_solutions_by_ref_bool +\bool_new:N \l__exsheets_questions_totoc_bool +\bool_new:N \l__exsheets_solutions_totoc_bool +\bool_new:N \l__exsheets_auto_label_bool +\bool_new:N \l__exsheets_no_skip_after_bool +\bool_new:N \l__exsheets_points_questions_default_bool +\bool_set_false:N \l__exsheets_points_questions_default_bool +\bool_new:N \l__exsheets_parse_points_bool +\bool_set_true:N \l__exsheets_parse_points_bool +\bool_new:N \l__exsheets_points_name_bool +\bool_set_true:N \l__exsheets_points_name_bool +\bool_new:N \l__exsheets_points_separate_bonus_bool +\bool_new:N \l__exsheets_grades_half_bool +\bool_new:N \g__exsheets_questions_use_bool +\bool_gset_true:N \g__exsheets_questions_use_bool +\bool_new:N \l__exsheets_questions_use_bool +\bool_set_true:N \l__exsheets_questions_use_bool +\bool_new:N \l__exsheets_questions_deactivate_bool +\bool_new:N \l__exsheets_save_question_body_to_aux_bool +\bool_set_false:N \l__exsheets_save_question_body_to_aux_bool +\bool_new:N \l__exsheets_solutions_use_bool +\bool_set_true:N \l__exsheets_solutions_use_bool +\bool_new:N \l__exsheets_use_this_question_bool +\bool_new:N \l__exsheets_questions_print_bool +\bool_set_true:N \l__exsheets_questions_print_bool +\bool_new:N \l__exsheets_inside_question_bool +\bool_new:N \l__exsheets_only_print_points_bool +\bool_new:N \l__exsheets_exam_bool +\bool_set_false:N \l__exsheets_exam_bool +\bool_new:N \l__exsheets_questions_runin_bool +\bool_set_false:N \l__exsheets_questions_runin_bool +\bool_new:N \l__exsheets_questions_debug_bool +\bool_set_false:N \l__exsheets_questions_debug_bool +\bool_new:N \l__exsheets_select_questions_bool +\bool_new:N \l__exsheets_include_all_bool +\bool_new:N \l__exsheets_include_random_bool +\bool_new:N \l__exsheets_include_by_id_bool +\bool_set_true:N \l__exsheets_include_all_bool +\bool_new:N \l__exsheets_include_questions_no_duplicates_bool +\bool_new:N \l__exsheets_use_selection_bool +\bool_new:N \l__exsheets_solutions_print_bool +\bool_set_false:N \l__exsheets_solutions_print_bool +\bool_new:N \l__exsheets_solutions_print_section_bool +\bool_set_false:N \l__exsheets_solutions_print_section_bool +\bool_new:N \l__exsheets_solutions_print_chapter_bool +\bool_set_false:N \l__exsheets_solutions_print_chapter_bool +\bool_new:N \l__exsheets_solutions_print_all_bool +\bool_set_false:N \l__exsheets_solutions_print_all_bool +\bool_new:N \l__exsheets_inside_solution_bool +\bool_set_false:N \l__exsheets_inside_solution_bool +\bool_new:N \l__exsheets_solutions_runin_bool +\bool_set_false:N \l__exsheets_solutions_runin_bool +\bool_new:N \l__exsheets_print_byID_sorted_bool +\bool_set_true:N \l__exsheets_print_byID_sorted_bool +\bool_new:N \l__exsheets_blank_width_bool +\bool_new:N \l__exsheets_blank_linespread_bool + +\tl_new:N \l__exsheets_points_name_tl +\tl_set:Nn \l__exsheets_points_name_tl {P.} +\tl_new:N \l__exsheets_points_name_plural_tl +\tl_set:Nn \l__exsheets_points_name_plural_tl {P.} +\tl_new:N \l__exsheets_bonus_name_tl +\tl_set:Nn \l__exsheets_bonus_name_tl {P.} +\tl_new:N \l__exsheets_bonus_name_plural_tl +\tl_set:Nn \l__exsheets_bonus_name_plural_tl {P.} +\tl_new:N \l__exsheets_points_number_format_tl +\tl_new:N \l__exsheets_bonus_number_format_tl +\tl_new:N \l__exsheets_points_pre_bonus_marker_tl +\tl_set:Nn \l__exsheets_points_pre_bonus_marker_tl { \space(+ } +\tl_new:N \l__exsheets_points_post_bonus_marker_tl +\tl_set:Nn \l__exsheets_points_post_bonus_marker_tl { ) } +\tl_new:N \l__exsheets_points_format_tl +\tl_set:Nn \l__exsheets_points_format_tl { \use:n } +\tl_new:N \l__exsheets_qu_counter_pattern_tl +\tl_set:Nn \l__exsheets_qu_counter_pattern_tl { qu. } +\tl_new:N \l__exsheets_qu_counter_interpretation_tl +\tl_new:N \l__exsheets_counter_patterns_tl +\tl_new:N \l__exsheets_heading_instance_tl +\tl_set:Nn \l__exsheets_heading_instance_tl {block} +\tl_new:N \l__exsheets_question_heading_instance_tl +\tl_new:N \l__exsheets_solution_heading_instance_tl +\tl_new:N \l_exsheets_heading_title_question_format_tl +\tl_new:N \l_exsheets_heading_title_solution_format_tl +\tl_new:N \l_exsheets_heading_subtitle_question_format_tl +\tl_new:N \l_exsheets_heading_subtitle_solution_format_tl +\tl_new:N \l__exsheets_questions_toclevel_tl +\tl_set:Nn \l__exsheets_questions_toclevel_tl {subsection} +\tl_new:N \l__exsheets_solutions_toclevel_tl +\tl_set:Nn \l__exsheets_solutions_toclevel_tl {subsection} +\tl_new:N \l__exsheets_new_chapter_hook_tl +\tl_new:N \l__exsheets_new_section_hook_tl +\tl_new:N \g__exsheets_use_current_question_tl +\tl_new:N \l__exsheets_questions_name_tl +\tl_set:Nn \l__exsheets_questions_name_tl {Question} +\tl_new:N \l__exsheets_exercise_name_tl +\tl_set:Nn \l__exsheets_exercise_name_tl {Exercise} +\tl_new:N \l__exsheets_questions_pre_hook_tl +\tl_new:N \l__exsheets_questions_post_hook_tl +\tl_new:N \l__exsheets_questions_pre_body_hook_tl +\tl_new:N \l__exsheets_questions_post_body_hook_tl +\tl_new:N \l__exsheets_after_begin_question_tl +\tl_new:N \CurrentQuestionID +\tl_new:N \l__exsheets_questions_id_tl +\tl_new:N \l__exsheets_questions_subtitle_tl +\tl_new:N \g__exsheets_questions_current_id_tl +\tl_new:N \l__exsheets_questions_title_tl +\tl_new:N \l__exsheets_questions_label_tl +\tl_new:N \l__exsheets_questions_points_tl +\tl_new:N \l__exsheets_include_id_tl +\tl_new:N \l__exsheets_solutions_name_tl +\tl_set:Nn \l__exsheets_solutions_name_tl {Solution} +\tl_new:N \l__exsheets_solutions_pre_body_hook_tl +\tl_new:N \l__exsheets_solutions_post_body_hook_tl +\tl_new:N \l__exsheets_solutions_pre_hook_tl +\tl_new:N \l__exsheets_solutions_post_hook_tl +\tl_new:N \l__exsheets_blank_linespread_tl +\tl_set:Nn \l__exsheets_blank_linespread_tl { 1 } +\tl_new:N \l__exsheets_blank_scale_tl +\tl_set:Nn \l__exsheets_blank_scale_tl { 1 } +\tl_new:N \l__exsheets_use_solution_tl +\tl_new:N \l_exsheets_solutions_name_style_tl +\tl_set:Nn \l_exsheets_solutions_name_style_tl { \normalsize \bfseries } + +\int_zero_new:N \l__exsheets_variations_int +\int_new:N \g__exsheets_questions_id_int +\int_gzero:N \g__exsheets_questions_id_int +\int_new:N \g__exsheets_questions_used_int +\int_zero_new:N \l__exsheets_include_random_int +\int_new:N \l__exsheets_questions_set_int +\int_new:N \g__exsheets_select_random_int +\int_new:N \g__exsheets_selection_number_int +\int_new:N \l__exsheets_counter_ch_int +\int_new:N \l__exsheets_current_ch_int +\int_new:N \l__exsheets_counter_sec_int +\int_new:N \l__exsheets_current_sec_int +\int_new:N \l_exsheets_counter_qu_int + +\fp_new:N \g__exsheets_points_sum_fp +\fp_new:N \l__exsheets_points_default_fp +\fp_set:Nn \l__exsheets_points_default_fp {1} +\fp_new:N \l__exsheets_question_points_fp +\fp_new:N \g_exsheets_total_points_fp +\fp_new:N \g__exsheets_bonus_sum_fp +\fp_new:N \l__exsheets_question_bonus_fp +\fp_new:N \g_exsheets_total_bonus_fp +\fp_new:N \l__exsheets_grade_round_fp +\fp_zero:N \l__exsheets_grade_round_fp +\fp_new:N \g__exsheets_this_question_points_fp +\fp_new:N \g__exsheets_this_question_bonus_fp + +\dim_new:N \l__exsheets_questions_skip_below_dim +\dim_set:Nn \l__exsheets_questions_skip_below_dim { .5\baselineskip } +\dim_new:N \l__exsheets_solutions_skip_below_dim +\dim_set:Nn \l__exsheets_solutions_skip_below_dim { .5\baselineskip } +\dim_new:N \l__exsheets_blank_dim +\dim_new:N \l__exsheets_blank_line_increment_dim +\dim_new:N \l__exsheets_blank_line_minimum_length_dim + +\seq_new:N \l__exsheets_use_tags_seq +\seq_new:N \g_exsheets_included_questions_seq + +\prop_new:N \l__exsheets_relgrades_prop +\prop_new:N \l__exsheets_class_prop +\prop_new:N \g__exsheets_tags_prop +\prop_new:N \g__exsheets_questions_id_prop +\prop_new:N \g__exsheets_questions_subtitle_prop +\prop_new:N \g__exsheets_questions_used_prop +\prop_new:N \g_exsheets_question_identification_prop +\prop_new:N \g__exsheets_included_questions_prop +\prop_new:N \g__exsheets_solutions_content_prop +\prop_new:N \g__exsheets_solutions_questions_id_prop +\prop_new:N \g__exsheets_solutions_names_prop +\prop_new:N \g__exsheets_solutions_counter_prop + +\clist_new:N \l__exsheets_include_id_clist +\clist_new:N \l__exsheets_exclude_id_clist +\clist_new:N \questionsincludedlast + +\box_new:N \l__exsheets_blank_box + +% ---------------------------------------------------------------------------- +% how are questions/solutions/... counted? +\RequirePackage {cntformats} + +\cs_if_exist:NT \thechapter + { + \AddCounterPattern* [exsheets] {chapter} {ch} + \ReadCounterFrom [exsheets] {chapter} \l__exsheets_counter_ch_int + } + +\AddCounterPattern* [exsheets] {section} {se} +\ReadCounterFrom [exsheets] {section} \l__exsheets_counter_sec_int + +\NewCounterPattern* [exsheets] {question} {qu} +\ReadCounterFrom [exsheets] {question} \l_exsheets_counter_qu_int + +% ---------------------------------------------------------------------------- +% (also) package options: +\keys_define:nn {exsheets} + { + counter-format .code:n = + \SaveCounterPattern [exsheets] + \l__exsheets_qu_counter_pattern_tl + \l__exsheets_qu_counter_interpretation_tl + {#1} , + counter-format .initial:n = qu. , + counter-within .code:n = \@addtoreset {question} {#1} , + headings .tl_set:N = \l__exsheets_heading_instance_tl , + load-headings .code:n = + \exsheets_option_dropped:n {load-headings} , + question/headings-format .tl_set:N = + \l_exsheets_heading_title_question_format_tl , + solution/headings-format .tl_set:N = + \l_exsheets_heading_title_solution_format_tl , + headings-format .meta:n = + { + question/headings-format = {#1} , + solution/headings-format = {#1} + } , + headings-format .initial:n = \normalsize\bfseries , + question/subtitle-format .tl_set:N = + \l_exsheets_heading_subtitle_question_format_tl , + solution/subtitle-format .tl_set:N = + \l_exsheets_heading_subtitle_solution_format_tl , + subtitle-format .meta:n = + { + question/subtitle-format = {#1} , + solution/subtitle-format = {#1} + } , + subtitle-format .initial:n = \normalsize\itshape , + load-tasks .code:n = + \exsheets_option_dropped:n {load-tasks} , + use-ref .bool_set:N = \l__exsheets_solutions_by_ref_bool , + totoc .choice: , + totoc / true .code:n = + \bool_set_true:N \l__exsheets_questions_totoc_bool + \bool_set_true:N \l__exsheets_solutions_totoc_bool , + totoc / false .code:n = + \bool_set_false:N \l__exsheets_questions_totoc_bool + \bool_set_false:N \l__exsheets_solutions_totoc_bool , + totoc .default:n = true , + questions-totoc .bool_set:N = \l__exsheets_questions_totoc_bool , + solutions-totoc .bool_set:N = \l__exsheets_solutions_totoc_bool , + toc-level .code:n = + \tl_set:Nn \l__exsheets_questions_toclevel_tl {#1} + \tl_set:Nn \l__exsheets_solutions_toclevel_tl {#1} , + questions-toc-level .tl_set:N = \l__exsheets_questions_toclevel_tl , + solutions-toc-level .tl_set:N = \l__exsheets_solutions_toclevel_tl , + skip-below .code:n = + \dim_set:Nn \l__exsheets_questions_skip_below_dim {#1} + \dim_set:Nn \l__exsheets_solutions_skip_below_dim {#1} , + no-skip-below .bool_set:N = \l__exsheets_no_skip_after_bool , + auto-label .bool_set:N = \l__exsheets_auto_label_bool , + label-format .code:n = + \cs_set:Npn \exsheets_label_format:n ##1 {#1} + \exsheets_update_referencing_commands: , + label-cmd .code:n = + \cs_set:Npn \__exsheets_label:n {#1} + \exsheets_update_referencing_commands: , + ref-cmd .code:n = + \cs_set:Npn \__exsheets_ref:n {#1} + \exsheets_update_referencing_commands: , + page-ref-cmd .code:n = + \cs_set:Npn \__exsheets_pageref:n {#1} + \exsheets_update_referencing_commands: , + chapter-hook .tl_set:N = \l__exsheets_new_chapter_hook_tl , + section-hook .tl_set:N = \l__exsheets_new_section_hook_tl %, +% use-saved-counter-format .bool_set:N = \l__exsheets_use_saved_pattern_bool + } + +% TODO: remove this in a v1.0: +% process package options: +\ProcessKeysOptions {exsheets} + +% ---------------------------------------------------------------------------- +% points for exercises +\cs_new_protected:Npn \__exsheets_set_points_name:nNN #1#2#3 + { + \tl_if_in:nnTF {#1} { / } + { \__exsheets_set_points_name_aux:wNN #1 \q_mark #2#3 } + { \__exsheets_set_points_name_aux:wNN #1 / \q_mark #2#3 } + } + +\cs_new_protected:Npn \__exsheets_set_points_name_aux:wNN #1/#2 \q_mark #3#4 + { + \tl_set:Nn #3 {#1} + \tl_set:Nn #4 { #1#2 } + } + +\cs_new_protected:Npn \exsheets_set_points_name:n #1 + { + \__exsheets_set_points_name:nNN {#1} + \l__exsheets_points_name_tl + \l__exsheets_points_name_plural_tl + } + +\cs_new_protected:Npn \exsheets_set_bonus_name:n #1 + { + \__exsheets_set_points_name:nNN {#1} + \l__exsheets_bonus_name_tl + \l__exsheets_bonus_name_plural_tl + } + +% FIXME: \fp_add will deprecate! +\cs_new_protected:Npn \exsheets_add_points:n #1 + { + \fp_gadd:Nn \g__exsheets_points_sum_fp {#1} + \fp_gadd:Nn \g__exsheets_this_question_points_fp {#1} + } +\cs_generate_variant:Nn \exsheets_add_points:n { V } + +\cs_new_protected:Npn \exsheets_add_bonus:n #1 + { + \fp_gadd:Nn \g__exsheets_bonus_sum_fp {#1} + \fp_gadd:Nn \g__exsheets_this_question_bonus_fp {#1} + } +\cs_generate_variant:Nn \exsheets_add_bonus:n { V } + +\cs_new_protected:Npn \exsheets@sum@of@points #1 + { \fp_gset:Nn \g_exsheets_total_points_fp {#1} } + +\cs_new_protected:Npn \exsheets@sum@of@bonus #1 + { \fp_gset:Nn \g_exsheets_total_bonus_fp {#1} } + +\cs_new:Npn \__exsheets_parse_points:nN #1#2 + { + \group_begin: + \tl_use:N #2 + { + \bool_if:NTF \l__exsheets_parse_points_bool + { \exsheets_num:n {#1} } + { \use:n {#1} } + } + \group_end: + } +\cs_new:Npn \exsheets_parse_points:n #1 + { + \__exsheets_parse_points:nN {#1} + \l__exsheets_points_number_format_tl + } +\cs_generate_variant:Nn \exsheets_parse_points:n { V } + +\cs_new:Npn \exsheets_parse_bonus:n #1 + { + \__exsheets_parse_points:nN {#1} + \l__exsheets_bonus_number_format_tl + } +\cs_generate_variant:Nn \exsheets_parse_bonus:n { V } + +\cs_new:Npn \exsheets_num:n #1 + { \fp_to_decimal:n {#1} } +\cs_generate_variant:Nn \exsheets_num:n { V,x } + +\cs_new:Npn \__exsheets_print_points_name:nNN #1#2#3 + { + \bool_if:NT \l__exsheets_points_name_bool + { + \, + \hbox:n + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \tl_if_eq:nnTF {#1} { ?? } + { \tl_use:N #3 } + { + \fp_compare:nTF { #1 = 1 } + { \tl_use:N #2 } + { \tl_use:N #3 } + } + } + { \tl_use:N #3 } + } + } + } + +\cs_new:Npn \exsheets_points_name:n #1 + { + \__exsheets_print_points_name:nNN {#1} + \l__exsheets_points_name_tl + \l__exsheets_points_name_plural_tl + } +\cs_generate_variant:Nn \exsheets_points_name:n { V } + +\cs_new:Npn \exsheets_bonus_name:n #1 + { + \__exsheets_print_points_name:nNN {#1} + \l__exsheets_bonus_name_tl + \l__exsheets_bonus_name_plural_tl + } +\cs_generate_variant:Nn \exsheets_bonus_name:n { V } + +\NewDocumentCommand \addpoints { sm } + { + \bool_if:NTF \l__exsheets_inside_question_bool + { + \exsheets_add_points:n {#2} + \IfBooleanF {#1} { \exsheets_print_points:n {#2} } + } + { \msg_error:nnn {exsheets} {only-inside-question} {\addpoints} } + } + +\NewDocumentCommand \addbonus { sm } + { + \bool_if:NTF \l__exsheets_inside_question_bool + { + \exsheets_add_bonus:n {#2} + \IfBooleanF {#1} { \exsheets_print_bonus:n {#2} } + } + { \msg_error:nnn {exsheets} {only-inside-question} {\addbonus} } + } + +\NewDocumentCommand \points { sm } + { + \IfBooleanTF {#1} + { \exsheets_parse_points:n {#2} } + { \exsheets_print_points:n {#2} } + } + +\NewDocumentCommand \bonus { sm } + { + \IfBooleanTF {#1} + { \exsheets_parse_bonus:n {#2} } + { \exsheets_print_bonus:n {#2} } + } + +\cs_new_protected:Npn \exsheets_print_points:n #1 + { + \group_begin: + \tl_use:N \l__exsheets_points_format_tl + { + \exsheets_parse_points:n {#1} + \exsheets_points_name:n {#1} + } + \group_end: + } +\cs_generate_variant:Nn \exsheets_print_points:n { V } + +\cs_new_protected:Npn \exsheets_print_bonus:n #1 + { + \exsheets_parse_bonus:n {#1} + \exsheets_bonus_name:n {#1} + } +\cs_generate_variant:Nn \exsheets_print_bonus:n { V } + +\NewDocumentCommand \pointssum { s } + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \IfBooleanTF {#1} + { \exsheets_parse_points:n { \g_exsheets_total_points_fp } } + { \exsheets_print_points:n { \g_exsheets_total_points_fp } } + } + { \msg_warning:nnn {exsheets} {parse-points} {\pointssum} } + } + +\NewDocumentCommand \bonussum { s } + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \IfBooleanTF {#1} + { \exsheets_parse_bonus:n { \g_exsheets_total_bonus_fp } } + { \exsheets_print_bonus:n { \g_exsheets_total_bonus_fp } } + } + { \msg_warning:nnn {exsheets} {parse-points} {\bonussum} } + } + +\NewDocumentCommand \currentpointssum { s } + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \IfBooleanTF {#1} + { \exsheets_parse_points:n { \g__exsheets_points_sum_fp } } + { \exsheets_print_points:n { \g__exsheets_points_sum_fp } } + } + { \msg_warning:nnn {exsheets} {parse-points} {\currentpointssum} } + } + +\NewDocumentCommand \currentbonussum { s } + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \IfBooleanTF {#1} + { \exsheets_parse_bonus:n { \g__exsheets_bonus_sum_fp } } + { \exsheets_print_bonus:n { \g__exsheets_bonus_sum_fp } } + } + { \msg_warning:nnn {exsheets} {parse-points} {\currentbonussum} } + } + +\NewDocumentCommand \totalpoints { s } + { + \group_begin: + \tl_use:N \l__exsheets_points_format_tl + { + \exsheets_totalpoints: + \IfBooleanF {#1} + { + \bool_if:nT + { + \l__exsheets_points_separate_bonus_bool || + \fp_compare_p:n { \g_exsheets_total_bonus_fp = 0 } + } + { \exsheets_points_name:n { \g_exsheets_total_points_fp } } + } + \exsheets_totalbonus: + \IfBooleanF {#1} + { + \fp_compare:nF { \g_exsheets_total_bonus_fp = 0 } + { + \bool_if:NTF \l__exsheets_points_separate_bonus_bool + { \exsheets_bonus_name:n { \g_exsheets_total_bonus_fp } } + { + \exsheets_points_name:n + { \g_exsheets_total_points_fp + \g_exsheets_total_bonus_fp } + } + } + } + } + \group_end: + } + +\exsheets_deprecate_cs:Npnn \sumpoints {} { \totalpoints* } + +\cs_new_protected:Npn \exsheets_totalpoints: + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \fp_compare:nTF { \g_exsheets_total_points_fp = 0 } + { ?? \, \exsheets_points_name:n { ?? } } + { + \exsheets_parse_points:n + { \g_exsheets_total_points_fp } + } + } + { \msg_warning:nn {exsheets} {totalpoints} } + } + +\cs_new:Npn \exsheets_totalbonus: + { + \bool_if:NT \l__exsheets_parse_points_bool + { + \fp_compare:nF { \g_exsheets_total_bonus_fp = 0 } + { + \tl_use:N \l__exsheets_points_pre_bonus_marker_tl + \exsheets_parse_bonus:n + { \g_exsheets_total_bonus_fp } + \tl_use:N \l__exsheets_points_post_bonus_marker_tl + } + } + } + +\keys_define:nn { exsheets / points } + { + name .code:n = + \exsheets_set_points_name:n {#1} + \exsheets_set_bonus_name:n {#1} , + name-plural .code:n = + \tl_set:Nn \l__exsheets_points_name_plural_tl {#1} + \tl_set:Nn \l__exsheets_bonus_name_plural_tl {#1} , + bonus-name .code:n = \exsheets_set_bonus_name:n {#1} , + bonus-plural .tl_set:N = \l__exsheets_bonus_name_plural_tl , + pre-bonus .tl_set:N = \l__exsheets_points_pre_bonus_marker_tl , + post-bonus .tl_set:N = \l__exsheets_points_post_bonus_marker_tl , + use-name .bool_set:N = \l__exsheets_points_name_bool , + format .tl_set:N = \l__exsheets_points_format_tl , + number-format .tl_set:N = \l__exsheets_points_number_format_tl , + bonus-format .tl_set:N = \l__exsheets_bonus_number_format_tl , + parse .bool_set:N = \l__exsheets_parse_points_bool , + separate-bonus .bool_set:N = \l__exsheets_points_separate_bonus_bool + } + +% ---------------------------------------------------------------------------- +% variations of an exam, see http://tex.stackexchange.com/q/57012/5049 for +% inspiration of the following features +\cs_new_protected:Npn \exsheets_set_variations:n #1 + { + \int_compare:nNnTF {#1} < { 2 } + { \msg_warning:nnn {exsheets} {variations} {#1} } + { + \int_set:Nn \l__exsheets_variations_int {#1} + \int_zero:N \l__exsheets_tmpa_int + \int_do_while:nNnn + { \l__exsheets_tmpa_int } < { \l__exsheets_variations_int } + { + \int_incr:N \l__exsheets_tmpa_int + \__exsheets_generate_variation_auxiliary:n + { \l__exsheets_tmpa_int } + \__exsheets_reset_variation_auxiliary:x + { \int_use:N \l__exsheets_tmpa_int } + } + \__exsheets_generate_variation_auxiliary:n + { \l__exsheets_variations_int + 1 } + \exsheets_variant:n { 1 } + } + } + +\cs_new_protected:Npn \exsheets_variant:n #1 + { + \bool_if:nTF + { + \int_compare_p:nNn {#1} > { 0 } && + \int_compare_p:nNn {#1} < { \l__exsheets_variations_int + 1 } + } + { + \int_zero:N \l__exsheets_tmpa_int + \int_do_while:nNnn + { \l__exsheets_tmpa_int } < { \l__exsheets_variations_int } + { + \int_incr:N \l__exsheets_tmpa_int + \__exsheets_reset_variation_auxiliary:x + { \int_use:N \l__exsheets_tmpa_int } + } + \cs_set:cpn { __exsheets_variation_ \int_to_roman:n {#1} :n } ##1 + { + ##1 + \cs_set:Npn \exsheets_last_variant: {##1} + \use:c { __exsheets_variation_ \int_to_roman:n { #1 + 1 } :n } + } + } + { + \msg_warning:nnxx {exsheets} {variant} + { \int_use:N \l__exsheets_variations_int } {#1} + } + } + +\cs_new_protected:Npn \exsheets_vary:w + { \__exsheets_variation_i:n } + +\cs_new:Npn \exsheets_last_variant: { } + +\cs_new_protected:Npn \__exsheets_generate_variation_auxiliary:n #1 + { + \cs_if_exist:cTF { __exsheets_variation_ \int_to_roman:n {#1} :n } + { \cs_set:cpn { __exsheets_variation_ \int_to_roman:n {#1} :n } { } } + { \cs_new:cpn { __exsheets_variation_ \int_to_roman:n {#1} :n } { } } + } + +\cs_new_protected:Npn \__exsheets_reset_variation_auxiliary:n #1 + { + \cs_set:cpn { __exsheets_variation_ \int_to_roman:n {#1} :n } ##1 + { \use:c { __exsheets_variation_ \int_to_roman:n { #1 + 1 } :n } } + } +\cs_generate_variant:Nn \__exsheets_reset_variation_auxiliary:n { x } + +\NewDocumentCommand \SetVariations { m } + { \exsheets_set_variations:n {#1} } + +\NewDocumentCommand \variant { m } + { \exsheets_variant:n {#1} } + +\NewDocumentCommand \vary { } + { \exsheets_vary:w } + +\NewDocumentCommand \lastvariant { } + { \exsheets_last_variant: } + +% initiate: two variations, first is default +\SetVariations { 2 } +\variant { 1 } + +% ---------------------------------------------------------------------------- +% grades distribution +\cs_new:Npn \__exsheets_fp_round_to_half:n #1 + { round( 2*(#1),0)/2 } + +\cs_new:Npn \__exsheets_grades_round:n #1 + { round ( #1 , \l__exsheets_grade_round_fp ) } + +\cs_new:Npn \__exsheets_grade_rounded: + { + \bool_if:NTF { \l__exsheets_grades_half_bool } + { \__exsheets_fp_round_to_half:n } + { \__exsheets_grades_round:n } + { \g_exsheets_total_points_fp * \l__exsheets_tmpa_fp } + } + +\cs_new:Npn \exsheets_strip_braces:N #1 + { \exp_after:wN \__exsheets_strip_braces:w \exp_after:wN #1#1 \q_stop } +\cs_new_protected:Npn \__exsheets_strip_braces:w #1#2 \q_stop + { \tl_set:Nn #1 {#2} } + +\cs_new_protected:Npn \__exsheets_declare_relgrades:n #1 + { + \clist_set:Nn \l__exsheets_tmpa_clist {#1} + \clist_map_inline:Nn \l__exsheets_tmpa_clist + { \__exsheets_declare_relgrade:w ##1 \q_stop } + } + +\cs_new_protected:Npn \__exsheets_declare_relgrade:w #1 = #2 \q_stop + { + \tl_set:Nn \l__exsheets_tmpa_tl {#1} + \tl_set:Nn \l__exsheets_tmpb_tl {#2} + \tl_trim_spaces:N \l__exsheets_tmpa_tl + \exsheets_strip_braces:N \l__exsheets_tmpa_tl + \tl_trim_spaces:N \l__exsheets_tmpb_tl + \exsheets_strip_braces:N \l__exsheets_tmpb_tl + \prop_put:NVV \l__exsheets_relgrades_prop + \l__exsheets_tmpa_tl + \l__exsheets_tmpb_tl + } + +\NewDocumentCommand \DeclareRelGrades { m } + { \__exsheets_declare_relgrades:n {#1} } +\@onlypreamble \DeclareRelGrades + +\cs_new_protected:Npn \__exsheets_grade:nn #1#2 + { + \prop_get:NnNTF \l__exsheets_relgrades_prop {#2} \l__exsheets_tmpa_fp + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \exsheets_parse_points:n + { min( \__exsheets_grade_rounded: , \g_exsheets_total_points_fp ) } + \int_compare:nT { #1 = 1 } + { + \exsheets_points_name:n + { min( \__exsheets_grade_rounded: , \g_exsheets_total_points_fp ) } + } + } + { \msg_warning:nnn {exsheets} {grade-parse} {#1} \textbf{??} } + } + { \msg_warning:nnn {exsheets} {grade-missing} {#1} \textbf{??} } + } + +\NewDocumentCommand \grade { sm } + { + \IfBooleanTF {#1} + { \__exsheets_grade:nn { 0 } {#2} } + { \__exsheets_grade:nn { 1 } {#2} } + } + +\keys_define:nn { exsheets / grades } + { + round .fp_set:N = \l__exsheets_grade_round_fp , + half .bool_set:N = \l__exsheets_grades_half_bool + } + +% ---------------------------------------------------------------------------- +% Aufgaben und Lösungen +\cs_new:Npn \exsheets_glue:N #1 + { \cleaders \vbox:n {} \skip_vertical:N #1 } + +% classes, topics and other group concepts: +\cs_new_protected:Npn \exsheets_new_question_class:nn #1#2 + { + \prop_put:Nnn \l__exsheets_class_prop {#2} {#1} + \prop_new:c { g__exsheets_questions_#1_prop } + \prop_new:c { g__exsheets_#2_prop } + \prop_new:c { g__exsheets_#2_active_prop } + \bool_new:c { l__exsheets_questions_#1_bool } + \bool_new:c { g__exsheets_use_#2_bool } + \bool_new:c { l__exsheets_#1_active_bool } + \tl_new:c { l__exsheets_questions_#1_tl } + \keys_define:nn {exsheets} + { + use-#2 .code:n = + { + \bool_gset_true:c { g__exsheets_use_#2_bool } + \use:c { __exsheets_activate_#2:n } {##1} + } , + question / #1 .code:n = + \bool_set_true:c { l__exsheets_questions_#1_bool } + \tl_set:cn { l__exsheets_questions_#1_tl } {##1} + } + \cs_new_protected:cpn { __exsheets_activate_#2:n } ##1 + { + \prop_gclear:c { g__exsheets_#2_active_prop } + \seq_set_split:Nnn \l__exsheets_tmpa_seq { , } {##1} + \seq_map_inline:Nn \l__exsheets_tmpa_seq + { + \prop_gput:cnn { g__exsheets_#2_active_prop } + {####1} { \__exsheets_dummy: } + } + } + \cs_new_protected:cpn { __exsheets_questions_use_#2: } + { + % is there a #1 provided? + \bool_if:cT { l__exsheets_questions_#1_bool } + { + % add #1 to questions property + \prop_gput:cxx { g__exsheets_questions_#1_prop } + { \int_to_arabic:n { \g__exsheets_questions_id_int } } + { \exp_not:v { l__exsheets_questions_#1_tl } } + % add to #2 list, if it's a new one + \prop_get:cxNF { g__exsheets_#2_prop } + { \exp_not:v { l__exsheets_questions_#1_tl } } + \l__exsheets_tmpa_tl + { + \prop_gput:cxn { g__exsheets_#2_prop } + { \exp_not:v { l__exsheets_questions_#1_tl } } + { \__exsheets_dummy: } + } + } + % are we using #2? + \bool_if:cT { g__exsheets_use_#2_bool } + { + % is this question an active one? + \prop_get:cxNTF { g__exsheets_#2_active_prop } + { \exp_not:v { l__exsheets_questions_#1_tl } } + \l__exsheets_tmpa_tl + { + \bool_set_true:c { l__exsheets_#1_active_bool } + \bool_set_true:N \l__exsheets_use_this_question_bool + } + { + \bool_set_false:c { l__exsheets_#1_active_bool } + \bool_set_false:N \l__exsheets_questions_print_bool + } + } + } + \cs_new_protected:cpn { __exsheets_solutions_use_#2: } + { + % are we using #2? + \bool_if:cT { g__exsheets_use_#2_bool } + { + % is the question to this solution an active one? + % get question number from ID + \prop_get:NVN \g__exsheets_questions_id_prop + \g__exsheets_questions_current_id_tl + \l__exsheets_tmpa_tl + % get question #1 from number + \prop_get:cVN { g__exsheets_questions_#1_prop } + \l__exsheets_tmpa_tl + \l__exsheets_tmpb_tl + % test if #1 is active + \prop_get:cVNF { g__exsheets_#2_active_prop } + \l__exsheets_tmpb_tl + \l__exsheets_tmpc_tl + { \bool_set_false:N \l__exsheets_solutions_use_bool } + % \bool_show:N \l__exsheets_solutions_use_bool + } + } + } + +\cs_new_protected:Npn \exsheets_declare_question_class:nn #1#2 + { + \prop_if_in:NnTF \l__exsheets_class_prop {#2} + {} + { \exsheets_new_question_class:nn {#1} {#2} } + } + +\NewDocumentCommand \DeclareQuestionClass { mm } + { \exsheets_declare_question_class:nn {#1} {#2} } +\@onlypreamble \DeclareQuestionClass + +% #1: class name +\cs_new:Npn \exsheets_get_question_class:n #1 + { + \cs_if_exist:cT { l__exsheets_questions_#1_tl } + { \tl_use:c { l__exsheets_questions_#1_tl } } + } + +% #1: class name +\DeclareExpandableDocumentCommand \GetQuestionClass { m } + { \exsheets_get_question_class:n {#1} } + +% #1: class name +\prg_new_conditional:Npnn \exsheets_if_question_class:n #1 {T,F,TF} + { + \tl_if_blank:fTF { \exsheets_get_question_class:n {#1} } + { \prg_return_false: } + { \prg_return_true: } + } +\cs_generate_variant:Nn \tl_if_blank:nTF {f} + +% #1: class name +\cs_new_protected:Npn \exsheets_print_question_class:nTF #1#2#3 + { + \exsheets_if_question_class:nTF {#1} + { + \cs_set_protected:Npn \__exsheets_print_question_class:n ##1 {#2} + \__exsheets_print_question_class:n + { \exsheets_get_question_class:n {#1} } + } + {#3} + } + +\NewDocumentCommand \PrintQuestionClassTF { mmm } + { \exsheets_print_question_class:nTF {#1} {#2} {#3} } +\NewDocumentCommand \PrintQuestionClassT { mm } + { \exsheets_print_question_class:nTF {#1} {#2} { } } +\NewDocumentCommand \PrintQuestionClassF { mm } + { \exsheets_print_question_class:nTF {#1} { } {#2} } + +% ---------------------------------------------------------------------------- +% question tags: +% #1: ID +% #2: tags +\cs_new_protected:Npn \exsheets_set_question_tags:nn #1#2 + { \prop_gput:Nnn \g__exsheets_tags_prop {#1} {#2} } +\cs_generate_variant:Nn \exsheets_set_question_tags:nn {V} + +\cs_new_protected:Npn \exsheets_set_this_question_tags:n #1 + { \exsheets_set_question_tags:Vn \g__exsheets_questions_current_id_tl {#1} } + +\keys_define:nn {exsheets} + { + use-tags .code:n = \seq_set_split:Nnn \l__exsheets_use_tags_seq {,} {#1} , + question / tags .code:n = + \exsheets_after_begin_question:n { \exsheets_set_this_question_tags:n {#1} } + } + +% #1: ID +\prg_new_protected_conditional:Npnn \exsheets_check_question_tags:n #1 {T,F,TF} + { + \bool_set_false:N \l__exsheets_tmpa_bool + \seq_if_empty:NTF \l__exsheets_use_tags_seq + { \bool_set_true:N \l__exsheets_tmpa_bool } + { + \prop_get:NnN \g__exsheets_tags_prop {#1} \l__exsheets_tmpa_tl + \seq_map_inline:Nn \l__exsheets_use_tags_seq + { + \tl_if_in:NnT \l__exsheets_tmpa_tl {##1} + { + \bool_set_true:N \l__exsheets_tmpa_bool + \seq_map_break: + } + } + } + \bool_if:NTF \l__exsheets_tmpa_bool + { \prg_return_true: } + { \prg_return_false: } + } +\cs_generate_variant:Nn \exsheets_check_question_tags:nF {V} + +% ---------------------------------------------------------------------------- +% die 'question' Umgebung +\cs_new:Npn \IfInsideQuestionTF + { \bool_if:NTF \l__exsheets_inside_question_bool } +\cs_new:Npn \IfInsideQuestionT + { \bool_if:NT \l__exsheets_inside_question_bool } +\cs_new:Npn \IfInsideQuestionF + { \bool_if:NF \l__exsheets_inside_question_bool } + +\cs_new_eq:NN \exsheets_par: \par + +\cs_new_protected:Npn \exsheets_after_begin_question:n #1 + { \tl_put_right:Nn \l__exsheets_after_begin_question_tl {#1} } + +\cs_new_protected:Npn \exsheets_add_space:N #1 + { + \bool_if:nF + { + % \l__exsheets_heading_runin_bool || + \l__exsheets_heading_inline_bool || + \l__exsheets_no_skip_after_bool + } + { + \exsheets_par: + \dim_compare:nNnT { \parskip } = { 0pt } + { \exsheets_glue:N #1 } + } + } + +% #1: pre question hook +% #2: post question hook +\NewEnviron { __exsheets_questions_internal: } [2] + { + \__exsheets_start_question_if_used:n {#1} + \bool_if:nT + { + % \l__exsheets_questions_print_bool && + \g__exsheets_questions_use_bool && + !\l__exsheets_questions_deactivate_bool + } + { + \exsheets_if_current_question_is_used:T + { + % label: + \tl_if_blank:VTF \l__exsheets_questions_label_tl + { + \bool_if:NT \l__exsheets_auto_label_bool + { + \exsheets_label:V \g__exsheets_questions_current_id_tl + \exsheets_set_ref_properties:V \CurrentQuestionID + } + } + { + \exsheets_label:V \l__exsheets_questions_label_tl + \exsheets_set_ref_properties:V \l__exsheets_questions_label_tl + } + \__exsheets_save_number_in:N \g_exsheets_question_identification_prop + % TODO: don't print, only save if \l__exsheets_questions_print_bool is false + \__exsheets_save_and_print_question_body:VVV + \BODY + \l__exsheets_questions_pre_body_hook_tl + \l__exsheets_questions_post_body_hook_tl + \exsheets_set_question_properties:x + { + \tl_if_blank:VF \l__exsheets_questions_subtitle_tl + { subtitle = { \exp_not:V \l__exsheets_questions_subtitle_tl } , } + counter = \l__exsheets_qu_counter_interpretation_tl , + % number = \int_to_arabic:V \g__exsheets_questions_id_int , + \bool_if:NF \l__exsheets_points_questions_default_bool + { + \fp_compare:nT { \g__exsheets_this_question_points_fp > 0 } + { points = \fp_to_decimal:N \g__exsheets_this_question_points_fp , } + \fp_compare:nT { \g__exsheets_this_question_bonus_fp > 0 } + { bonus-points = \fp_to_decimal:N \g__exsheets_this_question_bonus_fp } + } + } + \bool_if:NT \l__exsheets_questions_print_bool {#2} + } + } + } + +% #1: body +% #2: pre body hook +% #3: post body hook +\cs_new_protected:Npn \__exsheets_save_and_print_question_body:nnn #1#2#3 + { + \group_begin: + \bool_if:NF \l__exsheets_save_question_body_to_aux_bool + { \@fileswfalse } + \exsheets_set_question_properties:n { question-body = {#1} } + \group_end: + \bool_if:NT \l__exsheets_questions_print_bool + { + #2 { #1 } #3 + \exsheets_add_space:N \l__exsheets_questions_skip_below_dim + } + } +\cs_generate_variant:Nn \__exsheets_save_and_print_question_body:nnn { VVV } + +\prg_new_conditional:Npnn \exsheets_if_question_subtitle: { p,T,F,TF } + { + \tl_if_blank:VTF \l__exsheets_questions_subtitle_tl + { \prg_return_false: } + { \prg_return_true: } + } + +\cs_new:Npn \IfQuestionSubtitleTF { \exsheets_if_question_subtitle:TF } +\cs_new:Npn \IfQuestionSubtitleT { \exsheets_if_question_subtitle:T } +\cs_new:Npn \IfQuestionSubtitleF { \exsheets_if_question_subtitle:F } + +\cs_new_protected:Npn \__exsheets_read_points:w #1 ! #2 ! #3 \q_stop + { + \tl_if_blank:nTF {#1} + { + \bool_set_true:N \l__exsheets_only_print_points_bool + \tl_set:Nn \l__exsheets_questions_points_tl {#2} + } + { + \bool_set_false:N \l__exsheets_only_print_points_bool + \__exsheets_read_points_aux:w #1++ \q_stop + } + } + +\cs_new_protected:Npn \__exsheets_read_points_aux:w #1+#2+#3 \q_stop + { + \tl_if_blank:nTF {#1} + { \fp_zero:N \l__exsheets_question_points_fp } + { \fp_set:Nn \l__exsheets_question_points_fp {#1} } + \tl_if_blank:nTF {#2} + { \fp_zero:N \l__exsheets_question_bonus_fp } + { + \tl_if_blank:nTF {#3} + { \fp_zero:N \l__exsheets_question_bonus_fp } + { \fp_set:Nn \l__exsheets_question_bonus_fp {#2} } + } + } +\cs_new_protected:Npn \__exsheets_read_points:n #1 + { + \bool_if:NTF \l__exsheets_parse_points_bool + { \__exsheets_read_points:w #1!! \q_stop } + { \tl_set:Nn \l__exsheets_questions_points_tl {#1} } + } + +\cs_new:Npn \exsheets_label_format:n #1 { qu:#1 } +\cs_new:Npn \__exsheets_label:n { \label } +\cs_new:Npn \exsheets_label:n { } +\cs_generate_variant:Nn \exsheets_label:n { V } +\cs_new:Npn \__exsheets_ref:n { \ref } +\cs_new:Npn \exsheets_ref:n { } +\cs_new:Npn \__exsheets_pageref:n { \pageref } +\cs_new:Npn \exsheets_pageref:n { } + +\cs_new_protected:Npn \exsheets_update_referencing_command:NN #1#2 + { + \cs_set:Npx #1 ##1 + { \exp_not:o {#2} { \exsheets_label_format:n {##1} } } + } + +\cs_new_protected:Npn \exsheets_update_referencing_commands: + { + \exsheets_update_referencing_command:NN \exsheets_label:n \__exsheets_label:n + \exsheets_update_referencing_command:NN \exsheets_ref:n \__exsheets_ref:n + \exsheets_update_referencing_command:NN \exsheets_pageref:n \__exsheets_pageref:n + } + +\cs_new_protected:Npn \exsheets_set_ref_properties:n #1 + { + \exsheets_set_question_properties:x + { + ref = \exp_not:o { \exsheets_ref:n {#1} } , + pageref = \exp_not:o { \exsheets_pageref:n {#1} } + } + } +\cs_generate_variant:Nn \exsheets_set_ref_properties:n { V } + +\exsheets_update_referencing_commands: + +\cs_new_protected:Npn \__exsheets_determine_question_usage: + { + \tl_gclear:N \g__exsheets_use_current_question_tl + \prop_map_inline:Nn \l__exsheets_class_prop + { + \use:c { __exsheets_questions_use_##1: } + \bool_if:nTF + { + ( + \l__exsheets_use_this_question_bool + && + \bool_if_p:c { l__exsheets_##2_active_bool } + ) + || + ! \bool_if_p:c { g__exsheets_use_##1_bool } + } + { \tl_gput_right:Nn \g__exsheets_use_current_question_tl { y } } + { \tl_gput_right:Nn \g__exsheets_use_current_question_tl { n } } + } + } + +\prg_new_protected_conditional:Npnn \exsheets_if_current_question_is_used: { T,F,TF } + { + \tl_if_in:NnTF \g__exsheets_use_current_question_tl { n } + { \prg_return_false: } + { \prg_return_true: } + } + +% #1: options +\cs_new_protected:Npn \__exsheets_question_start:n #1 + { + \bool_set_true:N \l__exsheets_inside_question_bool + \bool_if:NT \l__exsheets_questions_use_bool + { \bool_gset_true:N \g__exsheets_questions_use_bool } + % Optionen: + \tl_if_blank:nF {#1} { \keys_set:nn { exsheets / question } {#1} } + % ID: + \__exsheets_determine_question_usage: + \bool_if:nT + { + (\l__exsheets_questions_deactivate_bool && \l__exsheets_select_questions_bool) + || + !\l__exsheets_select_questions_bool + } + { + \int_gincr:N \g__exsheets_questions_id_int + \tl_if_blank:VTF \l__exsheets_questions_id_tl + { + \tl_gset:Nx \g__exsheets_questions_current_id_tl + { \int_use:N \g__exsheets_questions_id_int } + } + { + \tl_gset:Nx \g__exsheets_questions_current_id_tl + { \tl_use:N \l__exsheets_questions_id_tl } + } + } + \tl_use:N \l__exsheets_after_begin_question_tl + \tl_clear:N \l__exsheets_after_begin_question_tl + } + +% #1: points or blank +\cs_new_protected:Npn \__exsheets_question_points:n #1 + { + % Punktevergabe: + \fp_gzero:N \g__exsheets_this_question_points_fp + \fp_gzero:N \g__exsheets_this_question_bonus_fp + \tl_if_blank:nTF {#1} + { + \__exsheets_read_points:n { 0 } + \bool_if:NT \l__exsheets_points_questions_default_bool + { + \fp_set_eq:NN + \l__exsheets_question_points_fp + \l__exsheets_points_default_fp + % check if moving this to a later point has negative effects... + % \exsheets_set_question_properties:x + % { points = \fp_to_tl:N \l__exsheets_points_default_fp } + } + } + { + \fp_gset_eq:NN + \g__exsheets_this_question_points_fp + \l__exsheets_question_points_fp + \fp_gset_eq:NN + \g__exsheets_this_question_bonus_fp + \l__exsheets_question_bonus_fp + \__exsheets_read_points:n {#1} + % check if moving this to a later point has negative effects... + % \exsheets_set_question_properties:n { points = #2 } + } + } + +% #1: pre question hook +\cs_new_protected:Npn \__exsheets_start_question_if_used:n #1 + { + \tl_if_blank:VT \l__exsheets_question_heading_instance_tl + { + \tl_set_eq:NN + \l__exsheets_question_heading_instance_tl + \l__exsheets_heading_instance_tl + } + % Auswahl der Frage: + \__exsheets_select_question:V \g__exsheets_questions_current_id_tl + \prop_map_inline:Nn \l__exsheets_class_prop + { \use:c { __exsheets_questions_use_##1: } } + \exsheets_check_question_tags:VF \g__exsheets_questions_current_id_tl + { \bool_gset_false:N \g__exsheets_questions_use_bool } + \bool_if:nT + { + \g__exsheets_questions_use_bool && + !\l__exsheets_questions_deactivate_bool + } + { + \exsheets_if_current_question_is_used:T + { \refstepcounter {question} } + \__exsheets_get_sectioning_numbers: + \bool_if:nT + { + ( + \l__exsheets_points_questions_default_bool && + \l__exsheets_parse_points_bool + ) || + ( + \l__exsheets_parse_points_bool% && + % \l__exsheets_questions_print_bool + ) + } + { + \exsheets_if_current_question_is_used:T + { + \exsheets_add_points:V \l__exsheets_question_points_fp + \exsheets_add_bonus:V \l__exsheets_question_bonus_fp + } + } + \tl_if_blank:VTF \l__exsheets_questions_id_tl + { + \tl_set:Nx \l__exsheets_tmpa_tl + { \int_use:N \g__exsheets_questions_id_int } + } + { + \tl_set_eq:NN + \l__exsheets_tmpa_tl + \l__exsheets_questions_id_tl + } + \tl_set_eq:NN \CurrentQuestionID \l__exsheets_tmpa_tl + \bool_if:NT \l__exsheets_questions_print_bool + { + \bool_if:NTF \l__exsheets_exam_bool + { + \tl_set_eq:NN + \l__exsheets_questions_title_tl + \l__exsheets_questions_name_tl + } + { + \tl_set_eq:NN + \l__exsheets_questions_title_tl + \l__exsheets_exercise_name_tl + } + \bool_if:nTF + { \l__exsheets_parse_points_bool && !\l__exsheets_only_print_points_bool } + { + #1 + \exsheets_use_heading:VVVVnV + \l__exsheets_question_heading_instance_tl + \l__exsheets_questions_title_tl + \l__exsheets_qu_counter_interpretation_tl + \l__exsheets_question_points_fp + { \l__exsheets_question_bonus_fp } + \l__exsheets_tmpa_tl + } + { + \bool_if:NT \l__exsheets_only_print_points_bool + { \bool_set_false:N \l__exsheets_parse_points_bool } + % might be dangerous to expand here... + \tl_if_blank:xTF { \l__exsheets_questions_points_tl } + { + #1 + \exsheets_use_heading:VVVnnV + \l__exsheets_question_heading_instance_tl + \l__exsheets_questions_title_tl + \l__exsheets_qu_counter_interpretation_tl + {0} + {0} + \l__exsheets_tmpa_tl + } + { + #1 + \exsheets_use_heading:VVVVnV + \l__exsheets_question_heading_instance_tl + \l__exsheets_questions_title_tl + \l__exsheets_qu_counter_interpretation_tl + \l__exsheets_questions_points_tl + {0} + \l__exsheets_tmpa_tl + } + } + } + } + } +\cs_generate_variant:Nn \__exsheets_start_question_if_used:n {V} + +\newenvironment { __exsheets_question: } [2] + { + \__exsheets_question_start:n {#1} + \__exsheets_question_points:n {#2} + \exp_args:NVV \__exsheets_questions_internal: + \l__exsheets_questions_pre_hook_tl + \l__exsheets_questions_post_hook_tl + } + { + \end__exsheets_questions_internal: + } + +% current question number: +\cs_new_protected:Npn \exsheets@save@number #1#2 + { \expandafter\global\expandafter\edef\csname exsheets@question@#1\endcsname{#2} } + +\cs_new_protected:Npn \__exsheets_save_number_in_aux_x:Nnn #1#2#3 + { + \prop_gput:Nfx #1 {#2} {#3} + \exsheets_write_to_aux_x:n { \exsheets@save@number {#2} {#3} } + } + +\cs_new_protected:Npn \__exsheets_save_number_in:N #1 + { + \bool_if:NTF \l__exsheets_print_number_bool + { + \cs_if_exist:NTF \thechapter + { + \__exsheets_save_number_in_aux_x:Nnn #1 + { \int_use:N \g__exsheets_questions_id_int } + { \arabic{chapter}-\arabic{section}-\arabic{question} } + } + { + \__exsheets_save_number_in_aux_x:Nnn #1 + { \int_use:N \g__exsheets_questions_id_int } + { -\arabic{section}-\arabic{question} } + } + } + { + \cs_if_exist:NTF \thechapter + { + \__exsheets_save_number_in_aux_x:Nnn #1 + { \int_use:N \g__exsheets_questions_id_int } + { @@@\arabic{chapter}-\arabic{section}-\arabic{question} } + } + { + \__exsheets_save_number_in_aux_x:Nnn #1 + { \int_use:N \g__exsheets_questions_id_int } + { @@@-\arabic{section}-\arabic{question} } + } + } + } + +% #1: prop +% #2: id +% #3: code +\cs_new_protected:Npn \__exsheets_restore_number_from_and_do:Nnn #1#2#3 + { + \prop_get:NnNT #1 {#2} \l__exsheets_tmpc_tl + { + \exp_after:wN + \__exsheets_read_number:w \l__exsheets_tmpc_tl \q_stop + #3 + } + % use \exsheets_read_counter_settings:V \l__exsheets_qu_counter_format_tl + % afterwards to print the number + } +\cs_generate_variant:Nn \__exsheets_restore_number_from_and_do:Nnn { NV } + +\DeclareExpandableDocumentCommand \QuestionNumber {m} + { \exsheets_question_number:n {#1} } + +\cs_new:Npn \exsheets_question_number:n #1 + { \exsheets_get_question_property:nn {counter} {#1} } + +% \cs_new_protected:Npn \__exsheets_question_number:N #1 +% { +% \cs_if_exist:NTF #1 +% { +% \exp_after:wN \__exsheets_get_question_number:w #1 \q_stop +% \ReadCounterPatternFrom [exsheets] \l__exsheets_qu_counter_pattern_tl +% } +% { \textbf {??} } +% } +% \cs_generate_variant:Nn \__exsheets_question_number:N { c } + +% \cs_new_protected:Npn \__exsheets_get_question_number:w #1-#2-#3 \q_stop +% { +% \cs_if_exist:NT \thechapter +% { \int_set:Nn \l__exsheets_counter_ch_int {#1} } +% \int_set:Nn \l__exsheets_counter_sec_int {#2} +% \int_set:Nn \l_exsheets_counter_qu_int {#3} +% } + +% map ID's to number of used questions +\cs_new_protected:Npn \exsheets@used@id #1#2 + { \prop_gput:Nnn \g__exsheets_questions_used_prop {#1} {#2} } + +\cs_new_protected:Npn \__exsheets_mark_as_used:n #1 + { + \int_gincr:N \g__exsheets_questions_used_int + \prop_gput_if_new:Nxx \g__exsheets_questions_used_prop + {#1} + { \int_use:N \g__exsheets_questions_used_int } + \exsheets_write_to_aux_x:n + { \exsheets@used@id {#1} { \int_use:N \g__exsheets_questions_used_int } } + } + +% ---------------------------------------------------------------------------- +% title of a question: +\cs_if_exist:NF \exsheets_headings_files_loaded: + { + \file_input:n {exsheets_headings.def} + \file_input:n {exsheets_headings.cfg} + } + +% #1: instance +% #2: title +% #3: number +% #4: points +% #5: bonus +% #6: id +\cs_new_protected:Npn \exsheets_use_heading:nnnnnn #1#2#3#4#5#6 + { + \IfInstanceExistTF {exsheets-heading} {#1} + { \UseInstance {exsheets-heading} {#1} } + { + \msg_warning:nnx {exsheets} {headings} {#1} + \UseInstance {exsheets-heading} {block} + } + {#2} {#3} {#4} {#5} {#6} + } +\cs_generate_variant:Nn \exsheets_use_heading:nnnnnn { V , VVVnnV , VVVVnV } + +\NewDocumentCommand \ExSheetsHeading { mmmmmm } + { \exsheets_use_heading:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} } + +% options for the questions: +\keys_define:nn { exsheets / question } + { + type .choice: , + type / exam .code:n = + \bool_set_true:N \l__exsheets_exam_bool , + type / exercise .code:n = + \bool_set_false:N \l__exsheets_exam_bool , + name .code:n = + \tl_set:Nn \l__exsheets_exercise_name_tl {#1} + \tl_set:Nn \l__exsheets_questions_name_tl {#1} , + headings .tl_set:N = \l__exsheets_question_heading_instance_tl , + subtitle .tl_set:N = \l__exsheets_questions_subtitle_tl , + print .bool_set:N = \l__exsheets_questions_print_bool , + print .default:n = true , + ID .tl_set:N = \l__exsheets_questions_id_tl , + label .tl_set:N = \l__exsheets_questions_label_tl , + use .choice: , + use / true .code:n = + \bool_gset_true:N \g__exsheets_questions_use_bool + \bool_set_true:N \l__exsheets_questions_use_bool , + use / false .code:n = + \bool_gset_false:N \g__exsheets_questions_use_bool + \bool_set_false:N \l__exsheets_questions_use_bool , + use .default:n = true , + skip-below .dim_set:N = \l__exsheets_questions_skip_below_dim , + no-skip-below .bool_set:N = \l__exsheets_no_skip_after_bool , + pre-hook .tl_set:N = \l__exsheets_questions_pre_hook_tl , + post-hook .tl_set:N = \l__exsheets_questions_post_hook_tl , + pre-body-hook .tl_set:N = \l__exsheets_questions_pre_body_hook_tl , + post-body-hook .tl_set:N = \l__exsheets_questions_post_body_hook_tl , + save-to-aux .bool_set:N = \l__exsheets_save_question_body_to_aux_bool + } + +% ---------------------------------------------------------------------------- +% using ``metadata'': +\cs_new_protected:Npn \exsheets_declare_question_property:n #1 + { + \prop_new:c { g__exsheets_question_property_#1_prop } + \keys_define:nn { question / meta } + { #1 .code:n = \__exsheets_question_set_property:nn {#1} {##1} } + } + +\NewDocumentCommand \DeclareQuestionProperty { m } + { \exsheets_declare_question_property:n {#1} } +\@onlypreamble \DeclareQuestionProperty + +\cs_new_protected:Npn \exsheets_set_question_properties:n #1 + { + \@bsphack + \bool_if:NTF \l__exsheets_inside_question_bool + { \keys_set:nn { question / meta } {#1} } + { \msg_error:nnn {exsheets} {only-inside-question} {\SetQuestionProperties} } + \@esphack + } +\cs_generate_variant:Nn \exsheets_set_question_properties:n { x } + +% #1: property +% #2: ID +\prg_new_conditional:Npnn \exsheets_if_question_property:nn #1#2 {T,F,TF} + { + \prop_if_in:cnTF { g__exsheets_question_property_#1_prop } {#2} + { \prg_return_true: } + { \prg_return_false: } + } +\DeclareExpandableDocumentCommand \IfQuestionPropertyTF { } + { \exsheets_if_question_property:nnTF } +\DeclareExpandableDocumentCommand \IfQuestionPropertyT { } + { \exsheets_if_question_property:nnT } +\DeclareExpandableDocumentCommand \IfQuestionPropertyF { } + { \exsheets_if_question_property:nnF } + +\NewDocumentCommand \SetQuestionProperties { +m } + { \exsheets_set_question_properties:n {#1} } + +% #1: ID +% #2: property +% #3: value +\cs_new_protected:Npn \exsheets@question@property #1#2#3 + { + \prop_gput:cnn { g__exsheets_question_property_#2_prop } + {#1} {#3} + } + +% #1: property +% #2: value +\cs_new_protected:Npn \__exsheets_question_set_property:nn #1#2 + { + \prop_gput:cVn { g__exsheets_question_property_#1_prop } + \CurrentQuestionID {#2} + % watch if this has negativ effects: + \exsheets_write_to_aux_x:n + { + \exp_not:N \exsheets@question@property + { \CurrentQuestionID } + { \exp_not:n {#1} } + { \exp_not:n {#2} } + } + } + +% #1: property +% #2: ID +\DeclareExpandableDocumentCommand \GetQuestionProperty { mm } + { \exsheets_get_question_property:no {#1} {#2} } + +\cs_new:Npn \exsheets_get_question_property:nn #1#2 + { + \prop_if_in:cnTF { g__exsheets_question_property_#1_prop } {#2} + { \prop_item:cn { g__exsheets_question_property_#1_prop } {#2} } + { ?? } + } +\cs_generate_variant:Nn \exsheets_get_question_property:nn { no , nV } + +\cs_new_protected:Npn \exsheets_for_each_question_do:n #1 + { + \int_gzero:N \g__exsheets_tmpa_int + \prop_map_inline:Nn \g__exsheets_questions_used_prop + { \int_gincr:N \g__exsheets_tmpa_int #1 } + } + +\NewDocumentCommand \ForEachQuestion {m} + { \exsheets_for_each_question_do:n {#1} } + +\cs_new:Npn \iflastquestion + { + \int_compare:nTF + { \numberofquestions = \g__exsheets_tmpa_int } + } + +\cs_if_exist:NF \numberofquestions + { + \cs_new:Npn \numberofquestions + { \int_to_arabic:V \g__exsheets_questions_used_int } + } + +% ---------------------------------------------------------------------------- +% debug-Info: +\RequirePackage {xcolor} +\colorlet {exsheetsdebugcolor} {yellow} + +\keys_define:nn {exsheets} + { + debug .bool_set:N = \l__exsheets_questions_debug_bool + } + +\cs_new_protected:Npn \exsheets_debug_box:nn #1#2 + { + \par + \noindent + \group_begin: + \normalfont\normalsize\normalcolor + \colorbox {exsheetsdebugcolor} + { \parbox { \dim_eval:n { #1 - 2 \fboxsep } } {#2} } + \group_end: + \par + } + +\cs_new:Npn \__exsheets_list_comma: {} + +\cs_new_protected:Npn \exsheets_questions_debug:n #1 + { + \bool_if:nT + { \l__exsheets_questions_debug_bool && \l__exsheets_inside_question_bool } + { + \exsheets_debug_box:nn { \linewidth } + { + \textbf {ID} :~ \textit {#1} + \prop_map_inline:Nn \l__exsheets_class_prop + { + \bool_if:cT { l__exsheets_questions_##2_bool } + { + ;~ \textbf {##2} :~ + \textit { \tl_use:c { l__exsheets_questions_##2_tl } } + } + } + \prop_get:NnN \g__exsheets_tags_prop + {#1} + \l__exsheets_tmpa_tl + \quark_if_no_value:VTF \l__exsheets_tmpa_tl + { ;~ \textbf {not~tagged} } + { + ;~ \textbf {tags} : ~ + \seq_set_split:NnV \l__exsheets_tmpa_seq + {,} + \l__exsheets_tmpa_tl + \textit { \seq_use:Nn \l__exsheets_tmpa_seq {,~} } + } + } + } + } + +\exsheets_deprecate_cs:Npnn \DebugExSheets #1 + {the~ option~ debug} + { \keys_set:nn {exsheets} { debug = #1 } } + +% ---------------------------------------------------------------------------- +% include random/selected questions from a file: +\cs_new_protected:Npn \exsheets_file_input_if_exist:n #1 + { \file_if_exist:nT {#1} { \file_input:n {#1} } } +\cs_new_protected:Npn \exsheets_file_input_if_exist:nF #1#2 + { \file_if_exist:nTF {#1} { \file_input:n {#1} } {#2} } + +\cs_new_protected:Npn \exsheets_prop_count:N #1 + { + \__exsheets_prop_count:NN #1 \l__exsheets_tmpa_int + \int_use:N \l__exsheets_tmpa_int + } + +\cs_new_protected:Npn \__exsheets_prop_count:NN #1#2 + { + \int_zero:N #2 + \prop_map_inline:Nn #1 + { \int_incr:N #2 } + } + +\NewDocumentCommand \includequestions { om } + { + \group_begin: + \IfNoValueF {#1} + { \keys_set:nn { exsheets / include } {#1} } + \exsheets_include_questions:n {#2} + \group_end: + } + +\cs_new_protected:Npn \exsheets_include_questions:n #1 + { + \bool_set_true:N \l__exsheets_select_questions_bool + \clist_gclear:N \questionsincludedlast + \seq_set_split:Nnn \l__exsheets_tmpa_seq { , } {#1} + \seq_map_inline:Nn \l__exsheets_tmpa_seq + { + \bool_set_true:N \l__exsheets_questions_deactivate_bool + \int_set_eq:NN + \l__exsheets_questions_set_int + \g__exsheets_questions_used_int + \int_set_eq:NN + \l__exsheets_tmpc_int + \g__exsheets_questions_id_int + \int_gzero:N \g__exsheets_select_random_int + \exsheets_file_input_if_exist:nF {##1} + { \msg_error:nnn {exsheets} {file-not-found} {##1} } + \__exsheets_prop_count:NN + \g__exsheets_included_questions_prop + \l__exsheets_tmpa_int + \bool_if:NT \l__exsheets_questions_debug_bool + { + \exsheets_debug_box:nn + { \linewidth } + { + The~file~ ` \texttt { \tl_to_str:n {##1} } ' ~contains~ + \exsheets_prop_count:N \g__exsheets_included_questions_prop + \c_space_tl questions~with~the~following~IDs:\par + \cs_set_protected:Npn \__exsheets_list_comma: + { \cs_set:Npn \__exsheets_list_comma: { ,~ } } + \prop_map_inline:Nn \g__exsheets_included_questions_prop + { \__exsheets_list_comma: ####2 } + } + } + \bool_set_false:N \l__exsheets_questions_deactivate_bool + \int_set_eq:NN \l__exsheets_tmpd_int \g__exsheets_questions_id_int + \int_gset_eq:NN \g__exsheets_questions_id_int \l__exsheets_tmpc_int + \bool_if:NT \l__exsheets_include_questions_no_duplicates_bool + { + \seq_map_inline:Nn \g_exsheets_included_questions_seq + { \clist_put_right:Nn \l__exsheets_exclude_id_clist {####1} } + } + \__exsheets_select_question_random:n {##1} + \exsheets_file_input_if_exist:n {##1} + \int_gset_eq:NN \g__exsheets_questions_id_int \l__exsheets_tmpd_int + \prop_gclear:N \g__exsheets_included_questions_prop + \clist_clear:N \l__exsheets_include_id_clist + \clist_clear:N \l__exsheets_exclude_id_clist + \int_gzero:N \g__exsheets_selection_number_int + % \seq_show:N \g_exsheets_included_questions_seq + } + \bool_set_false:N \l__exsheets_select_questions_bool + } + +% options: +% - IDs=<list of IDs> +% - all=true|false % default when no option is given +% - random=<num> +% - exclude=<list of IDs> +\keys_define:nn { exsheets / include } + { + all .bool_set:N = \l__exsheets_include_all_bool , + IDs .code:n = + \bool_set_false:N \l__exsheets_include_all_bool + \bool_set_false:N \l__exsheets_include_random_bool + \bool_set_true:N \l__exsheets_include_by_id_bool + \clist_set:Nn \l__exsheets_include_id_clist {#1} , + % the `exclude' option does _not_ set \l__exsheets_include_random_bool , + % \l__exsheets_include_by_id_bool or \l__exsheets_include_all_bool so + % it can be combined with the other options: + exclude .clist_set:N = \l__exsheets_exclude_id_clist , + random .code:n = + \bool_set_false:N \l__exsheets_include_all_bool + \bool_set_true:N \l__exsheets_include_random_bool + \bool_set_false:N \l__exsheets_include_by_id_bool + \int_set:Nn \l__exsheets_include_random_int {#1} , + no-duplicates .bool_set:N = \l__exsheets_include_questions_no_duplicates_bool + } + +\cs_new_protected:Npn \__exsheets_select_question:n #1 + { + \bool_if:NTF \l__exsheets_select_questions_bool + { + \bool_if:NTF \l__exsheets_questions_deactivate_bool + { + \bool_if:NT \l__exsheets_questions_use_bool + { + \int_gincr:N \g__exsheets_selection_number_int + \bool_if:NTF \l__exsheets_include_random_bool + { + \prop_gput:Nxn \g__exsheets_included_questions_prop + { \int_use:N \g__exsheets_selection_number_int } {#1} + } + { + \prop_gput:Nxn \g__exsheets_included_questions_prop + { \int_use:N \g__exsheets_questions_id_int } {#1} + } + } + } + { + \int_gincr:N \g__exsheets_questions_id_int + \bool_if:NTF \l__exsheets_include_random_bool + { + \int_gincr:N \g__exsheets_select_random_int + \int_set_eq:NN \l__exsheets_tmpa_int \g__exsheets_select_random_int +% ID: \int_use:N \g__exsheets_questions_id_int ,~ +% set: \int_use:N \l__exsheets_questions_set_int ,~ +% selection: \int_use:N \g__exsheets_selection_number_int ,~ +% tmpa: \int_use:N \l__exsheets_tmpa_int \par + } + { + \int_set_eq:NN + \l__exsheets_tmpa_int + \g__exsheets_questions_id_int + } + \prop_get:NxN \g__exsheets_included_questions_prop + { \int_use:N \l__exsheets_tmpa_int } + \l__exsheets_tmpa_tl + \__exsheets_select_question_by_id:V \l__exsheets_tmpa_tl + } + } + { + \__exsheets_use_question:n {#1} + } + } +\cs_generate_variant:Nn \__exsheets_select_question:n { V } + +\cs_new_protected:Npn \__exsheets_select_question_by_id:n #1 + { + \bool_if:NTF \l__exsheets_include_all_bool + {% parsing list of excluded IDs + \clist_if_in:NnTF + \l__exsheets_exclude_id_clist + {#1} + { \bool_gset_false:N \g__exsheets_questions_use_bool } + { + \bool_gset_true:N \g__exsheets_questions_use_bool + \clist_gput_right:Nn \questionsincludedlast {#1} + \seq_gput_right:Nn \g_exsheets_included_questions_seq {#1} + \__exsheets_use_question:n {#1} + } + } + {% parsing list of included IDs + \clist_if_in:NnTF + \l__exsheets_include_id_clist + {#1} + { + \clist_if_in:NnTF + \l__exsheets_exclude_id_clist + {#1} + { \bool_gset_false:N \g__exsheets_questions_use_bool } + { + \bool_gset_true:N \g__exsheets_questions_use_bool + \clist_gput_right:Nn \questionsincludedlast {#1} + \seq_gput_right:Nn \g_exsheets_included_questions_seq {#1} + \__exsheets_use_question:n {#1} + % \exsheets_if_current_question_is_used:T + % { \__exsheets_mark_as_used:n {#1} } + % \prop_gput:NnV \g__exsheets_questions_id_prop + % {#1} + % \g__exsheets_questions_id_int + } + } + { \bool_gset_false:N \g__exsheets_questions_use_bool } + } + } +\cs_generate_variant:Nn \__exsheets_select_question_by_id:n { V } + +\cs_new_protected:Npn \__exsheets_use_question:n #1 + { + \exsheets_if_current_question_is_used:T + { \__exsheets_mark_as_used:n {#1} } + \prop_gput:NnV \g__exsheets_questions_id_prop + {#1} + \g__exsheets_questions_id_int + } + +% TODO: poor efficiency -- there should be no need to map through +% \l__exsheets_class_prop *two* times +\cs_new_protected:Npn \__exsheets_select_question_random:n #1 + { + \bool_if:NT \l__exsheets_include_random_bool + { + % number of question in file: + \__exsheets_prop_count:NN + \g__exsheets_included_questions_prop + \l__exsheets_tmpa_int + % number of selectable questions in file: + \int_zero:N \l__exsheets_tmpb_int + \prop_map_inline:Nn \g__exsheets_included_questions_prop + { + \prop_map_inline:Nn \l__exsheets_class_prop + { + \bool_if:cT { g__exsheets_use_####1_bool } + { + \bool_set_true:N \l__exsheets_use_selection_bool + \prop_get:cnNT { g__exsheets_questions_####2_prop } {##1} + \l__exsheets_tmpa_tl + { + \prop_if_in:cVT { g__exsheets_####1_active_prop } + \l__exsheets_tmpa_tl + { \int_incr:N \l__exsheets_tmpb_int } + } + } + } + } + \int_compare:nTF { \l__exsheets_include_random_int >= \l__exsheets_tmpa_int } + { + % not enough questions available: + \msg_warning:nnxxx {exsheets} {random-file} + { \int_use:N \l__exsheets_include_random_int } + {#1} + { \int_use:N \l__exsheets_tmpa_int } + \bool_set_true:N \l__exsheets_include_all_bool + } + { + \bool_if:nTF + { + \int_compare_p:n + { \l__exsheets_include_random_int >= \l__exsheets_tmpb_int } + && + \l__exsheets_use_selection_bool + } + { + % not enough questions selectable: + \msg_warning:nnxxxx {exsheets} {random-selectable} + { \int_use:N \l__exsheets_include_random_int } + {#1} + { \int_use:N \l__exsheets_tmpa_int } + { \int_use:N \l__exsheets_tmpb_int } + \bool_set_true:N \l__exsheets_include_all_bool + } + { + \int_zero:N \l__exsheets_tmpb_int + \int_do_while:nn + { \l__exsheets_tmpb_int < \l__exsheets_include_random_int } + { + \pgfmathparse { random(\int_use:N \l__exsheets_tmpa_int) } + \tl_set_eq:NN \l__exsheets_tmpa_tl \pgfmathresult + \prop_get:NVN \g__exsheets_included_questions_prop + \l__exsheets_tmpa_tl + \l__exsheets_tmpb_tl + \clist_if_in:NVF \l__exsheets_include_id_clist \l__exsheets_tmpb_tl + { + \tl_clear:N \l__exsheets_include_id_tl + \prop_map_inline:Nn \l__exsheets_class_prop + { + \prop_get:cVNT { g__exsheets_questions_##2_prop } + \l__exsheets_tmpa_tl \l__exsheets_tmpc_tl + { + \bool_if:cT { g__exsheets_use_##1_bool } + { + \prop_if_in:cVTF { g__exsheets_##1_active_prop } + \l__exsheets_tmpc_tl + { \tl_put_right:Nn \l__exsheets_include_id_tl {y} } + { \tl_put_right:Nn \l__exsheets_include_id_tl {n} } + } + } + } + \bool_set_true:N \l__exsheets_tmpa_bool + \clist_if_in:NVT + \l__exsheets_exclude_id_clist + \l__exsheets_tmpb_tl + { \bool_set_false:N \l__exsheets_tmpa_bool } + \seq_if_in:NnT + \g_exsheets_included_questions_seq + \l__exsheets_tmpb_tl + { \bool_set_false:N \l__exsheets_tmpa_bool } + \tl_if_in:NnT \l__exsheets_include_id_tl {n} + { \bool_set_false:N \l__exsheets_tmpa_bool } + \bool_if:NT \l__exsheets_tmpa_bool + % \tl_if_in:NnF \l__exsheets_include_id_tl { n } + % { + % \clist_if_in:NVF + % \l__exsheets_exclude_id_clist + % \l__exsheets_tmpb_tl + { + \clist_put_right:NV + \l__exsheets_include_id_clist + \l__exsheets_tmpb_tl + \int_incr:N \l__exsheets_tmpb_int + } + % } + } + } + } + } + } + } +% \cs_generate_variant:Nn \clist_if_in_p:Nn {NV} +% \cs_generate_variant:Nn \seq_if_in_p:Nn {NV} + +\NewDocumentCommand \PrintIfIncludeActiveTF { mm } + { \bool_if:NTF \l__exsheets_questions_deactivate_bool {#2} {#1} } + +\NewDocumentCommand \PrintIfIncludeActiveT { } + { \bool_if:NF \l__exsheets_questions_deactivate_bool } + +\NewDocumentCommand \PrintIfIncludeActiveF { } + { \bool_if:NT \l__exsheets_questions_deactivate_bool } + +% ---------------------------------------------------------------------------- +% die 'solution' Umgebung: +\cs_new_protected:Npn \__exsheets_save_solution:n #1 + { + % save for later use + \bool_if:NTF \l__exsheets_include_all_bool + { \int_set:Nn \l__exsheets_tmpe_int { \g__exsheets_questions_id_int -1 } } + { \int_set_eq:NN \l__exsheets_tmpe_int \g__exsheets_questions_id_int } + \prop_gput:Nxn \g__exsheets_solutions_content_prop + { \int_use:N \g__exsheets_questions_id_int } + {#1} + \prop_gput:NxV \g__exsheets_solutions_questions_id_prop + { \int_use:N \g__exsheets_questions_id_int } + \g__exsheets_questions_current_id_tl + \prop_gput:NxV \g__exsheets_solutions_names_prop + { \int_use:N \g__exsheets_questions_id_int } + \l__exsheets_solutions_name_tl + \prop_gput:NxV \g__exsheets_solutions_counter_prop + { \int_use:N \g__exsheets_questions_id_int } + \l__exsheets_qu_counter_pattern_tl + % print here + \exsheets_if_current_question_is_used:T + { + \bool_if:NT \l__exsheets_solutions_print_bool + { + \int_set:Nn \l_exsheets_counter_qu_int { \arabic {question} } + \__exsheets_get_sectioning_numbers: + \__exsheets_print_solution:VVn + \g__exsheets_questions_current_id_tl + \l__exsheets_solutions_name_tl + {#1} + } + } + } +\cs_generate_variant:Nn \__exsheets_save_solution:n { V } + +\NewEnviron { __exsheets_solution_internal: } + { + \bool_if:nT + { \g__exsheets_questions_use_bool && \l__exsheets_solutions_use_bool } + { \__exsheets_save_solution:V \BODY } + } + +\newenvironment {__exsheets_solution:} [1] + { + \tl_clear:N \l__exsheets_use_solution_tl + % \prop_show:N \l__exsheets_class_prop + \prop_map_inline:Nn \l__exsheets_class_prop + { + \use:c {__exsheets_solutions_use_##1:} + \bool_if:nTF + { + \l__exsheets_solutions_use_bool + && + ( + !\bool_if_p:c {g__exsheets_use_##1_bool} + || + \bool_if_p:c {l__exsheets_##2_active_bool} + ) + } + { \tl_put_right:Nn \l__exsheets_use_solution_tl {y} } + { \tl_put_right:Nn \l__exsheets_use_solution_tl {n} } + } + % verwende, wenn ein Ja dabei war: + \tl_if_in:NnT \l__exsheets_use_solution_tl {y} + { \bool_set_true:N \l__exsheets_solutions_use_bool } + \bool_if:NT \l__exsheets_questions_deactivate_bool + { \bool_set_false:N \l__exsheets_solutions_use_bool } + \bool_if:NT \l__exsheets_solutions_use_bool + { + \bool_set_true:N \l__exsheets_inside_solution_bool + \IfNoValueF {#1} { \keys_set:nn {exsheets/solution} {#1} } + } + \tl_if_blank:VT \l__exsheets_solution_heading_instance_tl + { + \tl_set_eq:NN + \l__exsheets_solution_heading_instance_tl + \l__exsheets_heading_instance_tl + } + \__exsheets_solution_internal: + } + { \end__exsheets_solution_internal: } + +\cs_new_protected:Npn \__exsheets_solutions_name:nnn #1#2#3 + { + \tl_if_blank:VT \l__exsheets_solution_heading_instance_tl + { + \tl_set_eq:NN + \l__exsheets_solution_heading_instance_tl + \l__exsheets_heading_instance_tl + } + \exsheets_use_heading:Vnnnnn + \l__exsheets_solution_heading_instance_tl + {#2} {#1} { 0 } { 0 } {#3} + } +\cs_generate_variant:Nn \__exsheets_solutions_name:nnn { VV , VVV } + +\cs_new:Npn \exsheets_solutions_name_style:n #1 + { \l_exsheets_solutions_name_style_tl #1 } + +% ---------------------------------------------------------------------------- +% print solutions: +% save section / chapter counter: +\cs_new_protected:Npn \__exsheets_exlabel:n #1 + { + \@bsphack + \exsheets_write_to_aux_x:n + { + \token_to_str:N \newlabel { exse:#1 } + { { \arabic {section} } { \thepage } } + } + \cs_if_exist:NT \thechapter + { + \exsheets_write_to_aux_x:n + { + \token_to_str:N \newlabel { exch:#1 } + { { \arabic {chapter} } { \thepage } } + } + } + \@esphack + } + +% user command: +\cs_new_eq:NN \exlabel \__exsheets_exlabel:n + +% adapt \label, maybe do this _after_ BeginDocument: +\bool_if:NT \l__exsheets_solutions_by_ref_bool + { + \cs_new_eq:NN \__exsheets_saved_label:n \label + \cs_set:Npn \label #1 + { \__exsheets_saved_label:n {#1} \__exsheets_exlabel:n {#1} } + } + +% this is like \ref from latex.ltx +\cs_new:Npn \__exsheets_exref:n #1 + { + \cs_if_exist:cTF { r@#1 } + { \__exsheets_exref_aux:n {#1} } + { + 1\relax + \protect\G@refundefinedtrue + \@latex@warning{exlabel `#1' on page \thepage \space undefined}% + } + } + +\cs_new:Npn \__exsheets_exref_aux:n #1 + { \exp_after:wN \exp_after:wN \exp_after:wN \use_i:nn \cs:w r@#1 \cs_end: } + +\cs_new_eq:NN \exref \__exsheets_exref:n + +% user command: +\NewDocumentCommand \printsolutions { O{all} } + { \exsheets_print_solutions:n {#1} } + +% internal command: +\cs_new_protected:Npn \exsheets_print_solutions:n #1 + { + \group_begin: + \bool_set_true:N \l__exsheets_solutions_print_bool + \bool_set_true:N \l__exsheets_inside_solution_bool + \cs_set:Npn \S ##1 { \exref { exse:##1 } } + \cs_set:Npn \C ##1 { \exref { exch:##1 } } + \keys_set:nn { exsheets / exsheets_print_solutions } {#1} + \group_end: + } + +\keys_define:nn {exsheets} + { + exsheets_print_solutions .choice: , + exsheets_print_solutions / section .code:n = + { \exsheets_print_solutions_section:n {#1} } , + exsheets_print_solutions / chapter .code:n = + { \exsheets_print_solutions_chapter:n {#1} } , + exsheets_print_solutions / all .code:n = + { \exsheets_print_solutions_all: } , + exsheets_print_solutions / byID .code:n = + { \exsheets_print_solutions_byID:n {#1} } + } + +\cs_new_protected:Npn \__exsheets_get_sectioning_numbers: + { + \cs_if_exist:NT \chapter + { \int_set:Nn \l__exsheets_counter_ch_int { \arabic {chapter} } } + \int_set:Nn \l__exsheets_counter_sec_int { \arabic {section} } + \int_set:Nn \l_exsheets_counter_qu_int { \arabic {question} } + } + +% #1: numeric ID +% #2: condition +\cs_new_protected:Npn \__exsheets_print_solution_if:nn #1#2 + { + \bool_if:nT + { #2 && \prop_if_in_p:Nn \g__exsheets_solutions_questions_id_prop {#1} } + { + \prop_get:NnN \g__exsheets_solutions_names_prop + {#1} \l__exsheets_tmpa_tl + \prop_get:NnN \g__exsheets_solutions_content_prop + {#1} \l__exsheets_tmpb_tl + \prop_get:NnN \g__exsheets_solutions_questions_id_prop + {#1} \l__exsheets_tmpc_tl + \prop_get:NnN \g__exsheets_solutions_counter_prop + {#1} \l__exsheets_tmpd_tl + \group_begin: + \tl_set_eq:NN \CurrentQuestionID \l__exsheets_tmpc_tl + \__exsheets_sectioning_hook:nV {ch} + \l__exsheets_new_chapter_hook_tl + \__exsheets_sectioning_hook:nV {sec} + \l__exsheets_new_section_hook_tl + \group_end: + \__exsheets_print_solution:VVV + \l__exsheets_tmpc_tl + \l__exsheets_tmpa_tl + \l__exsheets_tmpb_tl + } + } + +% print by section: +\cs_new_protected:Npn \exsheets_print_solutions_section:n #1 + { + \tl_if_blank:nTF {#1} + { + \prop_map_inline:Nn \g_exsheets_question_identification_prop + { + \__exsheets_print_solutions_section:nnn + {##1} + {##2} + { \arabic{section} } + } + } + { + \clist_map_inline:nn {#1} + { \__exsheets_print_solutions_by_section:w ##1-- \q_stop } + } + } + +\cs_new_protected:Npn \__exsheets_print_solutions_by_section:w #1-#2-#3 \q_stop + { + % wenn #3=-, dann range-Input + \tl_if_eq:nnTF {#3} { - } + { + \int_zero:N \l__exsheets_tmpa_int + \int_set_eq:NN \l__exsheets_tmpb_int \c_ten_thousand + \tl_if_blank:nF {#1} { \int_set:Nn \l__exsheets_tmpa_int {#1} } + \tl_if_blank:nF {#2} { \int_set:Nn \l__exsheets_tmpb_int {#2} } + \int_do_while:nn { \l__exsheets_tmpa_int <= \l__exsheets_tmpb_int } + { + \prop_map_inline:Nn \g_exsheets_question_identification_prop + { + \__exsheets_print_solutions_section:nnn + {##1} {##2} { \l__exsheets_tmpa_int } + } + \int_incr:N \l__exsheets_tmpa_int + } + } + { + \prop_map_inline:Nn \g_exsheets_question_identification_prop + { \__exsheets_print_solutions_section:nnn {##1} {##2} {#1} } + } + } + +\cs_new_protected:Npn \__exsheets_print_solutions_section:nnn #1#2#3 + { + \__exsheets_read_number:w #2 \q_stop + \__exsheets_print_solution_if:nn {#1} + { \int_compare_p:n { \l__exsheets_counter_sec_int = #3 } } + } + +% print by chapter: +\cs_new_protected:Npn \exsheets_print_solutions_chapter:n #1 + { + \tl_if_blank:nTF {#1} + { + \prop_map_inline:Nn \g_exsheets_question_identification_prop + { + \__exsheets_print_solutions_chapter:nnn {##1} {##2} + { \arabic{chapter} } + } + } + { + \clist_map_inline:nn {#1} + { \__exsheets_print_solutions_by_chapter:w ##1-- \q_stop } + } + } + +\cs_new_protected:Npn \__exsheets_print_solutions_by_chapter:w #1-#2-#3 \q_stop + { + % wenn #3=-, dann range-Input + \tl_if_eq:nnTF {#3} { - } + { + \int_zero:N \l__exsheets_tmpa_int + \int_set_eq:NN \l__exsheets_tmpb_int \c_ten_thousand + \tl_if_blank:nF {#1} { \int_set:Nn \l__exsheets_tmpa_int {#1} } + \tl_if_blank:nF {#2} { \int_set:Nn \l__exsheets_tmpb_int {#2} } + \int_do_while:nn { \l__exsheets_tmpa_int <= \l__exsheets_tmpb_int } + { + \prop_map_inline:Nn \g_exsheets_question_identification_prop + { + \__exsheets_print_solutions_chapter:nnn + {##1} + {##2} + { \l__exsheets_tmpa_int } + } + \int_incr:N \l__exsheets_tmpa_int + } + } + { + \prop_map_inline:Nn \g_exsheets_question_identification_prop + { \__exsheets_print_solutions_chapter:nnn {##1} {##2} {#1} } + } + } + +\cs_new_protected:Npn \__exsheets_print_solutions_chapter:nnn #1#2#3 + { + \__exsheets_read_number:w #2 \q_stop + \__exsheets_print_solution_if:nn {#1} + { \int_compare_p:n { \l__exsheets_counter_ch_int = #3 } } + } + +% print all: +\cs_new_protected:Npn \exsheets_print_solutions_all: + { + \prop_map_function:NN \g_exsheets_question_identification_prop + \__exsheets_print_solutions_all:nn + % \prop_show:N \g_exsheets_question_identification_prop + } + +\cs_new:Npn \__exsheets_sectioning_hook:nn #1#2 + { + \bool_if:nT { + !\int_compare_p:n + { + \use:c { l__exsheets_current_#1_int } + = + \use:c { l__exsheets_counter_#1_int } + } + && + !\int_compare_p:n + { \use:c { l__exsheets_counter_#1_int } = 0 } + } + {#2} + } +\cs_generate_variant:Nn \__exsheets_sectioning_hook:nn { nV } + +\cs_new_protected:Npn \__exsheets_print_solutions_all:nn #1#2 + { \exsheets_print_solutions_if:nnn { \c_true_bool } {#1} {#2} } + +% #1: condition +% #2: numeric question ID +% #3: question number string (stored in \g_exsheets_question_identification_prop) +% use function in a wrapper which in turn is fed to +% \prop_map_function:NN \g_exsheets_question_identification_prop +\cs_new_protected:Npn \exsheets_print_solutions_if:nnn #1#2#3 + { + \prop_if_in:NnT \g__exsheets_solutions_names_prop {#2} + { + \int_set_eq:NN + \l__exsheets_current_sec_int + \l__exsheets_counter_sec_int + \int_set_eq:NN + \l__exsheets_current_ch_int + \l__exsheets_counter_ch_int + \__exsheets_read_number:w #3 \q_stop + \__exsheets_print_solution_if:nn {#2} {#1} + } + } +\cs_generate_variant:Nn \exsheets_print_solutions_if:nnn {nnV} + +% print by ID: +\seq_new:N \l__exsheets_solutions_byID_seq +\cs_new_protected:Npn \exsheets_print_solutions_byID:n #1 + { + \seq_set_split:Nnn \l__exsheets_solutions_byID_seq { , } {#1} + \seq_clear:N \l__exsheets_tmpa_seq + \seq_map_inline:Nn \l__exsheets_solutions_byID_seq + { + \prop_get:NnN \g__exsheets_questions_id_prop + {##1} \l__exsheets_tmpa_tl + \seq_put_right:NV \l__exsheets_tmpa_seq \l__exsheets_tmpa_tl + } + \bool_if:NT \l__exsheets_print_byID_sorted_bool + { + \seq_sort:Nn \l__exsheets_tmpa_seq + { + \int_compare:nNnTF {##1} > {##2} + { \sort_return_swapped: } + { \sort_return_same: } + } + } + \seq_map_inline:Nn \l__exsheets_tmpa_seq + { + \prop_get:NnNT \g_exsheets_question_identification_prop {##1} + \l__exsheets_tmpa_tl + { + \exsheets_print_solutions_if:nnV + { \c_true_bool } + {##1} + \l__exsheets_tmpa_tl + } + } + } + +\cs_new_protected:Npn \__exsheets_read_number:w #1-#2-#3 \q_stop + { + \int_zero:N \l__exsheets_counter_ch_int + \int_zero:N \l__exsheets_counter_sec_int + \int_zero:N \l_exsheets_counter_qu_int + \tl_if_in:nnF {#1} { @@@ } + { + \tl_if_blank:nF {#1} + { \int_set:Nn \l__exsheets_counter_ch_int {#1} } + } + \int_set:Nn \l__exsheets_counter_sec_int {#2} + \int_set:Nn \l_exsheets_counter_qu_int {#3} + } + +\cs_new_protected:Npn \exsheets_solutions_print_name:nnn #1#2#3 + { + \tl_set_rescan:Nnn \l__exsheets_tmpa_tl + { \char_set_catcode_letter:N \@ } {#1} + \tl_if_in:nnTF {#1} { @@@ } + { \__exsheets_solutions_name:nnn { } {#2} {#3} } + { \__exsheets_solutions_name:nnn {#1} {#2} {#3} } + \tex_penalty:D \c_ten_thousand + } +\cs_generate_variant:Nn \exsheets_solutions_print_name:nnn { V , VVV } + +\cs_new:Npn \__exsheets_surround_with:nnn #1#2#3 { #2#1#3 } +\cs_generate_variant:Nn \__exsheets_surround_with:nnn { nVV } + +% think about the interface with \exsheetsprintsolution a bit more, especially +% about the placement of the hooks! + +% #1: ID +% #2: name +% #3: body +\cs_new_protected:Npn \__exsheets_print_solution:nnn #1#2#3 + { + \group_begin: + \tl_set:Nn \CurrentQuestionID {#1} + \tl_set:Nx \l__exsheets_tmpa_tl { \exsheets_question_number:n {#1} } + \__exsheets_surround_with:nVV + { + \exp_args:Nnx + \exsheetsprintsolution + { \exsheets_solutions_print_name:Vnn \l__exsheets_tmpa_tl {#2} {#1} } + { + \exp_not:V \l__exsheets_solutions_pre_body_hook_tl + \exp_not:n {#3} + \exp_not:V \l__exsheets_solutions_post_body_hook_tl + } + } + \l__exsheets_solutions_pre_hook_tl + \l__exsheets_solutions_post_hook_tl + \exsheets_add_space:N \l__exsheets_solutions_skip_below_dim + \group_end: + } +\cs_generate_variant:Nn \__exsheets_print_solution:nnn { VV , VVV } + +% a user command to be redefined as needed; must have two mandatory arguments! +% #1: heading +% #2: body +\cs_new:Npn \exsheetsprintsolution #1#2 { #1#2 } + +\cs_new:Npn \PrintSolutionsTF + { \bool_if:NTF \l__exsheets_solutions_print_bool } +\cs_new:Npn \PrintSolutionsT + { \bool_if:NT \l__exsheets_solutions_print_bool } +\cs_new:Npn \PrintSolutionsF + { \bool_if:NF \l__exsheets_solutions_print_bool } + +\keys_define:nn { exsheets / solution } + { + headings .tl_set:N = \l__exsheets_solution_heading_instance_tl , + print .choice: , + print / true .code:n = + { + \bool_set_true:N \l__exsheets_solutions_print_bool + \bool_set_false:N \l__exsheets_solutions_print_section_bool + \bool_set_false:N \l__exsheets_solutions_print_chapter_bool + \bool_set_false:N \l__exsheets_solutions_print_all_bool + } , + print / false .code:n = + { + \bool_set_false:N \l__exsheets_solutions_print_bool + } , + print .default:n = true , + name .tl_set:N = \l__exsheets_solutions_name_tl , + sorted .bool_set:N = \l__exsheets_print_byID_sorted_bool , + skip-below .dim_set:N = \l__exsheets_solutions_skip_below_dim , + no-skip-below .bool_set:N = \l__exsheets_no_skip_after_bool , + pre-body-hook .tl_set:N = \l__exsheets_solutions_pre_body_hook_tl , + post-body-hook .tl_set:N = \l__exsheets_solutions_post_body_hook_tl , + pre-hook .tl_set:N = \l__exsheets_solutions_pre_hook_tl , + post-hook .tl_set:N = \l__exsheets_solutions_post_hook_tl + } + +% ---------------------------------------------------------------------------- +% create question/solution pairs +\cs_new_protected:Npn \__exsheets_new_qu_sol_pair:nnnnnn #1#2#3#4#5#6 + { + \NewDocumentEnvironment {#1} { O{}G{} } + { \keys_set:nn {exsheets} {#3} \__exsheets_question: {#2,##1} {##2} } + { \end__exsheets_question: } + \NewDocumentEnvironment {#4} { O{} } + { \keys_set:nn {exsheets} {#6} \__exsheets_solution: {#5,##1} } + { \end__exsheets_solution: } + } + +\cs_new_protected:Npn \__exsheets_renew_qu_sol_pair:nnnnnn #1#2#3#4#5#6 + { + \RenewDocumentEnvironment {#1} { O{}G{} } + { \keys_set:nn {exsheets} {#3} \__exsheets_question: {#2,##1} {##2} } + { \end__exsheets_question: } + \RenewDocumentEnvironment {#4} { O{} } + { \keys_set:nn {exsheets} {#6} \__exsheets_solution: {#5,##1} } + { \end__exsheets_solution: } + } + +\NewDocumentCommand \NewQuSolPair { mO{}O{}mO{}O{} } + { \__exsheets_new_qu_sol_pair:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} } +\@onlypreamble \NewQuSolPair + +\NewDocumentCommand \RenewQuSolPair { mO{}O{}mO{}O{} } + { \__exsheets_renew_qu_sol_pair:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} } +\@onlypreamble \RenewQuSolPair + +% ---------------------------------------------------------------------------- +% the `tasks' list +\RequirePackage {tasks} [2014/07/03] +\AddCounterPattern* [tasks] {question} {qu} +\ReadCounterFrom [tasks] {question} \l_exsheets_counter_qu_int + +% ---------------------------------------------------------------------------- +% the \blank{<words>} command +\RequirePackage {ulem} \normalem + +\cs_new:Npn \exsheets_write_blank:n #1 {#1} +\cs_set_eq:NN \exsheets_write_blank:n \uline + +\keys_define:nn { exsheets / blank } + { + style .choice: , + style / line .code:n = + \cs_set_eq:NN \exsheets_write_blank:n \uline , + style / wave .code:n = + \cs_set_eq:NN \exsheets_write_blank:n \uwave , + style / dline .code:n = + \cs_set_eq:NN \exsheets_write_blank:n \uuline , + style / dotted .code:n = + \cs_set_eq:NN \exsheets_write_blank:n \dotuline , + style / dashed .code:n = + \cs_set_eq:NN \exsheets_write_blank:n \dashuline , + scale .tl_set:N = \l__exsheets_blank_scale_tl , + width .code:n = + { + \bool_set_true:N \l__exsheets_blank_width_bool + \dim_set:Nn \l__exsheets_blank_dim {#1} + } , + linespread .code:n = + \bool_set_true:N \l__exsheets_blank_linespread_bool + \tl_set:Nn \l__exsheets_blank_linespread_tl {#1} , + line-increment .dim_set:N = + \l__exsheets_blank_line_increment_dim , + line-increment .initial:n = 1pt , + line-minimum-length .dim_set:N = + \l__exsheets_blank_line_minimum_length_dim , + line-minimum-length .initial:n = 2em + } + +\NewDocumentCommand \blank { som } + { + \group_begin: + \IfNoValueF {#2} { \keys_set:nn { exsheets / blank } {#2} } + \mode_if_vertical:TF + { + \IfBooleanF {#1} { \noindent } + \exsheets_blank:n {#3} + \IfBooleanF {#1} + { + \bool_if:NT \l__exsheets_blank_linespread_bool + { \linespread { \l__exsheets_blank_linespread_tl } \selectfont } + \par + } + } + { \exsheets_blank:n {#3} } + \group_end: + } + +\cs_new_protected:Npn \exsheets_blank:n #1 + { + \box_clear:N \l__exsheets_blank_box + \mode_if_math:TF + { \hbox_set:Nn \l__exsheets_blank_box { $ \m@th \mathpalette{}{#1} $ } } + { \hbox_set:Nn \l__exsheets_blank_box {#1} } + \bool_if:NTF \l__exsheets_inside_solution_bool + { \exsheets_write_blank:n {#1} } + { + \bool_if:NTF \l__exsheets_blank_width_bool + { \__exsheets_blank_skip:N \l__exsheets_blank_dim } + { + \__exsheets_blank_skip:n + { \box_wd:N \l__exsheets_blank_box } + } + } + } + +\cs_new_protected:Npn \__exsheets_blank_skip:N #1 + { + \bool_if:NTF \l__exsheets_blank_width_bool + { \dim_set:Nn \l__exsheets_tmpa_dim {#1} } + { + \fp_set:Nn \l__exsheets_tmpa_fp + { \dim_to_fp:n {#1} * \l__exsheets_blank_scale_tl } + \dim_set:Nn \l__exsheets_tmpa_dim { \fp_to_dim:N \l__exsheets_tmpa_fp } + } + \dim_compare:nTF + { \l__exsheets_tmpa_dim > \l__exsheets_blank_line_minimum_length_dim } + { + \mode_if_math:TF + { \exsheets_write_blank:n { \skip_horizontal:N \l__exsheets_tmpa_dim } } + { + \dim_do_while:nn { \l__exsheets_tmpa_dim > \c_zero_dim } + { + \tex_penalty:D \hyphenpenalty + \dim_compare:nTF + { \l__exsheets_tmpa_dim < \l__exsheets_blank_line_increment_dim } + { \exsheets_write_blank:n { \skip_horizontal:N \l__exsheets_tmpa_dim } } + { + \exsheets_write_blank:n + { \skip_horizontal:N \l__exsheets_blank_line_increment_dim } + } + \dim_sub:Nn \l__exsheets_tmpa_dim { \l__exsheets_blank_line_increment_dim } + } + } + } + { \exsheets_write_blank:n { \skip_horizontal:N \l__exsheets_tmpa_dim } } + } +\cs_generate_variant:Nn \__exsheets_blank_skip:N { n } + +% the following code from Heiko Oberdieck in d.c.t.t served as inspiration +% and basis for the \blank command: +% https://groups.google.com/d/msg/de.comp.text.tex/fZLwraH04jE/o1RSdFXjGuIJ +% +% \makeatletter +% \newcommand*{\luecke}{% +% \begingroup +% \setlength{\dimen@}{6cm}% +% \ifdim\dimen@>2em % +% \underline{\hspace{1em}}% +% \advance\dimen@ by -2em\relax +% \@whiledim\dimen@>0pt\do{% +% \penalty\hyphenpenalty +% \ifdim\dimen@<1pt % +% \underline{\hspace{\dimen@}}% +% \else +% \underline{\hspace{1pt}}% +% \fi +% \advance\dimen@ by -1pt % +% }% +% \underline{\hspace{1em}}% +% \else +% \underline{\hspace{\dimen@}}% +% \fi +% \endgroup +% \xspace +% } +% \makeatother + +% ---------------------------------------------------------------------------- +% \examspace +% insert space for a student to answer a question +\cs_new_protected:Npn \__exsheets_examspace:nn #1#2 + { + \par + \tex_penalty:D -100 \scan_stop: + \dim_set:Nn \l__exsheets_tmpa_dim {#2} + \dim_set:Nn \l__exsheets_tmpb_dim { \pagegoal - \pagetotal - \baselineskip } + \dim_compare:nTF { \l__exsheets_tmpa_dim > \l__exsheets_tmpb_dim } + { + \dim_compare:nT { \l__exsheets_tmpb_dim > 0pt } { \vfil } + \break + \IfBooleanF {#1} + { + \dim_sub:Nn \l__exsheets_tmpa_dim { \l__exsheets_tmpb_dim } + \vspace* { \l__exsheets_tmpa_dim } + } + } + { \skip_vertical:N \l__exsheets_tmpa_dim } + } +\NewDocumentCommand \examspace { sm } + { \__exsheets_examspace:nn {#1} {#2} } + +% ---------------------------------------------------------------------------- +% SETUP +\NewDocumentCommand \SetupExSheets { o +m } + { + \IfNoValueTF {#1} + { \keys_set:nn {exsheets} {#2} } + { \keys_set:nn { exsheets / #1 } {#2} } + } + +% ---------------------------------------------------------------------------- +% default definitions: +% question / solution pair: +\NewQuSolPair {question} {solution} + +% properties: +% \DeclareQuestionProperty{number} +\DeclareQuestionProperty {counter} +\DeclareQuestionProperty {subtitle} +\DeclareQuestionProperty {question-body} +\DeclareQuestionProperty {points} +\DeclareQuestionProperty {bonus-points} +\bool_if:NT \l__exsheets_auto_label_bool + { + \DeclareQuestionProperty {ref} + \DeclareQuestionProperty {pageref} + } + +% classes: +\DeclareQuestionClass {class} {classes} +\DeclareQuestionClass {topic} {topics} + +% ---------------------------------------------------------------------------- +% Sprachanpassungen +\RequirePackage {translations} +% translation for the exercises +\DeclareTranslationFallback {exsheets-exercise-name} {Exercise} +\DeclareTranslation {English} {exsheets-exercise-name} {Exercise} +\DeclareTranslation {British} {exsheets-exercise-name} {Exercise} +\DeclareTranslation {American} {exsheets-exercise-name} {Exercise} +\DeclareTranslation {French} {exsheets-exercise-name} {Exercice} +\DeclareTranslation {German} {exsheets-exercise-name} {\"Ubung} +\DeclareTranslation {Italian} {exsheets-exercise-name} {Esercizio} +\DeclareTranslation {Spanish} {exsheets-exercise-name} {Ejercicio} +\DeclareTranslation {Catalan} {exsheets-exercise-name} {Exercici} +\DeclareTranslation {Turkish} {exsheets-exercise-name} {Egzersiz} +\DeclareTranslation {Croatian} {exsheets-exercise-name} {Primjer} +\DeclareTranslation {Hungarian} {exsheets-exercise-name} {Gyakorol} +\DeclareTranslation {Danish} {exsheets-exercise-name} {Opgave} +\DeclareTranslation {Norsk} {exsheets-exercise-name} {Oppgave} +\DeclareTranslation {Portuges} {exsheets-exercise-name} {Exerc\'\i cio} +% translation for the question +\DeclareTranslationFallback {exsheets-question-name} {Question} +\DeclareTranslation {English} {exsheets-question-name} {Question} +\DeclareTranslation {British} {exsheets-question-name} {Question} +\DeclareTranslation {American} {exsheets-question-name} {Question} +\DeclareTranslation {French} {exsheets-question-name} {Question} +\DeclareTranslation {German} {exsheets-question-name} {Aufgabe} +\DeclareTranslation {Italian} {exsheets-question-name} {Questione} +\DeclareTranslation {Spanish} {exsheets-question-name} {Pregunta} +\DeclareTranslation {Catalan} {exsheets-question-name} {Q\"uesti\'o} +\DeclareTranslation {Turkish} {exsheets-question-name} {Soru} +\DeclareTranslation {Croatian} {exsheets-question-name} {Zadatak} +\DeclareTranslation {Hungarian} {exsheets-question-name} {Feladat} +\DeclareTranslation {Danish} {exsheets-question-name} {Opgave} +\DeclareTranslation {Norsk} {exsheets-question-name} {Oppgave} +\DeclareTranslation {Portuges} {exsheets-question-name} {Quest\~ao} +% translation for the solutions +\DeclareTranslationFallback {exsheets-solution-name} {Solution} +\DeclareTranslation {English} {exsheets-solution-name} {Solution} +\DeclareTranslation {British} {exsheets-solution-name} {Solution} +\DeclareTranslation {American} {exsheets-solution-name} {Solution} +\DeclareTranslation {French} {exsheets-solution-name} {Solution} +\DeclareTranslation {German} {exsheets-solution-name} {L\"osung} +\DeclareTranslation {Italian} {exsheets-solution-name} {Soluzione} +\DeclareTranslation {Spanish} {exsheets-solution-name} {Soluci\'on} +\DeclareTranslation {Catalan} {exsheets-solution-name} {Soluci\'o} +\DeclareTranslation {Turkish} {exsheets-solution-name} {\c C\"oz\"um} +\DeclareTranslation {Croatian} {exsheets-solution-name} {Rje\v{s}enje} +\DeclareTranslation {Hungarian} {exsheets-solution-name} {Megold\'{a}s} +\DeclareTranslation {Danish} {exsheets-solution-name} {L\o sning} +\DeclareTranslation {Norsk} {exsheets-solution-name} {L\o sning} +\DeclareTranslation {Portuges} {exsheets-solution-name} {Solu\c c\~ao} +% the actual translating +\tl_set:Nn \l__exsheets_exercise_name_tl + { \GetTranslation {exsheets-exercise-name} } +\tl_set:Nn \l__exsheets_questions_name_tl + { \GetTranslation {exsheets-question-name} } +\tl_set:Nn \l__exsheets_solutions_name_tl + { \GetTranslation {exsheets-solution-name} } + + +% ---------------------------------------------------------------------------- +% save total points in .aux file to make it available for \allpoints anywhere +\AtEndDocument + { + \exsheets_write_to_aux_x:n + { + \exp_not:N \exsheets@sum@of@points + { \fp_eval:n { \g__exsheets_points_sum_fp } }^^J + \exp_not:N \exsheets@sum@of@bonus + { \fp_eval:n { \g__exsheets_bonus_sum_fp } }^^J + \exp_not:N \gdef \exp_not:N \numberofquestions + { \int_use:N \g__exsheets_questions_used_int } + % \exsheets@number@of@questions + % { \int_to_arabic:V \g__exsheets_questions_id_int } + } + } + +% ---------------------------------------------------------------------------- +% load custom configuration +\file_if_exist:nT {exsheets_configurations.cfg} + { + \AtBeginDocument + { + \msg_info:nn {exsheets} {loading-configurations} + \file_input:n {exsheets_configurations.cfg} + } + } + +\tex_endinput:D + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +HISTORY: +2011/11/23 v0.1pre - first upload to bitbucket and all changes until + considered stable enough/ready to be called + 0.1alpha. There'll be no further descriptions until + then. +2012/06/08 v0.1alpha - first hopefully stable version +2012/06/11 v0.1alpha-a - added headings instances, slightly rewritten + `exercises-tasks' object and `tasks' environment +2012/06/11 v0.1alpha-b - added `multiplechoice' instance and `load-tasks' + option +2012/06/12 v0.1alpha-c - renamed from `exercises' into `ExSheets' +2012/06/15 v0.1alpha-d - added more flexible solution printing method +2012/06/15 v0.1beta - filled in some blanks in the documentation, now we + need some testing! +2012/09/07 v0.1beta-a - adjustments to the updated l3kernel +2012/09/08 v0.1beta-b - sort solutions printed with the `byID' key +2012/09/16 v0.1beta-c - renamed option `questions-counter-format' into + `counter-format' +2012/09/19 v0.1beta-d - added `topic' key, provide \includequestions with + options `all' and `IDs' +2012/09/24 v0.1beta-e - added question properties and improved random + question selection +2012/09/27 v0.1 - added two headings instances, new option + `headings-format' + - small changes in the definition of the + `exsheets-headings' object + - preliminary version of totoc options. Unfortunatly + \exsheets@recover@number is not expandable => no + hyperref support +2012/09/30 v0.2beta - version numbering gone crazy! this will now stay + 0.2beta until upload to CTAN (v0.2) + - integrated packages `translations' and `cntformats': + trnslt: provide expandable version of `translator's + \translate + cntfmts: outsourced previous counter formatting + commands; should now be usable in other packages, + too, and simplified definitions in `ExSheets' + - thanks to `translations' and `cntformats' the `totoc' + option now works with `hyperref' +2012/10/05 v0.2 - removed \sumpoints and moved the functionality to + \totalpoints* + - changed meaning of \addpoints* and moved former + functionality to \points + - added bonus point functionality including \addbonus, + \bonus, \bonussum, \pointssum, \currentpointssum, + \currentbonussum + - added grades distribution +2012/10/05 v0.2a - resolved bug in saving and recovering question number + using \exsheets@save@number and \QuestionNumber +2012/10/08 v0.2b - improved the reference to chapter/solution numbers + in \printsolutions + - resolved bug in \printsolutions introduced in the + last update + - upload to CTAN + +2012/10/23 v0.3 - bugfix in \exref + - new: \NewQuSolPair, \RenewQuSolPair, \examspace +2012/10/24 v0.3a - fix of headings when followed by a list + - changed syntax of {tasks} list to resemble the real + lists like enumerate +2012/10/26 v0.3b - small fix to the {tasks} environment, \NewTasks, + \RenewTasks, resolve stupid bug: + \ckeckedchoicebox => \checkedchoicebox +2012/11/08 v0.4 - compatibility with KOMA-Script's `parskip' option: + now no unwanted skip and no overfull hbox is produced + - env {task} now supports inner environments +2012/12/02 v0.5 - added \CurrentQuestionID +2012/12/06 v0.5a - bug fix: solutions had wrong numbers with + counter-format=se.qu and [print] option +2012/12/18 v0.6 - variations, Hungarian translations, corrected + Catalanian translations +2012/12/23 v0.6a - bug fix: labels and items of {tasks} weren't joined + at their baselines +2013/01/06 v0.6b - bug fix: ID counting fixed in \includequestions +2013/01/19 v0.7 - extracted `tasks' environment into standalone + package; this also lead to a slightly new syntax and + a few new options for it + - changed internals for random selection of questions: + uses `pgf' instead of `lcg' and seems to be more + reliable than before +2013/01/21 v0.7a - added option `auto-label' and questions key `label', + also added question properties `ref' and `pageref' +2013/02/17 v0.7b - bug fix: question selection by ID now works again +2013/03/10 v0.8 - \prop_length => \exsheets_prop_count + - define unexpandable internal commands protected + - translations basic dictionaries for English, German, + French and Spanish + - new \includequestions option `exclude' + - new way of handling the `class' of questions: + instead of hard-coded `classes' and `topics' + individual groups like e.g. `difficulties' can be + chosen; `classes' and `topics' are still provided for + backwards compatibility; this introduces the new + command \DeclareQuestionClass + - minor changes to the debugging information layout + - bug fix in number saving mechanism + - \includequestions[random=<num>] now obeys class + as done with \SetupExSheets{use-topics={foo,bar}} + - new macro \questionsincludedlast +2013/04/04 v0.8a - added Portuguese translations +2013/04/07 v0.9 - protected internal commands where appropriate + - added possibility to set general options with + \NewQuSolPair and \RenewQuSolPair +2013/04/08 v0.9a - added headings instance `empty' +2013/04/18 v0.9b - fixed erroneous behaviour of \includequestions when + used more than once + - added hook \l__exsheets_heading_points_post_hook_tl +2013/04/21 v0.9c - bug fix: \ForEachQuestion seems to work correctly + again +2013/04/25 v0.9d - bug fix: \includequestions works correctly when used + multiple times together with ordinary instances of + the {question} environment + - bug fix: points/parse=false correctly disables + parsing points again + - bug fix: \addpoints didn't add to the question + property + - new option `points/format' + - \blank now works in math mode, it doesn't do + linebreaks there if `ulem' doesn't allow them (which + it doesn't) +2013/05/01 v0.9e - corrected erroneous behaviour of \examspace +2013/05/26 v0.9f - fixed incorrectly placed links when the `totoc' + option is enabled and questions/solutions are at the + top of a new page because there wasn't enough place + left at the page before +2013/05/30 v0.9g - obey \if@filesw +2013/06/28 v0.9h - cleaner internal use of + \exsheets_set_question_properties:n +2013/07/17 v0.9i - made \g__exsheets_total_bonus_fp and + \g__exsheets_total_points_fp public + - removed `translations' from the bundle +2013/10/11 v0.10 - require `translations' like any other package + - added `exsheets-listings' package + - added Norwegian translations + - changed horizontal spaces declared as `1ex' into + `.3333em' in the declarations of the headings + instances + - added subtitles +2013/11/07 v0.10a - fix bug in loading headings of questions; when + included from an external file sometimes the wrong ID + has been passed to the headings +2013/11/20 v0.11 - \GetQuestionClass{} + - \PrintQuestionClass(TF) +2013/12/02 v0.12 - fix issue with \CurrentQuestionID + - new options `label-format', `label-cmd', `ref-cmd' + and `pageref-cmd' for `auto-label' options that + allow specification of labelling command and thus + compatibility with packages like `cleveref' + - write question properties to aux file so they can be + retrieved before the corresponding question is + printed + - make \GetQuestionProperty expandable + - new syntax feature in points argument: a leading + bang prevents the points from being added to the sum + of points + - added possibility for + https://bitbucket.org/cgnieder/exsheets/issue/15 + - added \IfQuestionSubtitle(TF) + - added `subtitle' property + - dropped `color' option +2013/12/08 v0.12a - changed details in the printing mechanism of the + points which seems to be more consistent + - fix bug introduced in the last update: subtitles work + again +2013/12/27 v0.12b - ensure that points are not parsed if a leading bang + is inserted + - fix bug in parsing the points +2014/05/11 v0.13 - new options: + * chapter-hook + * section-hook + These options provide hooks to add code in the list + of solutions (when printed with \printsolutions[all]) + when solutions from a new section or chapter are + printed +2014/05/11 v0.13a - bug fix: solutions get the counter-format that's + active when the corresponding `solution' environment + is placed in the source +2014/06/27 v0.14 - new command: \ExSheetsHeading + - \__exsheets_use_heading:nnnnnn => + \exsheets_use_heading:nnnnnn + - new options `question/pre-hook' and + `question/post-hook' + - new pre-defined property `question-body' + - new pre-defined property `bonus-points' + - new pre-defined property `counter' + - new option `question/save-to-aux' + - \ForEachQuestion, \numberofquestions and + \iflastquestion are now available before any + questions have been typeset +2014/07/20 v0.15 - remove `tasks' from the bundle and into a package of + its own + - remove `cntformats' from the bundle and into a package of + its own + - drop options `load-headings' and `load-tasks' + - new command \IfQuestionPropertyTF +2014/09/14 v0.16 - fix `subtitle-format' option + - allow that the format given in `headings-format' and + `subtitle-format' can end with a command needing an + argument + - add options `solution/pre-hook', + `solution/post-hook', `solution/pre-body-hook' and + `solution/post-body-hook' (this adds a possibility + for issue #21) + - add options `question/pre-body-hook' and + `question/post-body-hook' + - add internal interface for the printing of solutions + ( \__exsheets_print_solution:nnnn ) + - fix issue #22 + - fix issue #23 + - use only one version number for the whole bundle +2014/10/14 v0.17 - new option `use-saved-counter-format' +2015/02/09 v0.18 - added correct Danish translations - thanks to Jonas + Nyrup + - introduce \exsheetsprintsolution, see + http://tex.stackexchange.com/q/227078/ for motivation + - change test in \exsheets_h_or_vspace:N to something + more reliable and meaningful + - new option `no-skip-below' +2015/05/06 v0.18a - fix bug in points mechanism + - singular points name is now only used for exactly 1 + point + - a few cosmetic changes to the points function + definitions +2015/07/04 v0.19 - add http://tex.stackexchange.com/q/222814 + - allow begin and end of pseudo-environments as hooks + to the question an solution environments +2015/11/18 v0.20 - add tagging feature + - new: \DeclareExSheetsHeadingContainer +2016/01/26 v0.21 - give error message when \includequestions tries to + load a file which can't be found (issue) + - \exsheets_print_solutions_if:nnn + - \l__exsheets_counter_qu_int => + \l_exsheets_counter_qu_int + - \g__exsheets_question_number_prop => + \g_exsheets_question_identification_prop + - make question properties accessable when question is + not printed +2016/01/26 v0.21a - remove deprecated \prop_get:Nn (=> \prop_item:Nn) +2016/02/01 v0.21b - fix annoying bug in \exsheets_print_solutions_if:nnn +2016/03/21 v0.21c - use question property `counter' for retrieving the + counter patterns in solution's headings (this + resolves http://tex.stackexchange.com/q/299898) + - remove option `use-saved-counter-format': solutions + should always have the same number pattern as the + corresponding questions +2016/08/14 v0.21d - fix issue #32 +2016/09/07 v0.21e - fix issue #29 + - fix issue #35 + - fix issue #36 +2016/09/17 v0.21f - make \exsheets_question_number:n an alias of + \exsheets_get_question_property:nn {counter}; this + also makes \QuestionNumber an alias of + \GetQuestionProperty {counter} +2016/10/25 v0.21g - smaller steps when creating the blank lines +2016/11/28 v0.21h - bug in \exsheets@used@id fixed +2017/02/08 v0.21i - adapt to l3sort integration into l3kernel + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% TODO: +- solve the problem using verbatim material in questions and solutions + (difficult) +- allow for different kinds of problems/solutions using an independant counter + (not trivial) +- points/decimal-marker, points/frac (?), points/format (?,im interface) +- points: swedish style +- \examspace inside {tasks} => possible? (\pagegoal-\pagetotal) gives wrong + values here +- remove doubled points name if total points are unknown diff --git a/macros/latex/contrib/exsheets/exsheets_configurations.cfg b/macros/latex/contrib/exsheets/exsheets_configurations.cfg new file mode 100644 index 0000000000..e5f7eb0046 --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets_configurations.cfg @@ -0,0 +1,32 @@ +% ---------------------------------------------------------------------------- +% the EXSHEETS package +% +% Yet another package for the creation of exercise sheets +% +% ---------------------------------------------------------------------------- +% Clemens Niederberger +% Web: http://www.mychemistry.eu/forums/forum/exsheets +% E-Mail: contact@mychemistry.eu +% ---------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% ---------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% ---------------------------------------------------------------------------- +\ProvidesFile{exsheets_configurations.cfg} + +% Put your definitions and configurations here. + +\endinput diff --git a/macros/latex/contrib/exsheets/exsheets_en.pdf b/macros/latex/contrib/exsheets/exsheets_en.pdf Binary files differnew file mode 100644 index 0000000000..56e3247c0d --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets_en.pdf diff --git a/macros/latex/contrib/exsheets/exsheets_en.tex b/macros/latex/contrib/exsheets/exsheets_en.tex new file mode 100644 index 0000000000..d79c5de063 --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets_en.tex @@ -0,0 +1,2650 @@ +% !arara: pdflatex +% !arara: biber +% arara: pdflatex +% arara: pdflatex +% arara: pdflatex +% -------------------------------------------------------------------------- +% the EXSHEETS package +% +% Yet another package for the creation of exercise sheets +% +% -------------------------------------------------------------------------- +% Clemens Niederberger +% Web: http://www.mychemistry.eu/forums/forum/exsheets/ +% E-Mail: contact@mychemistry.eu +% -------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% -------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% -------------------------------------------------------------------------- +\documentclass[load-preamble+]{cnltx-doc} + +\usepackage{exsheets} +\usepackage{bookmark} + +\setcnltx{ + package = {exsheets} , + authors = Clemens Niederberger , + email = contact@mychemistry.eu , + url = {http://www.mychemistry.eu/forums/forum/exsheets/} , + title = the \ExSheets\ bundle , + info = {% + the packages \ExSheets{} and \ExSheetslistings \\ + \emph{or}\\ + Yet another package for the creation of exercise sheets and exams.% + } , + module-sep = {\,>>\,} , + index-setup = { othercode=\footnotesize,level=\section} , + abstract = {% + \ExSheets\ provides means to create exercises or questions and their + corresponding solutions. The questions can be divided into classes and + can be printed selectively. Meta-data to questions can be added and + recovered. + \par + The solutions may be printed where they are, can be collected and printed + at a later point in the document alltogether or section-wise or + selectively by \acs{id}.\par + \ExSheets\ provides a comprehensive interface for styling the headings of + questions and solutions.% + } , + add-cmds = { + % exsheets: + addpoints, + blank, + C, + checkedchoicebox,choice,choicebox, + correct, + CurrentQuestionID, + DebugExSheets, + DeclareExSheetsHeadingContainer, + DeclareQuestionClass,DeclareQuestionProperty, + examspace, + exlabel, + ForEachQuestion, + GetQuestionClass, + GetQuestionProperty, + grade, + includequestions,iflastquestion, + IfQuestionPropertyF,IfQuestionPropertyT,IfQuestionPropertyTF, + IfQuestionSubtitleF,IfQuestionSubtitleT,IfQuestionSubtitleTF, + lastvariant, + NewQuSolPair,NewLstQuSolPair, + numberofquestions, + points,pointssum, + PrintIfIncludeActiveF,PrintIfIncludeActiveT,PrintIfIncludeActiveTF, + PrintQuestionClassF,PrintQuestionClassT,PrintQuestionClassTF, + printsolutions, + PrintSolutionsF,PrintSolutionsTF,PrintSolutionsT, + questionsincludedlast,QuestionNumber,RenewQuSolPair, + S, + SetQuestionProperties, + SetupExSheets, + SetVariations, + startnewitemline, + sumpoints, + totalpoints, + variant,vary, + % cntformats: + @cntfmts@parsed@pattern, + AddCounterPattern, + eSaveCounterPattern, + NewCounterPattern, + ReadCounterFrom, + ReadCounterPattern,ReadCounterPatternFrom, + SaveCounterPattern, + % tasks: + NewTasks, + settasks, + task + } , + add-envs = { + question, + solution, + tasks + } , + add-silent-cmds = { + acs, + bigstar,bottomrule, + citetitle,cs,color, + DeclareInstance,DeclareTemplateInterface, + endmdframed,endspacing, + keyis, + leftthumbsup, + mdframed,midrule, + rightarrow,rlap, + s,sample,setlength, + spacing,square, + tabcolsep, + textcite, + textcolor, + tmpa,tmpb, + toprule + } +} +\usepackage{exsheets-listings} + +\microtypesetup{tracking=scshape} + +\defbibheading{bibliography}[\bibname]{\section{#1}} + +\usepackage[biblatex]{embrac}[2012/06/29] + \ChangeEmph{[}[,.02em]{]}[.055em,-.08em] + \ChangeEmph{(}[-.01em,.04em]{)}[.04em,-.05em] +\usepackage{booktabs,array,ragged2e} + +\newpackagename\ExSheets{ExSheets} +\newpackagename\ExSheetslistings{ExSheets-listings} +\newpackagename\cntformats{cntformats} +\newpackagename\Tasks{tasks} + +% ---------------------------------------------------------------------------- +% other packages, bibliography, index +\usepackage{xcoffins,wasysym,enumitem,siunitx} + +\usepackage[accsupp]{acro} +\DeclareAcronym{faq}{ + short = faq , + long = Frequently Asked Questions , + format = \scshape , + pdfstring = FAQ , + accsupp = FAQ +} +\DeclareAcronym{id}{ + short = id , + long = Identifier , + format = \scshape , + pdfstring = ID , + accsupp = ID +} +\DeclareAcronym{ctan}{ + short = ctan , + long = Comprehensive \TeX\ Archive Network , + format = \scshape , + pdfstring = CTAN , + accsupp = CTAN +} + +\usepackage{filecontents} + +\usepackage{csquotes} + +\addbibresource{biblatex-examples.bib} +\addbibresource{\jobname.bib} + +\begin{filecontents*}{\jobname.bib} +@online{tex.sx:131546, + title = {Fixing lstlisting inside \ExSheets\ \code{question} and + \code{solution} environments} , + author = {Stefano Bragaglia} , + url = {http://tex.stackexchange.com/q/131546/5049} , + date = {2013-09-04} , + urldate = {2013-09-22} +} +@online{tex.sx:133907, + title = {How do I extract repeated functionality (\ExSheets\ workaround) to + make it reusable?} , + author = {Forkrul Assail} , + url = {http://tex.stackexchange.com/q/133907/5049} , + date = {2013-09-18} , + urldate = {2013-09-22} +} +\end{filecontents*} + +% ---------------------------------------------------------------------------- +% example definitions that have to be done in the preamble: +\DeclareQuestionClass{difficulty}{difficulties} +\DeclareQuestionProperty{notes} +\DeclareQuestionProperty{reference} +\DeclareQuestionProperty{topic} + +\DeclareRelGrades{ + 1 = 1 , + {1,5} = .9167 , + 2 = .8333 , + {2,5} = .75 , + 3 = .6667 , + {3,5} = .5833 , + 4 = .5 +} + +\usepackage{amssymb} +\let\checkmark\relax +\usepackage{dingbat} + +\DeclareRobustCommand*\questionstar{\texorpdfstring{\bonusquestionsign}{* }} +\DeclareRobustCommand*\bonusquestionsign{\llap{$\bigstar$\space}} + +\NewQuSolPair + {question*}[name=\questionstar Bonus Question] + {solution*}[name=\questionstar Solution] + +\NewTasks[style=multiplechoice]{multiplechoice}[\choice](3) +\newcommand*\correct{\PrintSolutionsTF{\checkedchoicebox}{\choicebox}} + +\usepackage{alphalph} +\NewPatternFormat{aa}{\alphalph} +\NewCounterPattern{testa}{ta} + +% \AfterPackage!{hyperref}{% +% \pdfstringdefDisableCommands{\def\questionstar{* }}% +% } + +\begin{document} + +\part{Preliminaries} +\section{Licence and Requirements} +\license + +\ExSheets\ loads and needs the following packages: +\needpackage{l3kernel}~\cite{bnd:l3kernel}, \pkg{xparse}, \pkg{xtemplate}, +\pkg{l3keys2e}\footnote{all three \CTANurl{l3packages}}~\cite{bnd:l3packages}, +\pkg{l3sort}\footnote{\CTANurl{l3experimental}}~\cite{bnd:l3experimental}, +\needpackage{xcolor}~\cite{pkg:xcolor}, \needpackage{ulem}~\cite{pkg:ulem}, +\needpackage{etoolbox}~\cite{pkg:etoolbox}, +\needpackage{environ}~\cite{pkg:environ}, and +\pkg{pgfcore}\footnote{\CTANurl[graphics]{pgf}}~\cite{pkg:pgf}. \ExSheets\ +calls \cs*{normalem} (from the \pkg{ulem} package). + +\section{Motivation} +There are already quite a number of packages that allow the creation of +exercise sheets or written exams. Just to name the most common ones: +\pkg{eqexam}~\cite{pkg:eqexam}, \pkg{exam}~\cite{cls:exam}, +\pkg{examdesign}~\cite{pkg:examdesign}, \pkg{exercise}~\cite{pkg:exercise}, +\pkg{probsoln}~\cite{pkg:probsoln}, \pkg{answers}~\cite{pkg:answers}, +\pkg{esami}~\cite{pkg:esami}, \pkg{exsol}~\cite{pkg:exsol} (and many +more \ldots). + +One thing I missed in all packages that I've tried out\footnote{Well, probably + I didn't try hard enough\ldots} was a high flexibility in choosing which +questions and solutions should be printed, where which solutions should be +printed and so on, combined with the possibility to assign questions to +different classes so one could for example create two versions of an exam out +of the box. And --~I can't get enough~-- I also want to be able to use/design +different layouts for questions additional to a standard section-like format. +All these points are realized in \ExSheets. + +Additionally one should be able to assign some sort of meta-data to questions +that of course should be easily reusable. How this can be done is explained +in section~\ref{sec:additional_info}. + +Then there is --~at least in Germany~-- the habit of having lists of exercises +aligned in columns but counting from the left to the right instead from up to +down. That's why the \pkg{tasks} package was developed as part of \ExSheets{} +and was distributed as part of the bundle\changedversion{0.15}. Now it is a +package of its own but is loaded by \ExSheets{} automatically with the +necessary setup to make them work together nicely. + +\ExSheets{} has no native support for multiple choice tests but that doesn't +mean that you can't create them with \ExSheets. It just means that they may +be a bit more work with \ExSheets{} than with other packages. + +I had the idea for this package in 2008. Back then my \TeX{} skills were by +far not good enough to write it. Actually, even today I wouldn't have been +able to realize it without all the l3 packages like \pkg{l3kernel} and +\pkg{l3packages}. I actively began to develop \ExSheets\ in spring~2011 but +it wasn't until now (September~2012) that I consider it stable enough for +wider usage. At the time of writing (\today) there still are probably lots of +rough edges let alone bugs so I am very interested in all kinds of feedback. + +\section{Additional Packages} +\ExSheets\ actually bundles two packages: \ExSheets, \ExSheetslistings. +\ExSheetslistings\ is an add-on to \ExSheets\ that offers some functionality +to use \pkg{listings} with \ExSheets. It is presented in +part~\ref{part:listings}. + +\ExSheets\ used to bundle the \pkg{translations} package, +too\changedversion{0.9i}, but doesn't any more. You can find the +\pkg{translations} package as a package of it's own on the \ac{ctan}. It also +used to bundle the packages \pkg{tasks} and +\pkg{cntformats}\changedversion{0.15}. They're available now as packages of +their own as well. + +% \section{Installation and Documentation} +% If you install \ExSheets\ manually beware to put the files +% \begin{itemize} +% \item[]\verb+exsheets_headings.def+ +% \item[]\verb+exsheets_headings.cfg+ +% \end{itemize} +% in the same directory as the \code{exsheets.sty} file\footnote{That is, a +% directory like \code{texmf-local/tex/latex/exsheets}, probably}. + +% As with every manual package installation you need to make sure to put the +% files in a directory where \TeX\ can find them and afterwards update the +% database. + +% \subsection{The \pkg*{tasks} Package} +% The \pkg{tasks} package~\cite{pkg:tasks} used to be part of the \ExSheets\ +% bundle but is a package of its own now\changedversion{0.15} and released +% independently. You can find it as every other package on \ctan\ and in a full +% \TeX~Live or \hologo{MiKTeX} installation. + +% \subsection{The \pkg*{cntformats} Package} +% The \pkg{cntformats} package~\cite{pkg:cntformats} used to be part of the +% \ExSheets\ bundle but is a package of its own now\changedversion{0.15} and +% released independently. You can find it as every other package on \ctan\ and +% in a full \TeX~Live or \hologo{MiKTeX} installation. + +% \subsection{The \pkg*{translations} Package} +% The \pkg{translations} package~\cite{pkg:translations} used to be part of the +% \ExSheets\ bundle but is a package of its own now\changedversion{0.9i} and +% released independently. You can find it as every other package on \ctan\ and +% in a full \TeX~Live or \hologo{MiKTeX} installation. + +% \section{News} +% \begin{description} +% \item[Version 0.7] +% With version~0.7 there has been a potentially breaking change: the +% \code{tasks} environment previously provided by \ExSheets\ has been +% extracted into a package of its own. This does not change any syntax +% \emph{per se}. However, if you used custom settings then you'll probably run +% into some problems. The options for the environment are no longer set with +% \cs{SetupExSheets} but with \cs{settasks}. Also the object that is used for +% the list template and its instances has been renamed from +% \code{exsheets-tasks} into \code{tasks}. + +% What's probably even more of a breaking change is a syntax difference of the +% \code{tasks} environment: the optional argument for the number of columns is +% \emph{no longer set in braces but parentheses}. This is deliberate as it +% reflects the optional nature of the argument better and is consistent with +% the syntax of \cs{NewTasks}, too. + +% Additionally the labels of the list got an additional offset of \code{1ex} +% from the items which will lead to slightly different output. In some cases +% this might actually lead to the most annoying changes. In this case say +% \cs{settasks}\Marg{label-offset=0pt} which should cure things again. + +% I am very sorry for any inconvenience! I am trying to keep such changes as +% minimal and rare as possibly. However, it is not always avoidable when a +% package is new and still a child. It will grow up eventually. + +% \ExSheets' other packages -- \href{tasks_en.pdf}{\Tasks} and +% \href{cntformats_en.pdf}{\cntformats} -- have gotten their own documentation +% which are essentially extracted from this very document you're reading now. +% This manual contains links to the respective manuals. + +% \item[Version v0.9i] +% The \pkg{translations} package~\cite{pkg:translations} is no longer part of +% the \ExSheets\ bundle. From now on (July~17.\@ 2013) it is provided as a +% package of its own. + +% \item[Version 0.10] +% The \ExSheets\ family has got a new member: \ExSheetslistings. This package +% proposes a solution for the problem of using verbatim material in \ExSheets' +% \env{question} and \env{solution} environments. It is presented in +% part~\ref{part:listings}. + +% Question now can get subtitles that are printed if the heading instance +% supports it, see section~\ref{sec:subtitles-questions}. + +% \item[Version 0.11] +% The commands \cs{GetQuestionClass} and \cs{PrintQuestionClassTF} have been +% added. They're explained in section~\ref{sec:retr-class-value}. + +% \item[Version 0.12] +% The \option{auto-label} is now more flexible to allow the use together with +% packages \pkg{cleveref}. + +% Question properties can now be retrieved before the question is printed (by +% writing the properties to the \code{aux} file). + +% \item[Version 0.13] +% New options: +% \begin{itemize} +% \item \option{chapter-hook} allows to add code to the list of solutions +% when the solutions of a new chapter are printed, see +% section~\ref{sec:solutions-print-all}. +% \item \option{section-hook} allows to add code to the list of solutions +% when the solutions of a new section are printed, see +% section~\ref{sec:solutions-print-all}. +% \end{itemize} + +% \item[Version 0.14] +% New options: +% \begin{itemize} +% \item New option \option{pre-hook} to the \env{question} environment that +% allows to add code directly before the question body, see +% section~\ref{sec:opti-ques-envir}. +% \item New option \option{post-hook} to the \env{question} environment that +% allows to add code directly after the question body, see +% section~\ref{sec:opti-ques-envir}. +% \item New command \cs{ExSheetsHeading}, see +% section~\ref{sec:using-an-exsheets}. +% \item New pre-defined question properties \code{question-body}, +% \code{bonus-points} and \code{counter}, see +% section~\ref{sec:additional_info}. +% \item New option \option{save-to-aux}, see +% section~\ref{sec:additional_info}. +% \end{itemize} + +% \item[Version 0.15] +% \begin{itemize} +% \item The packages \pkg{tasks} and \pkg{cntformats} have been removed from +% the bundle and are now distributed as packages of their own. +% \item The options \option*{load-headings} and \option*{load-tasks} have +% been dropped. The optional functionality they provided is now provided +% all the time. +% \item New command \cs{IfQuestionPropertyTF}, see +% section~\ref{sec:additional_info}. +% \end{itemize} + +% \item[Version 0.16] +% New options/changes: +% \begin{itemize} +% \item The option \option{pre-hook} to the \env{question} environment now +% places its contents before the question heading, see +% section~\ref{sec:opti-ques-envir}. +% \item New option \option{pre-body-hook} to the \env{question} environment +% which adds its contents before the question body, see +% section~\ref{sec:opti-ques-envir}. +% \item New option \option{post-body-hook} to the \env{question} environment +% which adds its contents after the question body, see +% section~\ref{sec:opti-ques-envir}. +% \item New option \option{pre-hook} to the \env{solution} environment which +% adds code before a solution, see section~\ref{sec:opti-soli-envir}. +% \item New option \option{post-hook} to the \env{solution} environment which +% adds code after a solution, see section~\ref{sec:opti-soli-envir}. +% \item New option \option{pre-body-hook} to the \env{solution} environment +% which adds its contents before the solution body, see +% section~\ref{sec:opti-soli-envir}. +% \item New option \option{post-body-hook} to the \env{solution} environment +% which adds its contents after the solution body, see +% section~\ref{sec:opti-soli-envir}. +% \end{itemize} + +% \item[Version 0.17] +% New option: +% \begin{itemize} +% \item The option \option{use-saved-counter-format} has been introduced. It +% is described in section~\ref{sec:solutions} on +% page~\pageref{option:use-saved-counter-format}. +% \end{itemize} + +% \item[Version 0.18] +% The package now provides the correct Danish translations, thanks to Jonas +% Nyrup. + +% The macro \cs{exsheetsprintsolution} is introduced, see +% page~\pageref{exsheetsprintsolution} for a little bit of an explanation. + +% The option \option{no-skip-below} is introduced which disables the insertion +% of vertical space after the question and solution environments. + +% \item[Version 0.20] +% New command \cs{DeclareExSheetsHeadingContainer}. + +% \item[Version 0.21] Changes: +% \begin{itemize} +% \item \cs{includequestions} issues an error if it can't find the file to +% include. +% \item question properties are now also accessable when the corresponding +% question isn't printed. +% \item The variables \verbcode+\l_exsheets_counter_qu_int+ and \\ +% \verbcode+\g_exsheets_question_identification_prop+ are now public. +% \end{itemize} +% \end{description} + +\section{Thanks} +I need to thank the many users who gave me feedback so far! For one thing +this shows me that \ExSheets\ is useful to people. It also led to many +improvements like new features and countless bug fixes. + +\part{The \ExSheets\ package}\label{part:exsheets} +\section{Setup} +The \ExSheets\ package has three different types of options, kind of. The +first type are the classic package options which are used when you load +\ExSheets: +\begin{sourcecode} + \usepackage[<options>]{exsheets} +\end{sourcecode} +All general options can be used this way and most of them are described in +section~\ref{sec:options}. All of those options also can be set via the setup +command: +\begin{commands} + \command{SetupExSheets}[\oarg{module}\marg{options}] +\end{commands} + +The second type are options that belong to a specific environment or command. +These options are either used directly with the environment/command +\begin{sourcecode} + \begin{env}[<options>] + ... + \end{env} +\end{sourcecode} +or can also be set with the setup command. In the first case they only act +upon the environment or command where they're used. In the second case they +are set for all following uses of the corresponding environment or command. + +The options of the second type all belong to \module*{modules}. Let's say you +want to specify some options of the \env{question} environment. You can then +say the following: +\begin{sourcecode} + \SetupExSheets[question]{option1,option2=value2} + % or: + \SetupExSheets{question/option1,question/option2=value2} +\end{sourcecode} +The \module*{module} an option belongs to is written in the left margin next +to the when the option is described. + +The third type aren't options at all, actually. However, thanks to the great +\pkg{xtemplate} package you are able to define your own instances of some of +the objects used by \ExSheets. This is explained in a little more detail in +part~\ref{part:style} on page~\pageref{part:style}\,ff. This third type, +however, brings in a possible instability: the \pkg{xtemplate} package is in +an experimental and developing state. This means that the sytax of the +package may and possibly will change sometime in the future. I cannot foresee +what any consequences of that will be for \ExSheets. + +\section{General Options}\label{sec:options} +The package \ExSheets\ has some options, namely the following ones: +\begin{options} + %% counter-format + \keyval{counter-format}{counter-format}\Default{qu.} + Formatting of the counter of the questions. This option takes a special + kind of string that is described in section~\ref{ssec:counter}. + \keyval{counter-within}{counter}\Default + Resets the \code{question} counter with every step of \meta{counter}. + %% auto-label + \keybool{auto-label}\Default{false} + If set to \code{true} \ExSheets\ will automatically place a + \cs*{label}\Marg{qu:\meta{id}} for each question. See + section~\ref{sec:auto-label-opti} for ways to customize this. It will + also create the question properties \code{ref} and \code{pageref}, see + section~\ref{sec:additional_info} for more on this. + %% headings + \keyval{headings}{instance}\Default{block} + Choose the style of the questions' and solutions' headings. There are two + predefined styles: \code{block} and \code{runin}. + %% headings-format + \keyval{headings-format}{code}\Default{\cs*{normalsize}\cs*{bfseries}} + This code is placed immediately before the headings of the questions and + solutions. + \keyval{subtitle-format}{code}\Default{\cs*{normalsize}\cs*{itshape}} + This code is placed immediately before the subtitle of the questions and + solutions. It only has an effect with a title instance that uses the + subtitle coffin, see section~\ref{sec:exsheets-headings}. + % skip-below + \keyval{skip-below}{dim}\Default{.5\cs*{baselineskip}} + \sinceversion{0.18}Sets the vertical space that is inserted after the + question and solution environments. + % no-skip-below + \keybool{no-skip-below}\Default{false} + \sinceversion{0.18}Disables the insertion of vertical space after the + question and solution environments. + %% totoc + \keybool{totoc}\Default{false} + This option adds the questions and solutions with their names and numbers + to the table of contents. + %% questions-totoc + \keybool{questions-totoc}\Default{false} + This option adds the questions with their names and numbers to the table + of contents. + %% solutions-totoc + \keybool{solutions-totoc}\Default{false} + This option adds the solutions with their names and numbers to the table + of contents. + %% toc-level + \keyval{toc-level}{toc level}\Default{subsection} + This option sets the level in which questions and solutions should appear + in the table of contents. + %% questions-toc-level + \keyval{questions-toc-level}{toc level}\Default{subsection} + This option sets the level in which questions should appear in the table + of contents. + %% solutions-toc-level + \keyval{solutions-toc-level}{toc level}\Default{subsection} + This option sets the level in which solutions should appear in the table + of contents. + %% use-ref + \keybool{use-ref}\Default{false} + enable referencing to sections and chapters in a way that the references + can be used with \cs{printsolutions}, see + section~\ref{sssec:print_specific_section} for details. +\end{options} +The \code{toc} options are demonstrated with section~\ref{sec:solutions:list} +and the solutions printed there being listed in the table of contents. + + +\section{Create Questions/Exercises and their Solutions} +Now, let's start with the most important part: the questions and (possibly) +their respective solutions. +\subsection{The \env*{question} Environment}\label{ssec:questions} +Questions are written inside the \env{question} environment: +\begin{environments} + \environment{question}[\oarg{options}\marg{points}] + The main environment: creates a new exercise/question. Both arguments are + optional! +\end{environments} +\begin{example} + \begin{question} + This is our very first very difficult to solve question! + \end{question} +\end{example} +As you can see a heading is automatically created and the question is +numbered. You can of course change both the numbering and the naming, but +more on that later. + +The \env{question} environment takes an optional argument \marg{points} that +can be used to assign points to the question (as is common in written exams): +\begin{example} + \begin{question}{3} + This is our first difficult question that is worth 3 points! + \end{question} +\end{example} +These points are saved internally (see section~\ref{sec:points} for reasons +why) and are written to the right margin next to the question heading in the +default setting. + +You can also assign bonus points by inserting \code{\meta{point}+\meta{bonus + points}} as argument. +\begin{example} + \begin{question}{1+1} + This question is worth 1 point and 1 bonus point. + \end{question} + \begin{question}{+3} + This question is a bonus question. It is worth 3 bonus points. + \end{question} +\end{example} + +The points are counted and added to the total sum of points, see +section~\ref{sec:points} for details on this. \sinceversion{0.12}Should you +want that the points of a specific question \emph{should not be added} to the +total sum then precede it with a bang \code{!}: +\begin{example} + \begin{question}{!3} + This question's points won't be added to the total sum. + \end{question} +\end{example} +Beware that this also prevents bonus points. The points simply will be +written where the heading instance puts them. + +\sinceversion{0.3}One additional thing: you might want to define custom +commands that should behave differently if they're inside or outside of the +\env{question} environment. In this case you can use these commands: +\begin{commands} + \expandable\command{IfInsideQuestionTF}[\marg{true code}\marg{false code}] + Check if inside of a question and either leave \meta{true code} or + \meta{false code} in the input stream. + \expandable\command{IfInsideQuestionT}[\marg{true code}] + Check if inside of a question and either leave \meta{true code} in the + input stream if true. + \expandable\command{IfInsideQuestionF}[\marg{false code}] + Check if inside of a question and either leave \meta{false code} in the + input stream if not. +\end{commands} + +\subsection{Options to the \env*{question} Environment}\label{sec:opti-ques-envir} +The \env{question} environment takes one or more of the following options: +\begin{options} + \keychoice{type}{exam,exercise}\Module{question}\Default{exercise} + Determines the type of question and changes the default name of a question + from ``Exercise'' to ``Question''. These default names are language + dependent.\par + If you use \cs*{usepackage}\oarg{ngerman}\marg{babel}, for example, then + the names are ``Übung'' and ``Aufgabe''. + \keyval{name}{name}\Module{question}\Default + Sets a custom name. All predefined names are discarded. + \keyval{subtitle}{subtitle}\Module{question}\Default + Adds a subtitle \meta{subtitle} for the question that is used by headings + instances that make use of the subtitle coffin, see + section~\ref{sec:exsheets-headings}. + \keyval{skip-below}{dim}\Module{question}\Default{.5\cs*{baselineskip}} + \sinceversion{0.18}Sets the vertical space that is inserted after the + question environment. + \keybool{no-skip-below}\Module{question}\Default{false} + \sinceversion{0.18}Disables the insertion of vertical space after the + question environment. + \keybool{print}\Module{question}\Default{true} + Prints or hides the question. + \keyval{ID}{id}\Module{question}\Default + Assigns a custom \acs{id} to the question. See section~\ref{ssec:ids} for + further information. + \keyval{label}{label}\Module{question}\Default + Places a \cs*{label}\marg{label} for the question. This will overwrite + any label that is placed by the \option{auto-label} option. + \keyval{class}{class}\Module{question}\Default + Assigns a class \meta{class} to the question. See + section~\ref{sec:classes} for further information. + \keyval{topic}{topic}\Module{question}\Default + Assigns a topic \meta{topic} to the question. See + section~\ref{sec:topics} for further information. + \keybool{use}\Module{question}\Default{true} + Discards the question. Or not. + \keyval{pre-hook}{code}\Module{question}\Default + \changedversion{0.16}Adds \meta{code} directly before the question title. + \keyval{post-hook}{code}\Module{question}\Default + \changedversion{0.16}Adds \meta{code} directly after the question. + \keyval{pre-body-hook}{code}\Module{question}\Default + \sinceversion{0.16}Adds \meta{code} directly before the question body. + \keyval{post-body-hook}{code}\Module{question}\Default + \sinceversion{0.16}Adds \meta{code} directly after the question body. +\end{options} + +\begin{example} + \begin{question}[type=exam] + This question has the type \keyis{type}{exam}. The default name has changed + from ``Exercise'' to ``Question''. + \end{question} + \begin{question}[name=Fancy name] + This question has a custom name. + \end{question} + \begin{question}[print=false] + This question is not printed. + \end{question} +\end{example} + +The difference between \option{print} and \option{use} lies behind the scenes: +with \keyis{print}{false} the question is not printed, but it still gets an +individual \ac{id}, is numbered, and a possible solution is saved. This is +for example useful when you want to print a sample solution for an exam. With +\keyis{use}{false} it is fully discarded which means it is not accessible +through an \acs{id} and a possible solution will not be saved. + +\subsection{Subtitles to Questions}\label{sec:subtitles-questions} +The \option{subtitle} option mentioned in section~\ref{sec:opti-ques-envir} +can be used to add a subtitle to a question. However, unless you choose a +suitable heading (see section~\ref{sec:exsheets-headings}) it won't be +printed. Currently there is \emph{one} heading instance that uses the +subtitles but it should be easy to create a custom heading using one of the +existing ones as a starter example. When creating such a heading you may want +to distinguish between the cases when a subtitle has been given and when no +subtitle is present. This can be done with the following commands: +\begin{commands} + \expandable\command{IfQuestionSubtitleTF}[\marg{true code}\marg{false code}] + Tests if the current question has a subtitle. Leaves either \meta{true + code} or \meta{false code} in the input stream. + \expandable\command{IfQuestionSubtitleT}[\marg{true code}] + Tests if the current question has a subtitle. Leaves \meta{true code} in + the input stream if it has. + \expandable\command{IfQuestionSubtitleF}[\marg{false code}] + Tests if the current question has a subtitle. Leaves \meta{false code} in + the input stream if it hasn't. +\end{commands} + +A subtitle is also a property of a question in the sense of +section~\ref{sec:additional_info}. That means if a subtitle is given it can +be retrieved with \cs{GetQuestionProperty}. + +As an example you could define your own heading instance that prints the +\acs{id} of a question and (if given) the subtitle: + +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{QE}{default}{ + join = { + title[r,B]number[l,B](.333em,0pt) ; + title[r,B]subtitle[l,B](1em,0pt) + } , + attach = { + main[l,vc]title[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } , + subtitle-post-code = {ID: \CurrentQuestionID} , + number-post-code = {\IfQuestionSubtitleF{ID: \CurrentQuestionID}} + } +\end{sourcecode} + +Please see section~\ref{sec:exsheets-headings} for more details on heading +instances. + +\subsection{The \env*{solution} Environment} +If you want to save/print (more on the exact usage in +section~\ref{sec:solutions}) a solution you have to use the \env{solution} +environment \emph{after} the question it belongs to and \emph{before} the next +question. +\begin{environments} + \environment{solution}[\oarg{options}] + The main environment for adding solutions to exercises/questions. +\end{environments} +\begin{example} + \begin{question}[ID=first]\label{qu:question_with_solution} + This is our first question that gets a solution! + \end{question} + \begin{solution} + This is the solution to exercise~\ref{qu:question_with_solution}! + \end{solution} +\end{example} +You can see that in the default settings the solution is \emph{not} written to +the document. It has been saved, though, for possible later usage. We will +see the solution later! + +\subsection{Options to the \env*{solution} Environment}\label{sec:opti-soli-envir} +The \env{solutions} environment also has options, namely these: +\begin{options} + \keyval{name}{name}\Module{solution}\Default + Sets a custom name. + \keybool{print}\Module{solution}\Default{false} + Prints or hides the solution. + \keyval{skip-below}{dim}\Module{solution}\Default{.5\cs*{baselineskip}} + \sinceversion{0.18}Sets the vertical space that is inserted after the + solution environment. + \keybool{no-skip-below}\Module{solution}\Default{false} + \sinceversion{0.18}Disables the insertion of vertical space after the + solution environment. + \keyval{pre-hook}{code}\Module{solution}\Default + \sinceversion{0.16}Adds \meta{code} directly before the solution title. + \keyval{post-hook}{code}\Module{solution}\Default + \sinceversion{0.16}Adds \meta{code} directly after the solution. + \keyval{pre-body-hook}{code}\Module{solution}\Default + \sinceversion{0.16}Adds \meta{code} directly before the solution body. + \keyval{post-body-hook}{code}\Module{solution}\Default + \sinceversion{0.16}Adds \meta{code} directly after the solution body. +\end{options} +Their meaning is the same as those for the \code{question} environment. +\begin{example} + \begin{question}{5} + The solution to this questions gets printed where it is. + \end{question} + \begin{solution}[print] + See? This solution gets printed where you have put it in the code of + your document. + \end{solution} + \begin{question}{2.5} + The solution to this questions gets printed where it is \emph{and} + has a fancy name. Have you noticed that you can assign partial + points? + \end{question} + \begin{solution}[print,name=Fancy name] + See? This solution gets printed where you have put it and has a fancy + name! + \end{solution} +\end{example} + +\subsection{Setting the Counter}\label{ssec:counter} +The package option \option{counter-format} allows you to specify how the question +counter (a counter unsurprisingly name \code{question}) is formatted. + +The input is an arbitrary string which means you can have anything as counter +number. However, the letter combinations \code{ch}, \code{se}, \code{qu} and +\code{tsk} are replaced with the counters for the chapter, section, question +or tasks (see the \Tasks\ package), respectively. While the last one is not +really useful in this case the others allow for a combined numbering. Each of +these letter combinations can have an optional argument that specifies the +format of the respective counter. \code{1}: \cs*{arabic}, \code{a}: +\cs*{alph}, \code{A}: \cs*{Alph}, \code{r}: \cs*{roman} and \code{R}: +\cs*{Roman}. +\begin{example} + \SetupExSheets{counter-format=Nr~se~(qu[a])} + \begin{question} + A question with a differently formatted number. + \end{question} +\end{example} +Since the strings associated with the counters are replaced one has to hide +them if they are actually wanted in the counter format. The easiest way would +to hide them in braces. +\begin{example} + \SetupExSheets{counter-format={section}\,se~{question}\,(qu[a])} + \begin{question} + A question with a yet differently formatted number. + \end{question} +\end{example} + +\subsection{Language Settings} +The names of the questions and solutions are language dependent. If you use +\pkg{babel} or \pkg{polyglossia} \ExSheets\ will adapt to the document language. +\ExSheets\ has a number of translations but surely not all! If you miss a +language please drop me a line in an +email\footnote{\href{mailto:contact@mychemistry.eu}{contact@mychemistry.eu}} +containing the \pkg{babel} language name and the correct translations for +questions (possibly distinguishing between exercises and exam questions) and +solutions. + +Until I implement it you can add something like this to your preamble (example +for Danish) and try if it works: +\begin{sourcecode} + \DeclareTranslation{Danish}{exsheets-exercise-name}{\O{}velse} + \DeclareTranslation{Danish}{exsheets-question-name}{Opgave} + \DeclareTranslation{Danish}{exsheets-solution-name}{Opl\o{}sning} +\end{sourcecode} +If this isn't working it means that the language you're using is unknown to +the \pkg{translations} package. In this case please notify me, too. You then +can still use the \option{name} options. + +\section{Counting Points}\label{sec:points} +\subsection{The Commands} +You have seen in section~\ref{ssec:questions} that you can assign points to a +question. If you do so these points are printed into the +margin\footnote{Well, not necessarily. It depends on the heading style you + have chosen.} and are counted internally. But there are additional commands +to assign points or bonus points and a number of commands to retrieve the sum +of points and/or bonus points. +\begin{commands} + \command{addpoints}[\sarg\marg{num}] + This command can be used to add points assigned to subquestions. + \cs{addpoints} will print the points (with ``unit'') \emph{and} add them + to the sum of all points, \cs{addpoints}\sarg\ will only add them but print + nothing. + \command{points}[\sarg\marg{num}] + This command will only print the points (with ``unit'') but won't add them + to the sum of points. + \command{addbonus}[\sarg\marg{num}] + This command can be used to add bonus points assigned to subquestions. + \cs{addbonus} will print the points (with ``unit'') \emph{and} add them + to the sum of all bonus points, \cs{addbonus}\sarg\ will only add them but + print nothing. + \command{bonus}[\sarg\marg{num}] + This command will only print the bonus points (with ``unit'') but won't + add them to the sum of bonus points. + \command{pointssum}[\sarg] + Prints the sum of all points with or without (starred version) ``unit'': + \pointssum + \command{currentpointssum}[\sarg] + Prints the current sum of points with or without (starred version) + ``unit'': \currentpointssum + \command{bonussum}[\sarg] + Prints the sum of all bonus points with or without (starred version) + ``unit'': \bonussum + \command{currentbonussum}[\sarg] + Prints the current sum of bonus points with or without (starred version) + ``unit'': \currentbonussum + \command{totalpoints}[\sarg] + prints the sum of the points \emph{and} the sum of the bonus points with + ``unit'': \totalpoints\space The starred version prints the sum of the + points without ``unit'': \totalpoints*. +\end{commands} +The commands \cs{pointssum}, \cs{bonussum} and \cs{totalpoints} need at +least \emph{two} \LaTeX\ runs to get the sum right. + +Suppose you have an exercise worth \points{4} which consists of four questions +listed with an \env{enumerate} environment that are all worth \points{1} +each. You have two possibilities to display and count them: +\begin{example} + % uses package `enumitem' + \begin{question}{4} + \begin{enumerate}[label=\alph*)] + \item blah (\points{1}) + \item blah (\points{1}) + \item blah (\points{1}) + \item blah (\points{1}) + \end{enumerate} + \end{question} + \begin{question} + \begin{enumerate}[label=\alph*)] + \item blah (\addpoints{1}) + \item blah (\addpoints{1}) + \item blah (\addpoints{1}) + \item blah (\addpoints{1}) + \end{enumerate} + \end{question} +\end{example} + +\subsection{Options} +\begin{options} + \keyval{name}{name}\Module{points}\Default{P.} + Choose the ``unit'' for the points. If you like to differentiate between + a single point and more than one point you can give a plural ending + separated with a slash: \keyis{name}{point/s}. This sets also the name of + the bonus points. + \keyval{name-plural}{plural form of name}\Module{points}\Default + Instead of forming the plural form with an ending to the singular form + this option allows to set an extra word for it. This sets also the plural + form for the bonus points. + \keyval{bonus-name}{name}\Module{points}\Default{P.} + Choose the ``unit'' for the bonus points. If you like to differentiate + between a single point and more than one point you can give a plural + ending separated with a slash: \key{bonus-name}{point/s}. + \keyval{bonus-plural}{plural form of name}\Module{points}\Default + Instead of forming the plural form with an ending to the singular form + this option allows to set an extra word for it. + \keybool{use-name}\Module{points}\Default{true} + Don't display the name at all. Or do. + \keyval{format}{code}\Module{points}\Default{\cs*{@firtsofone}} + \sinceversion{0.9d}Format number plus name as a whole. Ideally + \meta{code} would end with a command that takes an argument. Else + number plus name will be braced. + \keyval{number-format}{any code}\Module{points}\Default + This option allows formatting of the number, \eg, italics: + \keyis{number-format}{\cs*{textit}}. + \keyval{bonus-format}{any code}\Module{points}\Default + This option allows formatting of the number of the bonus points, \eg, + italics: \keyis{bonus-format}{\cs*{textit}}. + \keybool{parse}\Module{points}\Default{true} + If set to \code{false} the points are not counted and the + \cs{totalpoints}, \cs{pointssum} and \cs{bonussum} commands won't know + their value. + \keybool{separate-bonus}\Module{points}\Default{false} + This option determines whether points and bonus points each get their own + unit when they appear together (in the margin or with \cs{totalpoints}). + \keyval{pre-bonus}{tokens}\Module{points}\Default{\cs*{space}(+} + Code to be inserted before the bonus points when they follow normal + points. + \keyval{post-bonus}{tokens}\Module{points}\Default{)} + Code to be inserted after the bonus points when they follow normal + points. +\end{options} + +\begin{example}[add-sourcecode-options={literate=}] + \SetupExSheets[points]{name=point/s,number-format=\color{red}} + \begin{question}{1} + This one's easy so only 1 point can be earned. + \end{question} + \begin{question}{7.5} + But this one's hard! 7.5 points are in there for you! + \end{question} +\end{example} + +\section{Printing Solutions}\label{sec:solutions} +You have already seen that you can print solutions where they are using the +\option{print} option. But \ExSheets\ offers you quite more +possibilities. + +In the next subsections the usage of the following command is discussed. +\begin{commands} + \command{printsolutions}[\oarg{setting}] + Print solutions of questions/exercises. +\end{commands} + +Before we do that a hint: remember that you can set the option \option{print} +globally: +\begin{sourcecode} + % in the preamble + \SetupExSheets{solution/print=true} +\end{sourcecode} + +Now if you want to typeset some text depending on the option being true or not +you can use the following commands: +\begin{commands} + \expandable\command{PrintSolutionsTF}[\marg{true code}\marg{false code}] + Either leaves \meta{true code} or \meta{false code} in the input stream + depending on wether solutions are printed or not, \ie, on the value of the + solution's option \option{print}. Inside a \env{solution} environment + this always prints \meta{true code}. + \expandable\command{PrintSolutionsT}[\marg{true code}] + Either leaves \meta{true code} or nothing in the input stream depending on + wether solutions are printed or not, \ie, on the value of the solution's + option \option{print}. Inside a \env{solution} environment this always + prints \meta{true code}. + \expandable\command{PrintSolutionsF}[\marg{false code}] + Either leaves nothing or \meta{false code} in the input stream depending + on wether solutions are printed or not, \ie, on the value of the + solution's option \option{print}. Inside a \env{solution}environment this + always prints nothing. +\end{commands} +They might come in handy if you want two versions of an exercise sheet, one +with the exercises and one with the solutions, and you want to add different +titles to these versions, for instance. + +% When solutions are saved a lot of information is saved. One of them is the +% current counter format. The following option determines wether the saved +% counter format or the currently active one is used when \cs{printsolutions} is +% called: +% \begin{options} +% \keybool{use-saved-counter-format}\Default{true} +% \changedversion{0.21}When set to true the counter format of solutions +% printed by \cs{printsolutions}\label{option:use-saved-counter-format} are +% independent from the setting of \option{counter-format}. The saved format +% is used instead. +% \end{options} + +\subsection{Print all}\label{sec:solutions-print-all} +The first and easiest usage of \cs{printsolutions} is the following: +\begin{sourcecode} + \printsolutions +\end{sourcecode} +There is nothing more to say, really. It prints all solutions you have +specified except those belonging to a question with option \keyis{use}{false}. +Yes, there's one more point: \cs{printsolutions} only knows the solutions +that have been set \emph{before} its usage! This is also true for every usage +explained in the next sections. + +\begin{example} + \printsolutions +\end{example} + +Two options allow to add code to the list of solutions when used with +\cs{printsolutions}\Oarg{all} (which is the same as using it without option): + +\begin{options} + \keyval{chapter-hook}{code} + \sinceversion{0.13}Adds \meta{code} to the list of solutions every time + solutions from a new chapter are printed (before the solutions of the + corresponding chapter are printed). + \keyval{section-hook}{code} + \sinceversion{0.13}Adds \meta{code} to the list of solutions every time + solutions from a new section are printed (before the solutions of the + corresponding section are printed). +\end{options} + +\subsection{Print per chapter/section} +\minisec{Current chapter/section} +If you are not creating an exercise sheet or an exam but are writing a +textbook you maybe want a section at the end of each chapter showing the +solution to the exercises presented in that chapter. In this case use the +command as follows: +\begin{sourcecode} + \printsolutions[section] + % or + \printsolutions[chapter] +\end{sourcecode} +Again, this is pretty much self-explaining. The solutions to the questions of +the current chapter\footnote{Only if the document class you're using + \emph{has} chapters, of course!} or section are printed. +\begin{example} + \begin{question} + This is the first and only question in this section. + \end{question} + \begin{solution} + This will be one of a few solutions printed by the following call of + \cs{printsolutions}. + \end{solution} + And now: + \printsolutions[section] +\end{example} + +\minisec{Specific chapter/section}\label{sssec:print_specific_section} +You can also print only the solutions from chapters or sections other than the +current ones. The syntax is fairly easy: +\begin{example} + \printsolutions[section={1-7,10}] + % the same for chapters: + % \printsolutions[chapter={1-7,10}] +\end{example} +Don't forget that \cs{printsolutions} cannot know the solutions from +section~10 yet. It is just used to demonstrate the syntax. You can also use +an open range, \eg, something like +\begin{sourcecode} + \printsolutions[section={-4,10-}] +\end{sourcecode} +This would print the solutions from sections~1--4 and from all sections with +number 10\footnote{Or rather where \cs*{value}\Marg{section} is 10 or greater -- + the actual counter formatting is irrelevant.} and greater. + +There is an obvious disadvantage: you have to know the section numbers! But +there is a solution: use the package option \keyis{use-ref}{true}. Then you +can do something like +\begin{sourcecode} + % in the preamble: + \usepackage[use-ref]{exsheets} + % somewhere in your code after \section{A really cool section title}: + \label{sec:ReallyCool} + % somewhere later in your code: + \printsolutions[section={-\S{sec:ReallyCool}}] + % which will print all solutions from questions up to and + % including the really cool section +\end{sourcecode} +With the package option \keyis{use-ref}{true} each usage of \cs*{label} will +create additional labels (one preceded with \code{exse:} and another one with +\code{exch:}) which store the section number and the chapter number, +respectively. These are used internally by two commands \cs{S} and \cs{C} +which refer to the section number and the chapter number the label was created +in. \emph{These commands are only available as arguments of} +\cs{printsolutions}. + +Since some packages like the well known \pkg{hyperref} for example redefine +\cs*{label} \option{use-ref} won't work in together with it. In this case +don't use \option{use-ref} and set \cs{exlabel}\marg{label} instead to +remember the section/the chapter number. Its usage is just like \cs*{label}. +So the safest way is as follows: +\begin{sourcecode} + % in the preamble: + \usepackage{exsheets} + % somewhere in your code after \section{A really cool section title}: + \exlabel{sec:ReallyCool} + % somewhere later in your code: + \printsolutions[section={-\S{sec:ReallyCool}}] + % which will print all solutions from questions up to and + % including the really cool section +\end{sourcecode} +Please be aware that the labels must be processed in a previous \LaTeX\ run +before \cs{S} and \cs{C} can pass them on to \cs{printsolutions}. + +\subsection{Print by \acs{id}}\label{ssec:ids} +Now comes the best part: you can also print selected solutions! Every +question has an \acs{id}. To see which \acs{id} a question has you can call +the following command: +\begin{commands} + % \command{DebugExSheets}[\Marg{\choices{true,false}}] + % Enable or disable visual \ExSheets' debugging. + \expandable\command{CurrentQuestionID} + \sinceversion{0.4a}Expands to the current question \acs{id}. +\end{commands} +\begin{options} + \keybool{debug} + Enable or disable visual \ExSheets' debugging. +\end{options} +Let's create some more questions and take a look what this command does: +\begin{example} + \SetupExSheets{debug=true} + \begin{question}[ID=nice!] + A question with a nice \acs{id}! + \end{question} + \begin{solution} + The solution to the question with the nice \acs{id}. + \end{solution} + \begin{question}{3.75} + Yet another question. But this time with quarter points! + \end{question} + \begin{solution} + Yet another solution. + \end{solution} +\end{example} + +So now we can call some specific solutions: +\begin{example} + \printsolutions[byID={first,nice!,10,14}] +\end{example} +This makes use of the \pkg{l3sort} package which at the time of writing is +still considered experimental. In case you wonder where solution~14 is: +question~14 has no solution given. + +If you don't want that the solutions are sorted automatically but appear in +the order given you can use the option +\begin{options} + \keybool{sorted}\Module{solution}\Default{true} + Sort solutions given by \acs{id} or don't. +\end{options} + +\section{Conditional Printing of Questions}\label{sec:cond-print-quest} +\subsection{Using Classes}\label{sec:classes} +For creating different variants of a written exam or different difficulty +levels of an exercise sheet it comes in handy if one can assign certain +classes to questions and then tell \ExSheets\ only to use one ore more +specific classes. +\begin{options} + \keyval{use-classes}{list of classes}\Default + When this option is used only the questions belonging to the specified + classes are printed and have their solutions saved. +\end{options} +\begin{example} + \SetupExSheets{use-classes={A,C}} + \begin{question}[class=A] + Belonging to class A. + \end{question} + \begin{question}[class=B] + Belonging to class B. + \end{question} + \begin{question}[class=C] + Belonging to class C! + \end{question} +\end{example} +Questions of classes that are not used are fully discarded. \emph{This also + means that questions that don't have a class assigned are discarded.} + +\ExplSyntaxOn + \bool_set_false:N \g__exsheets_use_classes_bool +\ExplSyntaxOff + +\subsection{Using Topics}\label{sec:topics} +Similarly to classes one can assign topics to questions. The usage is +practically identical, the semantic meaning is different. +\begin{options} + \keyval{use-topics}{list of topics}\Default + When this option is used only the questions belonging to the specified + topics are printed and have their solutions saved. +\end{options} +\begin{example} + \SetupExSheets{use-topics={trigonometry}} + \begin{question}[topic=trigonometry] + A trigonometry question. + \end{question} + \begin{question}[topic=arithmetics] + A arithmetics question + \end{question} +\end{example} +Questions of topics that are not used are fully discarded. \emph{This also + means that questions that don't have a topic assigned are discarded.} + +If you set both \option{use-classes} and \option{use-topics} then only +questions will be used that \emph{match both categories}. + +Ideally one could assign more than one topic to a question but this is +\emph{not} supported yet. + +\ExplSyntaxOn + \bool_set_false:N \g__exsheets_use_topics_bool +\ExplSyntaxOff + +\subsection{Own Dividing Concepts} +Actually\sinceversion{0.8} both classes and topics are introduced into +\ExSheets\ internally this way: +\begin{sourcecode} + \DeclareQuestionClass{class}{classes} + \DeclareQuestionClass{topic}{topics} +\end{sourcecode} +which means you can do the same introducing your own dividing concepts. +\begin{commands} + \command{DeclareQuestionClass}[\marg{singular name}\marg{plural name}] + Introduces a new dividing concept and defines both new options for the + \env{question} environment and new global options. +\end{commands} + +For example you could decide you want to group your questions according to +their difficulty. You could place the following line in your preamble: +\begin{sourcecode} + \DeclareQuestionClass{difficulty}{difficulties} +\end{sourcecode} +This would define an option \option*{use-difficulties} analogous to +\option{use-classes} and \option{use-topics}. It would also define an option +\option{difficulty} for the \env{question} environment. This means you could +now do something like the following: +\begin{example} + \SetupExSheets{use-difficulties={easy,hard}} + \begin{question}[difficulty=easy] + An easy question. + \end{question} + \begin{question}[difficulty=medium] + This one's a bit harder. + \end{question} + \begin{question}[difficulty=hard] + Now let's see if you can solve this one. + \end{question} +\end{example} + +\subsection{Retrieving the Class Value in a Question}\label{sec:retr-class-value} +Sometimes it may be desirable to retrieve the value of a class defined by +\cs{DeclareQuestionClass} that a question has in order to be able to print, +say. This is possible with the following commands: +\begin{commands} + \expandable\command{GetQuestionClass}[\marg{class}] + Prints the value of \meta{class} a question has. The command is + expandable. If the class does not exist or the value is empty the command + expands to nothing. + \command{PrintQuestionClassTF}[\marg{class}\marg{true}\marg{false}] + Test if a question has a non-empty value for class \meta{class} and either + leaves \meta{true} or \meta{false} in the input stream. In the + \meta{true} argument you can refer to the value with \code{\#1} where you + want it printed. + \command{PrintQuestionClassT}[\marg{class}\marg{true}] + Like \cs{PrintQuestionClassTF} but only has the \meta{true} branch. + \command{PrintQuestionClassF}[\marg{class}\marg{false}] + Like \cs{PrintQuestionClassTF} but only has the \meta{false} branch. +\end{commands} + +\begin{example} + \begin{question}[difficulty=hard] + This question has the difficulty level + ``\PrintQuestionClassTF{difficulty}{#1}{??}''. + \end{question} +\end{example} + +\ExplSyntaxOn + \bool_set_false:N \g__exsheets_use_difficulties_bool +\ExplSyntaxOff + +\subsection{Tagging Questions} +There\sinceversion{0.20} is another way of dividing questions: you can assign +tags to questions: +\begin{sourcecode} + \begin{question}[tags={foo,bar,baz}] + ... + \end{question} +\end{sourcecode} +You can then decide to print only questions with certain tags by using the +following option: +\begin{options} + \keyval{use-tags}{csv list of tags to include} + Select tags. When used only questions being tagged with at least one of + the tags in \meta{csv list of tags to include} are printed. +\end{options} + +\section{Adding and Using Additional Information to + Questions}\label{sec:additional_info} +\subsection{Question Properties -- the Basics} + +For managing lots of questions and corresponding solutions it can be very +useful to be able to save and recover additional information to the questions. +This is possible with the following commands. First the ones for saving: +\begin{commands} + \command{DeclareQuestionProperty}[\marg{name}] + This command defines a question property \meta{name}. It can only be + used in the document preamble. + \command{SetQuestionProperties}[\Marg{\meta{name}=\meta{value},...}] + Set the properties for a specific question. this command can only be used + inside the \env{question} environment. +\end{commands} +Now the commands for recovering the properties: +\begin{commands} + \command{QuestionNumber}[\marg{id}] + Recover the number of the question with the \acs{id} \meta{id}. The + number is displayed according to the format set with + \option{counter-format}. + \expandable\command{GetQuestionProperty}[\marg{name}\marg{id}] + Recover the property \meta{name} of the question with the \acs{id} + \meta{id}. Of course the property must have been declared before. The + command is expandable. Since\changedversion{0.12} the properties of a + question are written to the \code{aux} file it is possible to retrieve + them before the corresponding \env{question} environment has been used. + \expandable\command{IfQuestionPropertyTF}[\marg{name}\marg{id}\marg{true}\marg{false}] + A command\sinceversion{0.15} that returns \meta{true} if the question with + the \acs{id} \meta{id} has the property \meta{name} and \meta{false} + otherwise. The variants \cs{IfQuestionPropertyT} and + \cs{IfQuestionPropertyF} also exist which only have the \meta{true} or the + \meta{false} branch. +\end{commands} + +Let's say we have declared the properties \code{notes}, \code{reference} and +\code{topic}. By default the property \code{points} is available and gets the +value of the optional argument of the \code{question} environment. + +We can now do the following: +\begin{example} + % uses `biblatex' + \begin{question}[ID=center,topic=LaTeX]{3} + Explain how you could center text in a \LaTeX\ document. + \SetQuestionProperties{ + topic = \TeX/\LaTeX , + notes = {How to center text.}, + reference = {\textcite{companion}}} + \end{question} + \begin{solution} + To center a short part of the text body one can use the \env*{center} + environment (\points{1}). Inside an environment like \env*{table} one + should use \cs*{centering} (\points{1}). For single lines there is also + the \cs*{centerline} command (\points{1}). + \end{solution} + \begin{question}[ID=knuthbooks,topic=LaTeX]{2} + Name two books by D.\,E.\,Knuth. + \SetQuestionProperties{ + topic = \TeX/\LaTeX , + notes = {Books by Knuth.}, + reference = {\textcite{knuth:ct:a,knuth:ct:b,knuth:ct:c,knuth:ct:d,knuth:ct:e}}} + \end{question} + \begin{solution} + For example two volumes from \citetitle{knuth:ct}: + \citetitle{knuth:ct:a,knuth:ct:b,knuth:ct:c,knuth:ct:d,knuth:ct:e}. Each + valid answer is worth \points{1} + \end{solution} +\end{example} + +It is now possible to recover these values later: +\begin{example} + % uses `booktabs' + \begin{center} + \begin{tabular}{lll} + \toprule + Question & Property & \\ + \midrule + \QuestionNumber{center} + & Points & \GetQuestionProperty{points}{center} \\ + & Topic & \GetQuestionProperty{topic}{center} \\ + & References & \GetQuestionProperty{reference}{center} \\ + & Note & \GetQuestionProperty{notes}{center} \\ + \midrule + \QuestionNumber{knuthbooks} + & Points & \GetQuestionProperty{points}{knuthbooks} \\ + & Topic & \GetQuestionProperty{topic}{knuthbooks} \\ + & References & \GetQuestionProperty{reference}{knuthbooks} \\ + & Note & \GetQuestionProperty{notes}{knuthbooks} \\ + \bottomrule + \end{tabular} + \end{center} +\end{example} + +Please note that properties \emph{are not the same} as the dividing concepts +explained in section~\ref{sec:cond-print-quest} although they may seem +similar in meaning or even have the same name. + +When properties are set they are also written to the \code{aux} file which +means they can be retrieved \emph{before} the corresponding question. Of +course this means that two compilation runs are necessary. + +\subsection{Pre-defined Properties} + +A few properties are already defined by \ExSheets: +\begin{itemize} + \item \code{counter}:\sinceversion{0.14} this property holds the actual + question number formatted according to the formatting set with option + \option{counter-format}. + \item \code{subtitle}:\sinceversion{0.12} this property holds the subtitle + of the question if given. + \item \code{question-body}:\sinceversion{0.14} this property holds the body + of the corresponding \env{question} environment. Unlike the other + properties it is per default \emph{not} written to the \code{aux} file. + \item \code{points}: this property holds the sum of points given to a + question. + \item \code{bonus-points}:\sinceversion{0.14} this property holds the sum of + bonus points given to a question. + \item \code{ref}:\sinceversion{0.7f} when the option \option{auto-label} is + used this property is defined and expands to the corresponding \cs*{ref}. + Also see section~\ref{sec:auto-label-opti}. + \item \code{page-ref}:\sinceversion{0.7f} when the option + \option{auto-label} is used this property is defined and expands to the + corresponding \cs*{pageref}. Also see section~\ref{sec:auto-label-opti}. +\end{itemize} + +There is one option affecting the property \code{question-body}: +\begin{options} + \keybool{save-to-aux}\Module{question}\Default{false} + When set to \code{true} the property \code{question-body} is also written + to the \code{aux} file. +\end{options} + +\subsection{Advanced Usage} + +There are additional commands\sinceversion{0.3} that might prove useful. They +allow advanced usage of defined properties. Below an example is shown how +they can be used to generate a grading table. +\begin{commands} + \command{ForEachQuestion}[\marg{code to be executed for each used question}] + \changedversion{0.14}Inside the argument one can refer to the \ac{id} of a + question with \code{\#1}. You can also refer to the number of the + question with \code{\#2}. \emph{Number} means that if you \emph{use} + seven questions then those questions have numbers~1 to~7. + \expandable\command{numberofquestions} + \changedversion{0.14} returns the complete number of used questions. + \expandable\command{iflastquestion}[\marg{true code}\marg{false code}] + Although this command is available in the whole document it is only useful + inside \cs{ForEachQuestion}. It tells you if the end of the loop is + reached or not. +\end{commands} + +One could use these commands to create a grading table, for instance: +\begin{sourcecode} + \begin{tabular}{|l|*{\numberofquestions}{c|}c|}\hline + Question & + \ForEachQuestion{\QuestionNumber{#1}\iflastquestion{}{&}} & + Total \\ \hline + Points & + \ForEachQuestion{\GetQuestionProperty{points}{#1}\iflastquestion{}{&}} & + \pointssum* \\ \hline + Reached & + \ForEachQuestion{\iflastquestion{}{&}} & \\ \hline + \end{tabular} +\end{sourcecode} +For four questions the table now would look similar to +figure~\ref{fig:grading-table}. + +\begin{figure}[ht] + \centering + \begin{tabular}{|l|*{4}{c|}c|}\hline + Question & 1. & 2. & 3. & 4. & Total \\ \hline + Points & 3 & 5 & 10 & 8 & 26 \\ \hline + Reached & & & & & \\ \hline + \end{tabular} + \caption{An example for a grading table. (Actually this is a fake. See the + \code{grading-table.tex} file shipped with exsheets for the real use case.)} + \label{fig:grading-table} +\end{figure} + + +\section{Variations of an Exam} + +It is a quite common task\sinceversion{0.6} to design an exam in two different +variants. This is of course possible with \ExSheets' classes (see +section~\ref{sec:classes}). However, often not the whole question is to be +different but only small details, the numbers in a maths exam, say. For this +purpose \ExSheets\ provides the following commands: +\begin{commands} + \command{SetVariations}[\marg{num}] + Set the number of different variants. This will determine how many + arguments the command \cs{vary} will get. \meta{num} must at least be + \code{2} and is initially set to \code{2}. + \command{variant}[\marg{num}] + Choose the active variant. The argument must be a number between \code{1} + and the number set with \cs{SetVariations}. Initially set to \code{1}. + \command{vary}[\marg{variant 1}\marg{variant 2}] + This command is the one actually used in the document. It has a number of + required arguments equal to the number set with \cs{SetVariations}. All + of its arguments are discarded except the one specified with + \cs{variant}. + \command{lastvariant} + \sinceversion{0.7b}Each time \cs{vary} is called it stores the value it + chose in \cs{lastversion}. This might be convenient to use if one + otherwise would have to repeatedly write the same \cs{vary}. +\end{commands} + +\begin{example} + \SetVariations{6}% + \variant{6}\vary{A}{B}{C}{D}{E}{F} + (last variant: \lastvariant) + \variant{1}\vary{A}{B}{C}{D}{E}{F} + (last variant: \lastvariant) + \variant{5}\vary{A}{B}{C}{D}{E}{F} + (last variant: \lastvariant) + \variant{2}\vary{A}{B}{C}{D}{E}{F} + (last variant: \lastvariant) + \variant{4}\vary{A}{B}{C}{D}{E}{F} + (last variant: \lastvariant) + \variant{3}\vary{A}{B}{C}{D}{E}{F} + (last variant: \lastvariant) +\end{example} + +\section{A Grade Distribution} +Probably this is a rather esoteric feature but it could proof useful in some +cases. Suppose you are a German math teacher and want to grade exactly +corresponding to the number of points relative to the sum of total points, +regardless of how big that might be. You could do something like this to +present your grading decisions for the exam: +\begin{example} + % preamble: + % \DeclareRelGrades{ + % 1 = 1 , + % {1,5} = .9167 , + % 2 = .8333 , + % {2,5} = .75 , + % 3 = .6667 , + % {3,5} = .5833 , + % 4 = .5 + % } + \small\setlength\tabcolsep{2pt} + \begin{tabular}{r|*8c} + Punkte + & $\grade*{1}$ & $\le\grade*{1}$ & $\le\grade*{1,5}$ & $\le\grade*{2}$ + & $\le\grade*{2,5}$ & $\le\grade*{3}$ & $\le\grade*{3,5}$ & $<\grade*{4}$ \\ + Note + & 1 & 1--2 & 2 & 2--3 & 3 & 3--4 & 4 & 5 + \end{tabular} +\end{example} + +These are the available commands and options: +\begin{commands} + \command{DeclareRelGrades}[\Marg{\meta{grade}=\meta{num},...}] + This command is used to define grades and assign the percentage of total + points to them. + \command{grade}[\sarg\marg{grade}] + Gives the number of points corresponding to a grade depending on the value + of \cs{pointssum} with or without (starred version) ``unit''. +\end{commands} +\begin{options} + \keyval{round}{num}\Module{grades}\Default{0} + The number of decimals the points of a grade are rounded to. This doesn't + apply to the maximum number of points if the rounded number would be + bigger than the actual sum. + \keybool{half}\Module{grades}\Default{false} + If set to \code{true} points are rounded either to full or to half + points. +\end{options} + +\section{Selectively Include Questions from External Files}\label{sec:include} +\subsection{Caveat} +I need to say some words of caution: the \cs{includequestions} that will be +presented shortly is probably \ExSheets' most experimental one at the time of +writing (\today). Thanks to feedback of users it is constantly improved and +bugs are fixed. It is not a very efficient way to insert question regarding +performance and you shouldn't wonder if compilation slows down when you use +it. It probably needs to be re-written all over but on the one hand that +would introduce new bugs and on the other hand for the time being I don't have +the capacities, anyway, so you'll have to live it, I'm afraid. + +\subsection{How it works} +Suppose you have one or more files with questions prepared to use them as a +kind of database. One for class A, say, one for class B, one for class C and +so one, something like this: +\begin{sourcecode} + % this is file classA.tex + \begin{question}[class=A,ID=A1,topic=X] + First question of class A, topic X. + \end{question} + \begin{solution} + First solution of class A. + \end{solution} + \begin{question}[class=A,ID=A2,topic=Y] + Second question of class A, topic Y. + \end{question} + \begin{solution} + Second solution of class A. + \end{solution} + ... + % end of file classA.tex + \endinput +\end{sourcecode} +You can of course just \cs*{input} or \cs*{include} it but that would of +course include the whole file into your document. But would't it be nice to +just include selected questions? Or maybe a five random questions from the +file? That is possible with the following command: +\begin{commands} + \command{includequestions}[\oarg{options}\marg{list of filenames}] + Include questions from external files. +\end{commands} +If you use it without options it will have the same effect as \cs*{input}. +There are however the following options: +\begin{options} + \keybool{all}\Module{include} + \keyval{IDs}{list of IDs}\Module{include}\Default + Includes only the specified questions. + \keyval{random}{num}\Module{include}\Default + Includes \meta{num} randomly selected questions. This option uses the + \pkg{pgfcore} package to create the pseudo-random numbers. + \keyval{exclude}{list of IDs}\Module{include}\Default + Questions who's \acp{id} are specified here are \emph{not} included. This + option can be combined with the \option{random} option. +\end{options} + +The usage should be self-explainable: +\begin{sourcecode} + % include questions A1, A3 and A4: + \includequestions[IDs={A1,A3,A4}]{classA.tex} + % or include 3 random questions: + \includequestions[random=3]{classA} +\end{sourcecode} +In order to be able to select the questions \ExSheets\ needs to \cs*{input} +the file twice. The first time the available questions are determined, the +second time the selected questions are used. This unfortunately means that +anything that is \emph{not} part of a question or solution is also input +twice. Either don't put anything else into the file or use one of the +following commands for control: +\begin{commands} + \command{PrintIfIncludeActiveTF}[\marg{true code}\marg{false code}] + Checks if the questions are actively included or not and puts \meta{true + code} or \meta{false code} in the input stream depending on the answer. + \command{PrintIfIncludeActiveT}[\marg{true code}] + Checks if the questions are actively included or not and puts \meta{true + code} in the input stream if the answer is yes. + \command{PrintIfIncludeActiveF}[\marg{false code}] + Checks if the questions are actively included or not and puts \meta{false + code} in the input stream if the answer is no. +\end{commands} + +The selection can be refined further by selecting questions belonging to a +specific class of questions (see section~\ref{sec:cond-print-quest}) before +using \cs{includequestions}. + +\sinceversion{0.8}After you've used \cs{includequestions} the \acp{id} of the +included questions is available as an unordered comma separated list in the +following macro: +\begin{commands} + \command{questionsincludedlast} + Unordered comma separated list of question \acp{id} included with the last + usage of \cs{includequestions}. +\end{commands} + +\section{The \option*{auto-label} Option}\label{sec:auto-label-opti} +The\sinceversion{0.12} package option \option{auto-label} sets a +\cs*{label}\Marg{qu:\meta{id}} every time the question environment is used. +Both the used command and the automated label can be customized using the +following options: + +\begin{options} + \keyval{label-format}{code}\Default{qu:\#1} + The pattern for generating the automatic label. \code{\#1} gets replaced + by the \ac{id} of the corresponding question. + \keyval{label-cmd}{macro}\Default{\cs*{label}} + The command used for generating the label. A command that should take one + mandatory argument. + \keyval{ref-cmd}{macro}\Default{\cs*{ref}} + The command used in the \code{ref} property created by the + \option{auto-label} option, also see section \ref{sec:additional_info}. + The command should take one mandatory argument. + \keyval{pageref-cmd}{macro}\Default{\cs*{pageref}} + The command used in the \code{pageref} property created by the + \option{auto-label} option, also see section \ref{sec:additional_info}. + The command should take one mandatory argument. +\end{options} + +\section{Own Question/Solution Pairs} +\ExSheets\changedversion{0.9} provides the possibility to create new +environments that behave like the \env{question} and \env{solution} +environments. This would allow, for example, to define a +\env*{question*}/\env*{solution*} environment pair for bonus questions. The +following commands may be used in the document preamble: +\begin{commands} + \command{NewQuSolPair}[\marg{question}\oarg{question options}\oarg{general + options}\marg{solution}\oarg{solution options}\oarg{general options}] + Define a new pair of question and solution environments. + \command{RenewQuSolPair}[\marg{question}\oarg{question options}\oarg{general + options}\marg{solution}\oarg{solution options}\oarg{general options}] + Redefine an existing pair of question and solution environments. +\end{commands} +The standard environments are defined as follows: +\begin{sourcecode} + \NewQuSolPair{question}{solution} +\end{sourcecode} + +Let's say we want the possibility to add bonus questions. A simple way would +be to define starred variants that add a star in the margin left to the title: +\begin{example} + % preamble: + % - \texorpdfstring is provided by `hyperref' + % - \bigstar is provided by `amssymb' + % \DeclareRobustCommand*\questionstar{\texorpdfstring{\bonusquestionsign}{* }} + % \DeclareRobustCommand*\bonusquestionsign{\llap{$\bigstar$\space}} + % + % \NewQuSolPair + % {question*}[name=\questionstar Bonus Question] + % {solution*}[name=\questionstar Solution] + \begin{question*} + This is a bonus question. + \end{question*} + \begin{solution*}[print] + This is what the solution looks like. + \end{solution*} +\end{example} +As you can see the environments take the same options as are described for the +standard \env{question} and \env{solution} environments. + +\section{Filling in the Blanks} +\subsection{Cloze} +Both\changedversion{0.4} in exercise sheets and in exams it is sometimes +desirable to be able to create \blank{blanks} that have to be filled in. Or +maybe some more lines: \blank[width=5\linewidth]{} + +\begin{commands} + \command{blank}[\sarg\oarg{options}\marg{text to be filled in}] + creates a blank in normal text or in a question but fills the text of its + argument if inside a solution. If used at the \emph{begin of a paragraph} + \cs{blank} will do two things: it will set the linespread according to an + option explained below and will insert \cs*{par} after the lines. If you + don't want that use the starred version. +\end{commands} + +The options are these: +\begin{options} + \keychoice{style}{line,wave,dline,dotted,dashed}\Module{blank}\Default{line} + The style of the line. This uses the corresponding command from the + \pkg{ulem} package and is the whole reason why \ExSheets\ loads it in the + first place. + \keyval{scale}{num}\Module{blank}\Default{1} + Scales the width of the blank by factor \meta{num} unless the width is + explicitly set. + \keyval{width}{dim}\Module{blank}\Default + The width of the line. If it is not used the width of the filled in text + is used. + \keyval{linespread}{num}\Module{blank}\Default{1} + Set the linespread for the blank lines. This only has an effect if + \cs{blank} is used at the begin of a paragraph. + \keyval{line-increment}{dim}\Module{blank}\Default{1pt} + \sinceversion{0.21h}When the blank line ist built it is built in multiples + of this value. If the value is too large you may end up with uneven + lines. If the value is too small you may end up with a non-ending + compilation. + \keyval{line-minimum-length}{dim}\Module{blank}\Default{2em} + \sinceversion{0.21h}The minimal length a line must have before it is built + step by step. +\end{options} +\begin{example} + \begin{question} + Try to fill in \blank[width=4cm]{these} blanks. All of them + \blank[style=dotted]{are created} by using the \cs{blank} + \blank[style=dashed]{command}. + \end{question} + \begin{solution}[print] + Try to fill in \blank[width=4cm]{these} blanks. All of them + \blank[style=dotted]{are created} by using the \cs{blank} + \blank[style=dashed]{command}. + \end{solution} +\end{example} +A number of empty lines are easily created by setting the width option: +\begin{example} + \blank[width=4.8\linewidth,linespread=1.5]{} +\end{example} + +\subsection{Vertical Space for answers} +When\sinceversion{0.3} you're creating an exam you might want to add some +vertical space where the students can write down their answers. While you can +always use \cs*{vspace} this is not always handy when the space left on the +page is less than you want. In this case it would be nice if a) there would +be no warning and b) the rest of the space would be added at the top of the +next page. This is what the following command is for: +\begin{commands} + \command{examspace}[\sarg\marg{dim}] + Add space as specified in \meta{dim}. If the space available on the + current page is not enough the rest of the space will be added at the top + of the next page. The starred version will silently drop any leftover + space instead of adding it to the next page. +\end{commands} +\begin{example}[side-by-side] + \begin{question} + What do you think of this feature? + \examspace{3cm} + \end{question} + This line comes after the space. +\end{example} + +\section{Styling your Exercise/Exam Sheets}\label{part:style} +\subsection{Background} +The \ExSheets\ package makes extensive use of \LaTeX3's coffins\footnote{See + the documentation to the \pkg{xcoffins} package for more information on + that.} as well as its templates concept\footnote{Have a look into the + documentation to the \pkg{xtemplate} package.}. The latter allows a +rather easy extension and customization of some of \ExSheets' environments. +To be more precise: you can define your own instances for the headings used +for questions and solutions. + +What this package doesn't provide is changing the background of questions or +framing them. But this is easily possible using the \pkg{mdframed} package +and its \cs*{surroundwithmdframed} command. + +\ExSheets{} also provides the options \option{pre-hook}, \option{post-hook}, +\option{pre-body-hook} and \option{post-body-hook} to both the question and +the solution environment. With them it is rather straightforward to add a +\pkg{mdframed} frame for instance: +\begin{sourcecode} + \SetupExSheets{ + solution/pre-hook = \mdframed , + solution/post-hook = \endmdframed + } +\end{sourcecode} + +Then\sinceversion{0.18} there is the macro +\cs{exsheetsprintsolution}\marg{heading}\marg{body}\label{exsheetsprintsolution} +which may be redefined to suit your needs. The default definition is +equivalent to +\begin{sourcecode} + \newcommand\exsheetsprintsolution[2]{#1#2} +\end{sourcecode} + +\subsection{The \code{exsheets-headings} Object}\label{sec:exsheets-headings} +\ExSheets\ defines the object \code{exsheets-headings} and one template for it, +the `default' template. The package also defines two instances of this +template, the `block' instance and the `runin' instance. + +\begin{example} + \SetupExSheets{headings=block} + \begin{question}{1} + a `block' heading + \end{question} + \SetupExSheets{headings=runin} + \begin{question}{1} + a `runin' heading + \end{question} +\end{example} + +\subsubsection{Available Options} +This section only lists the options that can be used when defining an instance +of the `default' template. The following subsections will give loads of +examples of their usage. The options are listed in the definition for the +template interface: + +\begin{sourcecode} + \DeclareTemplateInterface{exsheets-heading}{default}{3}{ + % option : type = default + inline : boolean = false , + runin : boolean = false , + indent-first : boolean = false , + toc-reversed : boolean = false , + vscale : real = 1 , + above : length = 2pt , + below : length = 2pt , + main : tokenlist = , + pre-code : tokenlist = , + post-code : tokenlist = , + title-format : tokenlist = , + title-pre-code : tokenlist = , + title-post-code : tokenlist = , + number-format : tokenlist = , + number-pre-code : tokenlist = , + number-post-code : tokenlist = , + subtitle-format : tokenlist = , + subtitle-pre-code : tokenlist = , + subtitle-post-code : tokenlist = , + points-format : tokenlist = , + points-pre-code : tokenlist = , + points-post-code : tokenlist = , + join : tokenlist = , + attach : tokenlist = + } +\end{sourcecode} + +Each heading is built with at most five coffins available with the names +`main', `title', `subtitle', `number' and `points'. Those coffins place +possibly the whole heading, the title, the subtitle, the question number and +the assigned points. The only coffin that's always typeset is the `main' +coffin, which is empty per default. + +Coffins can be joined (two become one, the first extends its bounding box to +contain the second) using the following syntax: +\begin{sourcecode} + join = coffin1[handle11,handle12]coffin2[handle21,handle22](x-offset,y-offset) +\end{sourcecode} +The syntax for attaching (two become one, the first does \emph{not} extend its +bounding box around the second) is the same. + +More on coffin handles is described in the documentation for the +\pkg{xcoffins}. Figure~\ref{fig:handles} briefly demonstrates the available +handle pairs. + +\begin{figure}[ht] + \centering + \parbox{4.5cm}{% + \NewCoffin\ExampleCoffin + \SetHorizontalCoffin\ExampleCoffin{\color{gray!30}\rule{4cm}{4cm}}% + \DisplayCoffinHandles\ExampleCoffin{blue}% + } + \caption{Available handles for a horizontal coffin.}\label{fig:handles} +\end{figure} + +It is possible\sinceversion{0.20} to add own static coffins: +\begin{commands} + \command{DeclareExSheetsHeadingContainer}[\marg{name}\marg{code}] + Defines a new coffin \meta{name} containing \meta{code}. You can refer to + the current question's \ac{id} with \cs{CurrentQuestionID}. +\end{commands} + +The following subsections will show all definitions of the instances available +and how they look. This will hopefully give you enough ideas to create your +own instance if you want to have another heading style than the ones +available. Each of the following instances is available through the option +\key{headings}{instance}. + +The following examples use a sample text defined as follows: +\begin{sourcecode} + \def\s{This is some sample text we will use to create a somewhat + longer text spanning a few lines.} + \def\sample{\s\ \s\par\s} +\end{sourcecode} +\def\s{This is some sample text we will use to create a somewhat longer text + spanning a few lines.} +\def\sample{\s\ \s\par\s} + +All of the following examples use the same question call: +\begin{sourcecode} + \SetupExSheets{headings=<name>} + \begin{question}[subtitle=The subtitle of the question]{1} + A `<name>' heading. \sample + \end{question} +\end{sourcecode} + +\subsubsection{The `block' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block}{default}{ + join = { title[r,B]number[l,B](.333em,0pt) } , + attach = + { + main[l,vc]title[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=block} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block' heading. \sample +\end{question} + +\subsubsection{The `runin' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin}{default}{ + runin = true , + number-post-code = \space , + attach = + { main[l,vc]points[l,vc](\linewidth+\marginparsep,0pt) } , + join = + { + main[r,vc]title[r,vc](0pt,0pt) ; + main[r,vc]number[l,vc](.333em,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=runin} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin' heading. \sample +\end{question} + +\subsubsection{The `simple' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{simple}{default}{ + title-format = \normalsize , + points-pre-code = ( , + points-post-code = ) , + attach = { main[l,t]number[l,t](0pt,0pt) } , + join = + { + number[r,b]title[l,b](.333em,0pt) ; + main[l,b]points[l,t](1em,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=simple} +\begin{question}[subtitle=The subtitle of the question]{1} + A `simple' heading. \sample +\end{question} + +\subsubsection{The `empty' Instance} +\sinceversion{0.9a} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{empty}{default}{ + runin = true , + above = \parskip , + below = \parskip , + attach = { main[l,vc]points[l,vc](\linewidth+\marginparsep,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=empty} +\begin{question}[subtitle=The subtitle of the question]{1} + An `empty' heading. \sample +\end{question} + +\subsubsection{The `block-rev' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block-rev}{default}{ + toc-reversed = true , + join = { number[r,B]title[l,B](.333em,0pt) } , + attach = + { + main[l,vc]number[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=block-rev} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block-rev' heading. \sample +\end{question} + +\subsubsection{The `block-subtitle' Instance} +\sinceversion{0.10} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block-subtitle}{default}{ + join = { + title[r,B]number[l,B](.333em,0pt) ; + title[r,B]subtitle[l,B](1em,0pt) + } , + attach = { + main[l,vc]title[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=block-subtitle} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block-subtitle' heading. \sample +\end{question} +\subsubsection{The `block-wp' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block-wp}{default}{ + points-pre-code = ( , + points-post-code = ) , + join = + { + title[r,B]number[l,B](.333em,0pt) ; + title[r,B]points[l,B](.333em,0pt) + } , + attach = { main[l,vc]title[l,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=block-wp} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block-wp' heading. \sample +\end{question} + +\subsubsection{The `block-wp-rev' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block-wp-rev}{default}{ + toc-reversed = true , + points-pre-code = ( , + points-post-code = ) , + join = + { + number[r,B]title[l,B](.333em,0pt) ; + number[r,B]points[l,B](.333em,0pt) + } , + attach = { main[l,vc]number[l,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=block-wp-rev} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block-wp-rev' heading. \sample +\end{question} + +\subsubsection{The `block-nr' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block-nr}{default}{ + attach = + { + main[l,vc]number[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=block-nr} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block-nr' heading. \sample +\end{question} + +\subsubsection{The `block-nr-wp' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{block-nr-wp}{default}{ + points-pre-code = ( , + points-post-code = ) , + join = { number[r,vc]points[l,vc](.333em,0pt) } , + attach = { main[l,vc]number[l,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=block-nr-wp} +\begin{question}[subtitle=The subtitle of the question]{1} + A `block-nr-wp' heading. \sample +\end{question} + +\subsubsection{The `runin-rev' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin-rev}{default}{ + toc-reversed = true , + runin = true , + title-post-code = \space , + attach = + { main[l,vc]points[l,vc](\linewidth+\marginparsep,0pt) } , + join = + { + main[r,vc]number[r,vc](0pt,0pt) ; + main[r,vc]title[l,vc](.333em,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=runin-rev} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin-rev' heading. \sample +\end{question} + +\subsubsection{The `runin-wp' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin-wp}{default}{ + runin = true , + points-pre-code = ( , + points-post-code = )\space , + join = + { + main[r,vc]title[r,vc](0pt,0pt) ; + main[r,vc]number[l,vc](.333em,0pt) ; + main[r,vc]points[l,vc](.333em,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=runin-wp} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin-wp' heading. \sample +\end{question} + +\subsubsection{The `runin-wp-rev' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin-wp-rev}{default}{ + toc-reversed = true , + runin = true , + points-pre-code = ( , + points-post-code = )\space , + join = + { + main[r,vc]number[r,vc](0pt,0pt) ; + main[r,vc]title[l,vc](.333em,0pt) ; + main[r,vc]points[l,vc](.333em,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=runin-wp-rev} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin-wp-rev' heading. \sample +\end{question} + +\subsubsection{The `runin-nr' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin-nr}{default}{ + runin = true , + number-post-code = \space , + attach = + { main[l,vc]points[l,vc](\linewidth+\marginparsep,0pt) } , + join = { main[r,vc]number[l,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=runin-nr} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin-nr' heading. \sample +\end{question} + +\subsubsection{The `runin-fixed-nr' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin-fixed-nr}{default}{ + runin = true , + number-pre-code = \hbox to 2em \bgroup , + number-post-code = \hfil\egroup , + attach = + { main[l,vc]points[l,vc](\linewidth+\marginparsep,0pt) } , + join = { main[r,vc]number[l,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=runin-fixed-nr} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin-fixed-nr' heading. \sample +\end{question} + +\subsubsection{The `runin-nr-wp' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{runin-nr-wp}{default}{ + runin = true , + points-pre-code = ( , + points-post-code = )\space , + join = + { + main[r,vc]number[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](.333em,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=runin-nr-wp} +\begin{question}[subtitle=The subtitle of the question]{1} + A `runin-nr-wp' heading. \sample +\end{question} + +\subsubsection{The `inline' Instance} +\sinceversion{0.5} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{inline}{default}{ + inline = true , + number-pre-code = \space , + number-post-code = \space , + join = + { + main[r,vc]title[r,vc](0pt,0pt) ; + main[r,vc]number[l,vc](0pt,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=inline} +Text before +\begin{question}[subtitle=The subtitle of the question]{1} + An `inline' heading. \sample +\end{question} + Text after + +\subsubsection{The `inline-wp' Instance} +\sinceversion{0.5} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{inline-wp}{default}{ + inline = true , + number-pre-code = \space , + number-post-code = \space , + points-pre-code = ( , + points-post-code = )\space , + join = + { + main[r,vc]title[r,vc](0pt,0pt) ; + main[r,vc]number[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](0pt,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=inline-wp} +Text before +\begin{question}[subtitle=The subtitle of the question]{1} + An `inline-wp' heading. \sample +\end{question} + Text after + +\subsubsection{The `inline-nr' Instance} +\sinceversion{0.5} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{inline-nr}{default}{ + inline = true , + number-post-code = \space , + join = { main[r,vc]number[l,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=inline-nr} +Text before +\begin{question}[subtitle=The subtitle of the question]{1} + An `inline-nr' heading. \sample +\end{question} + Text after + +\subsubsection{The `centered' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{centered}{default}{ + join = { title[r,B]number[l,B](.333em,0pt) } , + attach = + { + main[hc,vc]title[hc,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=centered} +\begin{question}[subtitle=The subtitle of the question]{1} + A `centered' heading. \sample +\end{question} + +\subsubsection{The `centered-wp' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{centered-wp}{default}{ + points-pre-code = ( , + points-post-code = ) , + join = + { + title[r,B]number[l,B](.333em,0pt) ; + title[r,B]points[l,B](.333em,0pt) + } , + attach = { main[hc,vc]title[hc,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=centered-wp} +\begin{question}[subtitle=The subtitle of the question]{1} + A `centered-wp' heading. \sample +\end{question} + +\subsubsection{The `margin' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{margin}{default}{ + runin = true , + number-post-code = \space , + points-pre-code = ( , + points-post-code = )\space , + join = { title[r,b]number[l,b](.333em,0pt) } , + attach = + { + main[l,vc]title[r,vc](0pt,0pt) ; + main[l,b]points[r,t](0pt,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=margin} +\begin{question}[subtitle=The subtitle of the question]{1} + A `margin' heading. \sample +\end{question} + +\subsubsection{The `margin-nr' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{margin-nr}{default}{ + runin = true , + attach = + { + main[l,vc]number[r,vc](-.333em,0pt) ; + main[r,vc]points[l,vc](\linewidth+\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=margin-nr} +\begin{question}[subtitle=The subtitle of the question]{1} + A `margin-nr' heading. \sample +\end{question} + +\subsubsection{The `raggedleft' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{raggedleft}{default}{ + join = { title[r,B]number[l,B](.333em,0pt) } , + attach = + { + main[r,vc]title[r,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=raggedleft} +\begin{question}[subtitle=The subtitle of the question]{1} + A `raggedleft' heading. \sample +\end{question} + +\subsubsection{The `fancy' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{fancy}{default}{ + toc-reversed = true , + indent-first = true , + vscale = 2 , + pre-code = \rule{\linewidth}{1pt} , + post-code = \rule{\linewidth}{1pt} , + title-format = \large\scshape\color{rgb:red,0.65;green,0.04;blue,0.07} , + number-format = \large\bfseries\color{rgb:red,0.02;green,0.04;blue,0.48} , + points-format = \itshape , + join = { number[r,B]title[l,B](.333em,0pt) } , + attach = + { + main[hc,vc]number[hc,vc](0pt,0pt) ; + main[l,vc]points[r,vc](-\marginparsep,0pt) + } + } +\end{sourcecode} +\SetupExSheets{headings=fancy} +\begin{question}[subtitle=The subtitle of the question]{1} + A `fancy' heading. \sample +\end{question} + +\subsubsection{The `fancy-wp' Instance} +\begin{sourcecode} + \DeclareInstance{exsheets-heading}{fancy-wp}{default}{ + toc-reversed = true , + indent-first = true , + vscale = 2 , + pre-code = \rule{\linewidth}{1pt} , + post-code = \rule{\linewidth}{1pt} , + title-format = \large\scshape\color{rgb:red,0.65;green,0.04;blue,0.07} , + number-format = \large\bfseries\color{rgb:red,0.02;green,0.04;blue,0.48} , + points-format = \itshape , + points-pre-code = ( , + points-post-code = ) , + join = + { + number[r,B]title[l,B](.333em,0pt) ; + number[r,B]points[l,B](.333em,0pt) + } , + attach = { main[hc,vc]number[hc,vc](0pt,0pt) } + } +\end{sourcecode} +\SetupExSheets{headings=fancy-wp} +\begin{question}[subtitle=The subtitle of the question]{1} + A `fancy-wp' heading. \sample +\end{question} + +\subsection{Using an \ExSheets{} Heading in Custom Code}\label{sec:using-an-exsheets} + +It can be useful to have access to \ExSheets{} headings in custom code. This +is possible with the following command\sinceversion{0.14}: + +\begin{commands} + \command{ExSheetsHeading}[\marg{instance}\marg{title}\marg{number}% + \marg{points}\marg{bonus}\marg{id}] + The meaning of the arguments is as follows: + \begin{itemize} + \item \meta{instance}: the name of the headings instance to be used. + \item \meta{title}: the contents of the \code{title} coffin. + \item \meta{number}: the contents of the \code{number} coffin. + \item \meta{points}: The number of points given to the question. If + non-zero this will cause the points to be printed in the \code{points} + coffin. + \item \meta{bonus}: the same as \meta{points} but for bonus points. + \item \meta{id}: the \acs{id} of the question this heading belongs to. + \end{itemize} +\end{commands} + +In combination with \cs{ForEachQuestion} the command can be used to build a +custom list of questions. An example of its usage can be seen at the German +Q\&A~site \TeX welt: \url{http://texwelt.de/wissen/fragen/6698#6738}. + +\subsection{Load Custom Configurations} +If you have custom configurations you want to be loaded automatically then save +them in a file \code{exsheets\_configurations.cfg}. If this file is present it +will be loaded \cs*{AtBeginDocument}. + +\SetupExSheets{headings=block} + +\part{The \ExSheetslistings\ Package}\label{part:listings} +\section{The Problem} +I knew the day would come when people would ask how to include verbatim +material in the \env{question} and \env{solution} environments. Since they're +defined with the \pkg{environ} package they're reading their environment +bodies like macros read their arguments. This makes it impossible to use +verbatim material inside them\footnote{See the \TeX\ \acs{faq} + \url{http://www.tex.ac.uk/cgi-bin/texfaq2html?label=verbwithin} for reasons + why.}. Now the day has come~\cite{tex.sx:131546}. Soon after the first +question appeared I wrote the first draft for \ExSheetslistings\ for a question +on \TeX.sx~\cite{tex.sx:133907}. + +\section{The Proposed Solution} + +The \ExSheetslistings\ package defines \pkg{listings} environments that place +their contents inside \env{question} and \env{solution} environments. They do +this by writing the listing to a unique auxiliary file -- +questions to \code{\cs*{jobname}-ex\meta{num}.lst} and solutions to +\code{\cs*{jobname}-sol\meta{num}.lst} where \meta{num} is an increasing +integer that ensures that each listing gets a unique file name. Those files +are then included with \cs{lstinputlisting} if and when the question or +solution is printed. + +\begin{environments} + \environment{lstquestion}[\oarg{options}] + A \pkg{listings} environment placed in a \env{question}. + \environment{lstsolution}[\oarg{options}] + A \pkg{listings} environment placed in a \env{solution}. +\end{environments} + +All you have to do to use the package is loading it the usual way: +\begin{sourcecode} + \usepackage{exsheets-listings} +\end{sourcecode} +This will also load the packages \ExSheets\ and \pkg{listings} if they're not +loaded already. + +\begin{example} + % this uses my listings style used in this documentation for all pieces of + % code: + \begin{lstquestion}[% + pre=Explain what this piece of \TeX\ code does:, + listings={style=cnltx}] + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname foo\endcsname\relax + ... + \else + ... + \fi + \end{lstquestion} +\end{example} + +The example already shows two options of these environments. Here is the +complete list: +\begin{options} + \keyval{pre}{text} + \meta{text} is placed before the code in the \env{question} or + \env{solution} environment. + \keyval{post}{text} + \meta{text} is placed after the code in the \env{question} or + \env{solution} environment. + \keyval{options}{options} + Options passed to underlying the \env{question} or \env{solution} + environment. + \keyval{points}{points} + The points assigned to the underlying \env{question} environment. + \keyval{listings}{options} + Options passed to the underlying \pkg{listings} environment. +\end{options} + +There are also two new options for \ExSheets\ that can be set with +\cs{SetupExSheets}: +\begin{options} + \keyval{listings}{options}\Module{question} + Options passed to the underlying \pkg{listings} environment of + \env{lstquestion}. + \keyval{listings}{options}\Module{solution} + Options passed to the underlying \pkg{listings} environment of + \env{lstsolution}. +\end{options} + +\section{Own Environments} + +\begin{commands} + \command{NewLstQuSolPair}[\oarg{options for both environments}\marg{lst question + env}\marg{question env}\oarg{options for lst question env}\marg{lst + solution env}\marg{solution env}\oarg{options for lst solution env}] + Defines two new \pkg{listings} environments that place the listing in a + question environment \meta{question env} or a solution environment + \meta{solution env}. Those underlying environments should be + environments as defined by \cs{NewQuSolPair}. The different options + allow to preset options for the newly defined environments. +\end{commands} + +The existing environments have been defined like this: +\begin{sourcecode} + \NewLstQuSolPair{lstquestion}{question}{lstsolution}{solution} +\end{sourcecode} + +\appendix +\part{Appendix} +\section{A List of all Solutions used in this Manual}\label{sec:solutions:list} +\SetupExSheets{headings=block-wp,solutions-totoc} +\printsolutions + +\end{document} diff --git a/macros/latex/contrib/exsheets/exsheets_headings.cfg b/macros/latex/contrib/exsheets/exsheets_headings.cfg new file mode 100644 index 0000000000..3badcdbbf4 --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets_headings.cfg @@ -0,0 +1,361 @@ +% -------------------------------------------------------------------------- +% the EXSHEETS package +% +% Yet another package for the creation of exercise sheets +% +% -------------------------------------------------------------------------- +% Clemens Niederberger +% Web: https://bitbucket.org/cgnieder/exsheets/ +% E-Mail: contact@mychemistry.eu +% -------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% -------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% -------------------------------------------------------------------------- +% HEADINGS FOR QUESTIONS AND SOLUTIONS +\ProvidesFile{exsheets_headings.cfg} + [ + \c_exsheets_date_tl \c_space_tl + v\c_exsheets_version_tl \c_space_tl + ExSheets~ headings~ instances + ] + +\cs_new:Npn \exsheets_headings_files_loaded: {} + +% EMPTY: +\DeclareInstance { exsheets-heading } { empty } { default } + { + runin = true , + above = \parskip , + below = \parskip , + attach = + { main[l,vc] points[l,vc] (\linewidth + \marginparsep,0pt) } + } + +% SIMPLE: +\DeclareInstance { exsheets-heading } { simple } { default } + { + title-format = \normalsize , + points-pre-code = ( , + points-post-code = ) , + attach = { main[l,t] number[l,t] (0pt,0pt) } , + join = + { + number[r,b] title[l,b] (.333em,0pt) ; + main[l,b] points[l,t] (1em,0pt) + } + } + +% BLOCK, REVERSED: +\DeclareInstance { exsheets-heading } { block-rev } { default } + { + toc-reversed = true , + join = { number[r,B] title[l,B] (.333em,0pt) } , + attach = + { + main[l,vc] number[l,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (\marginparsep,0pt) + } + } + +% BLOCK, SUBTITLE: +\DeclareInstance{exsheets-heading}{block-subtitle}{default}{ + join = { + title[r,B]number[l,B](.333em,0pt) ; + title[r,B]subtitle[l,B](1em,0pt) + } , + attach = { + main[l,vc]title[l,vc](0pt,0pt) ; + main[r,vc]points[l,vc](\marginparsep,0pt) + } +} + +% BLOCK, POINTS WITH THE TITLE: +\DeclareInstance { exsheets-heading } { block-wp } { default } + { + points-pre-code = ( , + points-post-code = ) , + join = + { + title[r,B] number[l,B] (.333em,0pt) ; + title[r,B] points[l,B] (.333em,0pt) + } , + attach = { main[l,vc] title[l,vc] (0pt,0pt) } + } + +% BLOCK, POINTS WITH THE TITLE, REVERSED: +\DeclareInstance { exsheets-heading } { block-wp-rev } { default } + { + toc-reversed = true , + points-pre-code = ( , + points-post-code = ) , + join = + { + number[r,B] title[l,B] (.333em,0pt) ; + number[r,B] points[l,B] (.333em,0pt) + } , + attach = { main[l,vc] number[l,vc] (0pt,0pt) } + } + +% BLOCK WITH NO TITLE: +\DeclareInstance { exsheets-heading } { block-nr } { default } + { + attach = + { + main[l,vc] number[l,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (\marginparsep,0pt) + } + } + +% BLOCK WITH NO TITLE, NUMBER WITH THE TITLE: +\DeclareInstance { exsheets-heading } { block-nr-wp } { default } + { + points-pre-code = ( , + points-post-code = ) , + join = { number[r,vc] points[l,vc] (.333em,0pt) } , + attach = { main[l,vc] number[l,vc] (0pt,0pt) } + } + +% RUNIN, REVERSED: +\DeclareInstance { exsheets-heading } { runin-rev } { default } + { + toc-reversed = true , + runin = true , + title-post-code = \c_space_tl , + attach = + { main[l,vc] points[l,vc] (\linewidth + \marginparsep,0pt) } , + join = + { + main[r,vc] number[r,vc] (0pt,0pt) ; + main[r,vc] title[l,vc] (.333em,0pt) + } + } + +% RUNIN, POINTS WITH THE TITLE: +\DeclareInstance { exsheets-heading } { runin-wp } { default } + { + runin = true , + points-pre-code = ( , + points-post-code = ) \c_space_tl , + join = + { + main[r,vc] title[r,vc] (0pt,0pt) ; + main[r,vc] number[l,vc] (.333em,0pt) ; + main[r,vc] points[l,vc] (.333em,0pt) + } + } + +% RUNIN, POINTS WITH THE TITLE, REVERSED: +\DeclareInstance { exsheets-heading } { runin-wp-rev } { default } + { + toc-reversed = true , + runin = true , + points-pre-code = ( , + points-post-code = ) \c_space_tl , + join = + { + main[r,vc] number[r,vc] (0pt,0pt) ; + main[r,vc] title[l,vc] (.333em,0pt) ; + main[r,vc] points[l,vc] (.333em,0pt) + } + } + +% RUNIN WITH NO TITLE: +\DeclareInstance { exsheets-heading } { runin-nr } { default } + { + runin = true , + number-post-code = \c_space_tl , + attach = + { main[l,vc] points[l,vc] (\linewidth + \marginparsep,0pt) } , + join = { main[r,vc] number[l,vc] (0pt,0pt) } + } + +% RUNIN WITH NO TITLE, POINTS WITH THE TITLE: +\DeclareInstance { exsheets-heading } { runin-nr-wp } { default } + { + runin = true , + points-pre-code = ( , + points-post-code = ) \c_space_tl , + join = + { + main[r,vc] number[l,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (.333em,0pt) + } + } + +% RUNIN WITH NO TITLE, FIXED WIDTH OF NUMBER +\DeclareInstance { exsheets-heading } { runin-fixed-nr } { default } + { + runin = true , + number-pre-code = \hbox to 2em \bgroup , + number-post-code = \hfil\egroup , + attach = + { main[l,vc]points[l,vc](\linewidth+\marginparsep,0pt) } , + join = { main[r,vc]number[l,vc](0pt,0pt) } + } + +% INLINE +\DeclareInstance { exsheets-heading } { inline } { default } + { + inline = true , + number-pre-code = \c_space_tl , + number-post-code = \c_space_tl , + join = + { + main[r,vc] title[r,vc] (0pt,0pt) ; + main[r,vc] number[l,vc] (0pt,0pt) + } + } + +% INLINE, POINTS WITH THE TITLE +\DeclareInstance { exsheets-heading } { inline-wp } { default } + { + inline = true , + number-pre-code = \c_space_tl , + number-post-code = \c_space_tl , + points-pre-code = ( , + points-post-code = ) \c_space_tl , + join = + { + main[r,vc] title[r,vc] (0pt,0pt) ; + main[r,vc] number[l,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (0pt,0pt) + } + } + +% INLINE WITH NO TITLE: +\DeclareInstance { exsheets-heading } { inline-nr } { default } + { + inline = true , + number-post-code = \c_space_tl , + join = { main[r,vc] number[l,vc] (0pt,0pt) } + } + +% CENTERED: +\DeclareInstance { exsheets-heading } { centered } { default } + { + join = { title[r,B] number[l,B] (.333em,0pt) } , + attach = + { + main[hc,vc] title[hc,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (\marginparsep,0pt) + } + } + +% CENTERED, POINTS WITH THE TITLE: +\DeclareInstance { exsheets-heading } { centered-wp } { default } + { + points-pre-code = ( , + points-post-code = ) , + join = + { + title[r,B] number[l,B] (.333em,0pt) ; + title[r,B] points[l,B] (.333em,0pt) + } , + attach = { main[hc,vc] title[hc,vc] (0pt,0pt) } + } + +% MARGIN: +\DeclareInstance { exsheets-heading } { margin } { default } + { + runin = true , + number-post-code = \c_space_tl , + points-pre-code = ( , + points-post-code = ) \c_space_tl , + join = { title[r,b] number[l,b] (.333em,0pt) } , + attach = + { + main[l,vc] title[r,vc] (0pt,0pt) ; + main[l,b] points[r,t] (0pt,0pt) + } + } + +% MARGIN WITH NO TITLE +\DeclareInstance { exsheets-heading } { margin-nr } { default } + { + runin = true , + attach = + { + main[l,vc]number[r,vc](-.333em,0pt) ; + main[r,vc]points[l,vc](\linewidth+\marginparsep,0pt) + } + } + +% RIGHT-ALIGNED: +\DeclareInstance { exsheets-heading } { raggedleft } { default } + { + join = { title[r,B] number[l,B] (.333em,0pt) } , + attach = + { + main[r,vc] title[r,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (\marginparsep,0pt) + } + } + +% MIMICKING KOMA-SECTION: +\DeclareInstance { exsheets-heading } { koma-section } { default } + { + vscale = 2 , + title-format = \Large\bfseries\sffamily , + join = { title[r,B] number[l,B] (.333em,0pt) } , + attach = + { + main[l,vc] title[l,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (\marginparsep,0pt) + } + } + +% FANCY: +\DeclareInstance { exsheets-heading } { fancy } { default } + { + toc-reversed = true , + indent-first = true , + vscale = 2 , + pre-code = \rule{\linewidth}{1pt} , + post-code = \rule{\linewidth}{1pt} , + title-format = \large\scshape\color{rgb:red,0.65;green,0.04;blue,0.07} , + number-format = \large\bfseries\color{rgb:red,0.02;green,0.04;blue,0.48} , + points-format = \itshape , + join = { number[r,B] title[l,B] (.333em,0pt) } , + attach = + { + main[hc,vc] number[hc,vc] (0pt,0pt) ; + main[l,vc] points[r,vc] (-\marginparsep,0pt) + } + } + +% FANCY, POINTS WITH THE TITLE: +\DeclareInstance { exsheets-heading } { fancy-wp } { default } + { + toc-reversed = true , + indent-first = true , + vscale = 2 , + pre-code = \rule{\linewidth}{1pt} , + post-code = \rule{\linewidth}{1pt} , + title-format = \large\scshape\color{rgb:red,0.65;green,0.04;blue,0.07} , + number-format = \large\bfseries\color{rgb:red,0.02;green,0.04;blue,0.48} , + points-format = \itshape , + points-pre-code = ( , + points-post-code = ) , + join = + { + number[r,B] title[l,B] (.333em,0pt) ; + number[r,B] points[l,B] (.333em,0pt) + } , + attach = { main[hc,vc] number[hc,vc] (0pt,0pt) } + } + +\tex_endinput:D diff --git a/macros/latex/contrib/exsheets/exsheets_headings.def b/macros/latex/contrib/exsheets/exsheets_headings.def new file mode 100644 index 0000000000..e7100ce4d6 --- /dev/null +++ b/macros/latex/contrib/exsheets/exsheets_headings.def @@ -0,0 +1,474 @@ +% -------------------------------------------------------------------------- +% the EXSHEETS package +% +% Yet another package for the creation of exercise sheets +% +% -------------------------------------------------------------------------- +% Clemens Niederberger +% Web: https://bitbucket.org/cgnieder/exsheets/ +% E-Mail: contact@mychemistry.eu +% -------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% -------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% -------------------------------------------------------------------------- +% HEADINGS FOR QUESTIONS AND SOLUTIONS +% the 6 base coffins: +\ProvidesFile{exsheets_headings.def} + [ + \c_exsheets_date_tl \c_space_tl + v\c_exsheets_version_tl \c_space_tl + ExSheets~ headings~ object] + +% the object variables: +\bool_new:N \l__exsheets_heading_runin_bool +\bool_new:N \l__exsheets_heading_inline_bool +\bool_new:N \l__exsheets_heading_indent_first_bool +\bool_new:N \l__exsheets_heading_toc_reversed_bool + +\dim_new:N \l__exsheets_heading_above_dim +\dim_new:N \l__exsheets_heading_below_dim +\fp_new:N \l__exsheets_heading_scale_fp + +\tl_new:N \l__exsheets_heading_main_tl +\tl_new:N \l__exsheets_heading_pre_code_tl +\tl_new:N \l__exsheets_heading_post_code_tl + +\tl_new:N \l__exsheets_heading_title_format_tl +\tl_new:N \l__exsheets_heading_title_pre_code_tl +\tl_set:Nn \l__exsheets_heading_title_pre_code_tl { \use:n } +\tl_new:N \l__exsheets_heading_title_post_code_tl + +\tl_new:N \l__exsheets_heading_number_format_tl +\tl_new:N \l__exsheets_heading_number_pre_code_tl +\tl_set:Nn \l__exsheets_heading_number_pre_code_tl { \use:n } +\tl_new:N \l__exsheets_heading_number_post_code_tl + +\tl_new:N \l__exsheets_heading_subtitle_format_tl +\tl_new:N \l__exsheets_heading_subtitle_pre_code_tl +\tl_set:Nn \l__exsheets_heading_subtitle_pre_code_tl { \use:n } +\tl_new:N \l__exsheets_heading_subtitle_post_code_tl + +\tl_new:N \l__exsheets_heading_points_format_tl +\tl_new:N \l__exsheets_heading_points_pre_code_tl +\tl_set:Nn \l__exsheets_heading_points_pre_code_tl { \use:n } +\tl_new:N \l__exsheets_heading_points_post_code_tl +\tl_new:N \l__exsheets_heading_points_post_hook_tl + +\tl_new:N \l__exsheets_heading_joined_coffins_tl +\tl_new:N \l__exsheets_heading_attached_coffins_tl +\seq_new:N \l__exsheets_heading_joined_coffins_seq +\seq_new:N \l__exsheets_heading_attached_coffins_seq + +% internal object functions: +% the following is shamelessly adapted from the `needspace' package by +% Peter Wilson and Herries Press +\cs_new:Npn \exsheets_needspace:n #1 + { + \group_begin: + \dim_set:Nn \l__exsheets_tmpa_dim { #1 } + \skip_vertical:n { \c_zero_dim + \l__exsheets_tmpa_dim } + \tex_penalty:D -100 + \skip_vertical:n { \c_zero_dim - \l__exsheets_tmpa_dim } + \skip_vertical:N \l__exsheets_tmpa_dim + \tex_penalty:D 9999 + \skip_vertical:n { - \l__exsheets_tmpa_dim } + \skip_vertical:N \c_zero_dim + \group_end: + } + +\AtBeginDocument + { + \cs_if_exist:NF \needspace + { \cs_set_eq:NN \needspace \exsheets_needspace:n } + } + +\cs_generate_variant:Nn \seq_set_split:Nnn { NnV } + +\cs_new:Npn \__exsheets_join:N #1 + { + \seq_map_inline:Nn #1 + { + \tl_if_blank:nF { ##1 } + { \exp_after:wN \__exsheets_join_coffin_sequence:w ##1 } + } + } +\cs_new:Npn \__exsheets_join_coffin_sequence:w #1[#2,#3] #4[#5,#6] (#7,#8) + { \__exsheets_join_coffins:nnnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8} } + +\cs_new:Npn \__exsheets_join_coffins:nnnnnnnn #1#2#3#4#5#6#7#8 + { + \coffin_join:cnncnnnn + { l__exsheets_heading_#1_coffin } {#2} {#3} + { l__exsheets_heading_#4_coffin } {#5} {#6} + {#7} + {#8} + } +\cs_new:Npn \__exsheets_attach:N #1 + { + \seq_map_inline:Nn #1 + { + \tl_if_blank:nF {##1} + { \exp_after:wN \__exsheets_attach_coffin_sequence:w ##1 } + } + } +\cs_new:Npn \__exsheets_attach_coffin_sequence:w #1[#2,#3]#4[#5,#6](#7,#8) + { \__exsheets_attach_coffins:nnnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8} } + +\cs_new:Npn \__exsheets_attach_coffins:nnnnnnnn #1#2#3#4#5#6#7#8 + { + \coffin_attach:cnncnnnn + { l__exsheets_heading_#1_coffin } {#2} {#3} + { l__exsheets_heading_#4_coffin } {#5} {#6} + {#7} + {#8} + } + +\prop_new:N \l__exsheets_heading_coffins_prop + +\prg_new_conditional:Npnn \exsheets_if_heading_coffin:n #1 {T,F,TF} + { + \coffin_if_exist:cTF {l__exsheets_heading_#1_coffin} + { \prg_return_true: } + { \prg_return_false: } + } + +\cs_new_protected:Npn \exsheets_new_heading_coffin:n #1 + { \coffin_new:c {l__exsheets_heading_#1_coffin} } + +\cs_new_protected:Npn \exsheets_set_heading_coffin:nn #1#2 + { + \exsheets_if_heading_coffin:nF {#1} + { \exsheets_new_heading_coffin:n {#1} } + \prop_put:Nnn \l__exsheets_heading_coffins_prop {#1} {#2} + } + +\NewDocumentCommand \DeclareExSheetsHeadingContainer {m+m} + { \exsheets_set_heading_coffin:nn {#1} {#2} } + +\exsheets_new_heading_coffin:n {main} +\exsheets_new_heading_coffin:n {pre} +\exsheets_new_heading_coffin:n {post} +\exsheets_new_heading_coffin:n {title} +\exsheets_new_heading_coffin:n {number} +\exsheets_new_heading_coffin:n {points} +\exsheets_new_heading_coffin:n {subtitle} + +\cs_new_protected:Npn \exsheets_heading_format:nn #1#2 + { + \bool_if:NT \l__exsheets_inside_question_bool + { \tl_use:c {l_exsheets_heading_#1_question_format_tl} {#2} } + \bool_if:NT \l__exsheets_inside_solution_bool + { \tl_use:c {l_exsheets_heading_#1_solution_format_tl} {#2} } + } + +% the `exsheets-heading' object: +% #1 = title, +% #2 = number, +% #3 = points +% #4 = bonus +% #5 = id +\DeclareObjectType {exsheets-heading} {5} + +% the `default' template interface: +\DeclareTemplateInterface {exsheets-heading} {default} {5} + { + inline : boolean = false , + runin : boolean = false , + indent-first : boolean = false , + toc-reversed : boolean = false , + vscale : real = 1 , + above : length = 2pt , + below : length = 2pt , + main : tokenlist = , + pre-code : tokenlist = , + post-code : tokenlist = , + title-format : tokenlist = , + title-pre-code : tokenlist = , + title-post-code : tokenlist = , + number-format : tokenlist = , + number-pre-code : tokenlist = , + number-post-code : tokenlist = , + subtitle-format : tokenlist = , + subtitle-pre-code : tokenlist = , + subtitle-post-code : tokenlist = , + points-format : tokenlist = , + points-pre-code : tokenlist = , + points-post-code : tokenlist = , + join : tokenlist = , + attach : tokenlist = + } + +% the `default' template code: +\DeclareTemplateCode {exsheets-heading} {default} {5} + { + inline = \l__exsheets_heading_inline_bool , + runin = \l__exsheets_heading_runin_bool , + indent-first = \l__exsheets_heading_indent_first_bool , + toc-reversed = \l__exsheets_heading_toc_reversed_bool , + vscale = \l__exsheets_heading_scale_fp , + above = \l__exsheets_heading_above_dim , + below = \l__exsheets_heading_below_dim , + main = \l__exsheets_heading_main_tl , + pre-code = \l__exsheets_heading_pre_code_tl , + post-code = \l__exsheets_heading_post_code_tl , + title-format = \l__exsheets_heading_title_format_tl , + title-pre-code = \l__exsheets_heading_title_pre_code_tl , + title-post-code = \l__exsheets_heading_title_post_code_tl , + number-format = \l__exsheets_heading_number_format_tl , + number-pre-code = \l__exsheets_heading_number_pre_code_tl , + number-post-code = \l__exsheets_heading_number_post_code_tl , + subtitle-format = \l__exsheets_heading_subtitle_format_tl , + subtitle-pre-code = \l__exsheets_heading_subtitle_pre_code_tl , + subtitle-post-code = \l__exsheets_heading_subtitle_post_code_tl , + points-format = \l__exsheets_heading_points_format_tl , + points-pre-code = \l__exsheets_heading_points_pre_code_tl , + points-post-code = \l__exsheets_heading_points_post_code_tl , + join = \l__exsheets_heading_joined_coffins_tl , + attach = \l__exsheets_heading_attached_coffins_tl + } + { + \AssignTemplateKeys + \bool_if:NT \l__exsheets_heading_inline_bool + { \cs_set_eq:NN \exsheets_par: \scan_stop: } + \seq_set_split:NnV \l__exsheets_heading_joined_coffins_seq { ; } + \l__exsheets_heading_joined_coffins_tl + \seq_set_split:NnV \l__exsheets_heading_attached_coffins_seq { ; } + \l__exsheets_heading_attached_coffins_tl + \bool_if:nTF + { \l__exsheets_heading_runin_bool || \l__exsheets_heading_inline_bool } + { + \hcoffin_set:Nn \l__exsheets_heading_main_coffin + { + \tl_if_blank:VTF \l__exsheets_heading_main_tl + { \tl_use:N \l__exsheets_heading_title_format_tl \strut } + { \tl_use:N \l__exsheets_heading_main_tl } + } + } + { + \hcoffin_set:Nn \l__exsheets_heading_main_coffin + { + \parbox { \linewidth } + { + \tl_if_blank:VTF \l__exsheets_heading_main_tl + { \tl_use:N \l__exsheets_heading_title_format_tl \strut } + { \tl_use:N \l__exsheets_heading_main_tl } + } + } + } + \hcoffin_set:Nn \l__exsheets_heading_title_coffin + { + \tl_use:N \l__exsheets_heading_title_format_tl + \strut + \tl_use:N \l__exsheets_heading_title_pre_code_tl + { \exsheets_heading_format:nn {title} {#1} } + \tl_use:N \l__exsheets_heading_title_post_code_tl + } + \hcoffin_set:Nn \l__exsheets_heading_number_coffin + { + \tl_if_blank:VTF \l__exsheets_heading_number_format_tl + { \tl_use:N \l__exsheets_heading_title_format_tl } + { \tl_use:N \l__exsheets_heading_number_format_tl } + \strut + \tl_use:N \l__exsheets_heading_number_pre_code_tl + { \exsheets_heading_format:nn {title} {#2} } + \tl_use:N \l__exsheets_heading_number_post_code_tl + } + \hcoffin_set:Nn \l__exsheets_heading_subtitle_coffin + { + \exsheets_if_question_subtitle:T + { + \strut + \tl_use:N \l__exsheets_heading_subtitle_pre_code_tl + { + \group_begin: + \exsheets_heading_format:nn + {subtitle} + { \exsheets_get_question_property:nn {subtitle} {#5} } + \group_end: + } + \tl_use:N \l__exsheets_heading_subtitle_post_code_tl + } + } + \hcoffin_set:Nn \l__exsheets_heading_points_coffin + { + \bool_if:NTF \l__exsheets_parse_points_bool + { + \bool_if:nF + { \fp_compare_p:n { #3 = 0 } && \fp_compare_p:n { #4 = 0 } } + { + \tl_use:N \l__exsheets_heading_points_format_tl + \group_begin: + \tl_use:N \l__exsheets_heading_title_format_tl \strut + \group_end: + \tl_use:N \l__exsheets_heading_points_pre_code_tl + { + \tl_use:N \tl_use:N \l__exsheets_points_format_tl + { + \fp_compare:nF { #3 = 0 } + { + \bool_if:nTF + { + \l__exsheets_points_separate_bonus_bool || + \fp_compare_p:n { #4 = 0 } + } + { + \exsheets_parse_points:n {#3} + \exsheets_points_name:n {#3} + } + { \exsheets_parse_points:n {#3} } + } + \fp_compare:nF { #4 = 0 } + { + \tl_use:N \l__exsheets_points_pre_bonus_marker_tl + \bool_if:nTF + { + \l__exsheets_points_separate_bonus_bool || + \fp_compare_p:n { #3 = 0 } + } + { + \exsheets_print_bonus:n {#4} + \tl_use:N \l__exsheets_points_post_bonus_marker_tl + } + { + \exsheets_parse_bonus:n {#4} + \tl_use:N \l__exsheets_points_post_bonus_marker_tl + \exsheets_points_name:n { #3 + #4 } + } + } + } + } + \tl_use:N \l__exsheets_heading_points_post_code_tl + } + } + {% points/parse = false + \tl_use:N \l__exsheets_heading_points_format_tl + \group_begin: + \tl_use:N \l__exsheets_heading_title_format_tl \strut + \group_end: + \tl_if_eq:xnF {#3} {0} + { + \tl_use:N \l__exsheets_heading_points_pre_code_tl + { \exsheets_print_points:n {#3} } + \tl_use:N \l__exsheets_heading_points_post_code_tl + } + } + } + % this allows users to provide their own point system while also using + % exsheets' positioning mechanism: + \tl_use:N \l__exsheets_heading_points_post_hook_tl + \bool_if:nT + { !\l__exsheets_heading_runin_bool && !\l__exsheets_heading_inline_bool } + { + \coffin_resize:Nnn \l__exsheets_heading_main_coffin { \linewidth } + { + \fp_to_decimal:N \l__exsheets_heading_scale_fp + \coffin_ht:N \l__exsheets_heading_main_coffin + + \l__exsheets_heading_below_dim + } + } + \hcoffin_set:Nn \l__exsheets_heading_pre_coffin + { \tl_use:N \l__exsheets_heading_pre_code_tl } + \hcoffin_set:Nn \l__exsheets_heading_post_coffin + { \tl_use:N \l__exsheets_heading_post_code_tl } + \coffin_join:NnnNnnnn + \l__exsheets_heading_main_coffin {l} {t} + \l__exsheets_heading_pre_coffin {l} {b} {0pt} {0pt} + \coffin_join:NnnNnnnn + \l__exsheets_heading_main_coffin {l} {b} + \l__exsheets_heading_post_coffin {l} {t} {0pt} {0pt} + \prop_map_inline:Nn \l__exsheets_heading_coffins_prop + { \hcoffin_set:cn {l__exsheets_heading_##1_coffin} {##2} } + \__exsheets_join:N \l__exsheets_heading_joined_coffins_seq + \__exsheets_attach:N \l__exsheets_heading_attached_coffins_seq + \bool_if:NTF \l__exsheets_heading_inline_bool + { \exsheets_questions_debug:n {#5} } + { + \skip_vertical:N \l__exsheets_heading_above_dim + \exsheets_needspace:n + { + \coffin_ht:N \l__exsheets_heading_main_coffin + + \coffin_dp:N \l__exsheets_heading_main_coffin + + \l__exsheets_heading_below_dim + + \baselineskip + } + \exsheets_questions_debug:n {#5} + \noindent + } + \skip_set:Nn \parfillskip { 0pt plus 1fil } + \bool_if:nT + { \l__exsheets_questions_totoc_bool && \l__exsheets_inside_question_bool } + { + \use:c {phantomsection} + \addcontentsline { toc } { \l__exsheets_questions_toclevel_tl } + { + \bool_if:NTF \l__exsheets_heading_toc_reversed_bool + { #2 \ #1 } + { #1 \ #2 } + } + } + \bool_if:nT + { \l__exsheets_solutions_totoc_bool && !\l__exsheets_inside_question_bool } + { + \use:c {phantomsection} + \addcontentsline { toc } { \l__exsheets_solutions_toclevel_tl } + { + \bool_if:NTF \l__exsheets_heading_toc_reversed_bool + { #2 \ #1 } + { #1 \ #2 } + } + } + \coffin_typeset:Nnnnn \l__exsheets_heading_main_coffin + { H } { l } { 0pt }{ 0pt } + \bool_if:nT + { !\l__exsheets_heading_runin_bool && !\l__exsheets_heading_inline_bool } + { + \skip_vertical:N \l__exsheets_heading_below_dim + \dim_compare:nF { \parskip = 0pt } + { \skip_vertical:n { -\parskip } } + \bool_if:NTF \l__exsheets_heading_indent_first_bool + { \@afterindenttrue\@afterheading } + { \@afterindentfalse\@afterheading } + } + } + +% the two basic instances: +% BLOCK: +\DeclareInstance { exsheets-heading } { block } { default } + { + join = { title[r,B] number[l,B] (1ex,0pt) } , + attach = + { + main[l,vc] title[l,vc] (0pt,0pt) ; + main[r,vc] points[l,vc] (\marginparsep,0pt) + } + } + +% RUNIN: +\DeclareInstance { exsheets-heading } { runin } { default } + { + runin = true , + number-post-code = \c_space_tl , + attach = + { main[l,vc] points[l,vc] (\linewidth + \marginparsep,0pt) } , + join = + { + main[r,vc] title[r,vc] (0pt,0pt) ; + main[r,vc] number[l,vc] (1ex,0pt) + } + } + +\tex_endinput:D diff --git a/macros/latex/contrib/exsheets/grading-table.pdf b/macros/latex/contrib/exsheets/grading-table.pdf Binary files differnew file mode 100644 index 0000000000..a845bcabb0 --- /dev/null +++ b/macros/latex/contrib/exsheets/grading-table.pdf diff --git a/macros/latex/contrib/exsheets/grading-table.tex b/macros/latex/contrib/exsheets/grading-table.tex new file mode 100644 index 0000000000..ef109bd164 --- /dev/null +++ b/macros/latex/contrib/exsheets/grading-table.tex @@ -0,0 +1,48 @@ +% ---------------------------------------------------------------------------- +% the EXSHEETS package +% +% Yet another package for the creation of exercise sheets +% +% ---------------------------------------------------------------------------- +% Clemens Niederberger +% Web: http://www.mychemistry.eu/forums/forum/exsheets +% E-Mail: contact@mychemistry.eu +% ---------------------------------------------------------------------------- +% Copyright 2011-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% ---------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% ---------------------------------------------------------------------------- +\documentclass{scrartcl} +\usepackage{exsheets} + +\begin{document} + +\begin{question}{3} +\end{question} +\begin{question}{5} +\end{question} +\begin{question}{10} +\end{question} +\begin{question}{8} +\end{question} + +\begin{tabular}{|l|*{\numberofquestions}{c|}c|}\hline + Question & \ForEachQuestion{\QuestionNumber{#1}\iflastquestion{}{&}} & Total \\ \hline + Points & \ForEachQuestion{\GetQuestionProperty{points}{#1}\iflastquestion{}{&}} & \pointssum* \\ \hline + Reached & \ForEachQuestion{\iflastquestion{}{&}} & \\ \hline +\end{tabular} + +\end{document} |