% ----------------------------------------------------------------------------
% 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-2013 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 package consists of the files
%  - exsheets.sty, exsheets_headings.def, exsheets_headings.cfg,
%    exsheets_tasks.def, exsheets_tasks.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.
% ----------------------------------------------------------------------------
\def\exsheets@date{2013/04/04}
\def\exsheets@version{0.8a}

\RequirePackage { expl3 , xparse }
\ProvidesExplPackage
  {exsheets}
  {\exsheets@date}
  {\exsheets@version}
  {Yet another package for the creation of exercise sheets and exams.}

% ----------------------------------------------------------------------------
% 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
\dim_new:N   \l__exsheets_tmpa_dim
\seq_new:N   \l__exsheets_tmpa_seq
\fp_new:N    \l__exsheets_tmpa_fp
\clist_new:N \l__exsheets_tmpa_clist

% ----------------------------------------------------------------------------
% messages
\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} { headings }
  {
    You~requested~the~headings~instance~`#1'~\msg_line_context: \c_space_tl
    which~is~not~defined.~Did~you~forget~to~use~the~package~option~
    `load-headings'?~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~"~\token_to_str:N #1 \c_space_tl"~is~deprecated.~
    Use~"~\token_to_str:N #2 \c_space_tl"~instead.
  }

\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:Npn \exsheets_depr_cmd:nn #1#2
  {
    \cs_new:Npn #1
      { \msg_warning:nnnn { exsheets } { deprecated-command } { #1 } { #2 } #2 }
  }

% ----------------------------------------------------------------------------
\RequirePackage
  { xtemplate , l3sort , l3keys2e , xcolor , etoolbox , environ , pgfcore }

% ----------------------------------------------------------------------------
% color:
\xdefinecolor { exsheetsblue } { rgb } { 0.02 , 0.04 , 0.48 }
\xdefinecolor { exsheetsred  } { rgb } { 0.65 , 0.04 , 0.07 }
\tl_new:N   \g__exsheets_color_tl
\tl_gset:Nn \g__exsheets_color_tl { exsheetsblue }

% ----------------------------------------------------------------------------
% how are questions/solutions/... counted?
\bool_new:N      \l__exsheets_print_number_bool
\bool_set_true:N \l__exsheets_print_number_bool

\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_current_pattern_interpretation_tl
\tl_new:N  \l__exsheets_current_pattern_tl

\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:
\bool_new:N \l__exsheets_load_headings_bool
\bool_new:N \l__exsheets_load_tasks_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

\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_user_format_tl
\tl_set:Nn  \l__exsheets_heading_title_user_format_tl { \normalsize\bfseries }
\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 }

\AtBeginDocument{
  \cs_if_exist:NF \phantomsection
    { \cs_new:Npn \phantomsection {} }
}

\keys_define:nn { exsheets }
  {
    color                     .tl_gset:N  = \g__exsheets_color_tl ,
    counter-format            .code:n     =
      \SaveCounterPattern [ exsheets ]
        \l__exsheets_qu_counter_pattern_tl
        \l__exsheets_qu_counter_interpretation_tl
        { #1 } ,
    counter-within            .code:n     = \@addtoreset{question}{#1} ,
    headings                  .tl_set:N   = \l__exsheets_heading_instance_tl ,
    load-headings             .bool_set:N = \l__exsheets_load_headings_bool ,
    headings-format           .tl_set:N   = \l__exsheets_heading_title_user_format_tl ,
    load-tasks                .bool_set:N = \l__exsheets_load_tasks_bool ,
    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 ,
    auto-label                .bool_set:N = \l__exsheets_auto_label_bool
  }
\keys_set:nn { exsheets} { counter-format = qu. }

% process package options:
\ProcessKeysOptions { exsheets }

% ----------------------------------------------------------------------------
% points for exercises
\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

\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

\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 { (+ }
\tl_new:N         \l__exsheets_points_post_bonus_marker_tl
\tl_set:Nn        \l__exsheets_points_post_bonus_marker_tl { ) }

\cs_new_nopar:Npn \exsheets_set_points_name:n #1
  {
    \tl_if_in:nnTF { #1 } { / }
      { \__exsheets_set_points_name_aux:nn #1 \q_stop }
      { \__exsheets_set_points_name_aux:nn #1 / \q_stop }
  }

\cs_new_nopar:Npn \__exsheets_set_points_name_aux:nn #1/#2 \q_stop
  {
    \tl_set:Nn \l__exsheets_points_name_tl { #1 }
    \tl_set:Nn \l__exsheets_points_name_plural_tl { #1#2 }
  }

\cs_new_nopar:Npn \exsheets_set_bonus_name:n #1
  {
    \tl_if_in:nnTF { #1 } { / }
      { \__exsheets_set_bonus_name_aux:nn #1 \q_stop }
      { \__exsheets_set_bonus_name_aux:nn #1 / \q_stop }
  }

\cs_new_nopar:Npn \__exsheets_set_bonus_name_aux:nn #1/#2 \q_stop
  {
    \tl_set:Nn \l__exsheets_bonus_name_tl { #1 }
    \tl_set:Nn \l__exsheets_bonus_name_plural_tl { #1#2 }
  }

% FIXME: \fp_add will deprecate!
\cs_new_nopar:Npn \exsheets_add_points:n #1
  { \fp_gadd:Nn \g__exsheets_points_sum_fp { #1 } }
\cs_generate_variant:Nn \exsheets_add_points:n { V }

\cs_new_nopar:Npn \exsheets_add_bonus:n #1
  { \fp_gadd:Nn \g__exsheets_bonus_sum_fp { #1 } }
\cs_generate_variant:Nn \exsheets_add_bonus:n { V }

\cs_new_nopar:Npn \exsheets@sum@of@points #1
  { \fp_gset:Nn \g__exsheets_total_points_fp { #1 } }

\cs_new_nopar:Npn \exsheets@sum@of@bonus #1
  { \fp_gset:Nn \g__exsheets_total_bonus_fp { #1 } }

\cs_new_nopar:Npn \exsheets_parse_points:n #1
  {
    \group_begin:
      \tl_use:N \l__exsheets_points_number_format_tl
        {
          \bool_if:NTF \l__exsheets_parse_points_bool
            { \exsheets_num:n { \fp_to_decimal:n { #1 } } }
            { \use:n { \fp_to_decimal:n { #1 } } }
        }
    \group_end:
  }
\cs_generate_variant:Nn \exsheets_parse_points:n { V }

\cs_new_nopar:Npn \exsheets_parse_bonus:n #1
  {
    \group_begin:
      \tl_use:N \l__exsheets_bonus_number_format_tl
        {
          \bool_if:NTF \l__exsheets_parse_points_bool
            { \exsheets_num:n { \fp_to_decimal:n { #1 } } }
            { \use:n { \fp_to_decimal:n { #1 } } }
        }
    \group_end:
  }
\cs_generate_variant:Nn \exsheets_parse_bonus:n { V }

\cs_new_nopar:Npn \exsheets_num:n #1
  {
    \group_begin:
      \fp_set:Nn \l__exsheets_tmpa_tl { #1 }
      \fp_to_tl:N \l__exsheets_tmpa_tl
    \group_end:
  }
\cs_generate_variant:Nn \exsheets_num:n { x }

\cs_new_nopar:Npn \exsheets_points_name:n #1
  {
    \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 \l__exsheets_points_name_plural_tl }
                  {
                    \fp_compare:nTF { #1 <=  1 }
                      { \tl_use:N \l__exsheets_points_name_tl }
                      { \tl_use:N \l__exsheets_points_name_plural_tl }
                  }
              }
              { \tl_use:N \l__exsheets_points_name_plural_tl }
          }
      }
  }
\cs_generate_variant:Nn \exsheets_points_name:n { V }

\cs_new_nopar:Npn \exsheets_bonus_name:n #1
  {
    \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 \l__exsheets_bonus_name_plural_tl }
                  {
                    \fp_compare:nTF { #1 <=  1 }
                      { \tl_use:N \l__exsheets_bonus_name_tl }
                      { \tl_use:N \l__exsheets_bonus_name_plural_tl }
                  }
              }
              { \tl_use:N \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_nopar:Npn \exsheets_print_points:n #1
  {
    \exsheets_parse_points:n { #1 }
    \exsheets_points_name:n { #1 }
  }
\cs_generate_variant:Nn \exsheets_print_points:n { V }

\cs_new_nopar: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 }
  {
    \IfBooleanTF { #1 }
      { \exsheets_parse_points:n { \g__exsheets_total_points_fp } }
      { \exsheets_print_points:n { \g__exsheets_total_points_fp } }
  }

\NewDocumentCommand \bonussum { s }
  {
    \IfBooleanTF { #1 }
      { \exsheets_parse_bonus:n { \g__exsheets_total_bonus_fp } }
      { \exsheets_print_bonus:n { \g__exsheets_total_bonus_fp } }
  }

\NewDocumentCommand \currentpointssum { s }
  {
    \IfBooleanTF { #1 }
      { \exsheets_parse_points:n { \g__exsheets_points_sum_fp } }
      { \exsheets_print_points:n { \g__exsheets_points_sum_fp } }
  }

\NewDocumentCommand \currentbonussum { s }
  {
    \IfBooleanTF { #1 }
      { \exsheets_parse_bonus:n { \g__exsheets_bonus_sum_fp } }
      { \exsheets_print_bonus:n { \g__exsheets_bonus_sum_fp } }
  }

\NewDocumentCommand \totalpoints { s }
  {
    \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 }
              }
          }
      }
  }

\exsheets_depr_cmd:nn { \sumpoints } { \totalpoints* }

\cs_new_nopar: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_nopar:Npn \exsheets_totalbonus:
  {
    \bool_if:NT \l__exsheets_parse_points_bool
      {
        \fp_compare:nF { \g__exsheets_total_bonus_fp = 0 }
          {
            \tl_use:N \c_space_tl
            \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 ,
    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
\int_zero_new:N \l__exsheets_variations_int

\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: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
\prop_new:N \l__exsheets_relgrades_prop
\fp_new:N   \l__exsheets_grade_round_fp
\fp_zero:N  \l__exsheets_grade_round_fp
\bool_new:N \l__exsheets_grades_half_bool

\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: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
\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_solutions_use_bool
\bool_set_true:N   \l__exsheets_solutions_use_bool

\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 }

\cs_new_nopar:Npn \exsheets_glue:N #1
  { \cleaders \vbox:n {} \skip_vertical:N #1 }

\keys_define:nn { exsheets }
  {
    skip-below .code:n =
      \dim_set:Nn \l__exsheets_questions_skip_below_dim { #1 }
      \dim_set:Nn \l__exsheets_solutions_skip_below_dim { #1 }
  }

% Einteilung in Klassen, Themen und andere Gruppierungen:
\prop_new:N \l__exsheets_class_prop
\tl_new:N   \l__exsheets_step_counter_tl
\bool_new:N \l__exsheets_use_this_question_bool

\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 }
%           \exsheets_set_question_properties:n { #1 = ##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:cff { g__exsheets_questions_#1_prop }
              { \int_to_arabic:n { \g__exsheets_questions_id_int } }
              { \tl_use:c { l__exsheets_questions_#1_tl } }
            % add to #2 list, if it's a new one
            \prop_get:cfN { g__exsheets_#2_prop }
              { \tl_use:c { l__exsheets_questions_#1_tl } }
              \l__exsheets_tmpa_tl
            \tl_if_eq:NNT \l__exsheets_tmpa_tl \q_no_value
              {
                \prop_gput:cfn { g__exsheets_#2_prop }
                  { \tl_use:c { 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:cfN { g__exsheets_#2_active_prop }
              { \tl_use:c { l__exsheets_questions_#1_tl } }
              \l__exsheets_tmpa_tl
            \tl_if_eq:NNTF \l__exsheets_tmpa_tl \q_no_value
              {
                \bool_set_false:c { l__exsheets_#1_active_bool }
                \bool_set_false:N \l__exsheets_questions_print_bool
              }
              {
                \bool_set_true:c { l__exsheets_#1_active_bool }
                \bool_set_true:N \l__exsheets_use_this_question_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:NoN \g__exsheets_questions_id_prop
              { \g__exsheets_questions_current_id_tl } \l__exsheets_tmpa_tl
            % get question #1 from number
            \prop_get:coN { g__exsheets_questions_#1_prop }
              { \l__exsheets_tmpa_tl } \l__exsheets_tmpb_tl
            % test if #1 is active
            \prop_get:coN { g__exsheets_#2_active_prop }
              { \l__exsheets_tmpb_tl } \l__exsheets_tmpc_tl
            \tl_if_eq:NNT \l__exsheets_tmpc_tl \q_no_value
              { \bool_set_false:N \l__exsheets_solutions_use_bool }
          }
      }
  }
\cs_generate_variant:Nn \prop_get:NnN { cf }
\cs_generate_variant:Nn \prop_gput:Nnn { cf , cff }

\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 }
%     \exsheets_declare_question_property:n { #1 }
  }
\@onlypreamble \DeclareQuestionClass

% ----------------------------------------------------------------------------
% die 'question' Umgebung
\tl_new:N         \l__exsheets_questions_name_tl
\tl_set:Nn        \l__exsheets_questions_name_tl { Question }
\tl_new:N         \l__exsheets_exsheets_name_tl
\tl_set:Nn        \l__exsheets_exsheets_name_tl { Exercise }

\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

\int_new:N        \g__exsheets_questions_id_int
\int_gzero:N      \g__exsheets_questions_id_int

\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

\NewEnviron { __exsheets_questions_internal: }
  {
    \csappto { BODY }
      {
        \cs_if_eq:NNTF \exsheets_par: \scan_stop:
          { \c_space_tl }
          {
            \exsheets_par:
            \dim_compare:nNnT { \parskip } = { 0pt }
              { \exsheets_glue:N \l__exsheets_questions_skip_below_dim }
          }
      }
    \bool_if:nT
      {
        \l__exsheets_questions_print_bool &&
        \g__exsheets_questions_use_bool &&
        !\l__exsheets_questions_deactivate_bool
      }
      {
        \__exsheets_save_number_in:N \g__exsheets_question_number_prop
        \BODY
      }
  }

\prop_new:N \g__exsheets_questions_id_prop
\prop_new:N \g__exsheets_questions_meta_prop
\prop_new:N \g__exsheets_questions_used_prop
\int_new:N  \g__exsheets_questions_used_int

\tl_new:N   \l__exsheets_questions_id_tl
\tl_new:N   \l__exsheets_questions_meta_tl
\tl_new:N   \g__exsheets_questions_current_id_tl
\tl_new:N   \l__exsheets_title_tl
\tl_new:N   \l__exsheets_questions_label_tl

\bool_new:N \l__exsheets_points_not_given_bool

\cs_new_protected:Npn \__exsheets_read_points: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:Npn \__exsheets_read_points:n #1
  { \__exsheets_read_points:w #1++ \q_stop }

\NewDocumentEnvironment { __exsheets_question: } { gg }
  {
    \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:
    \IfNoValueF { #1 } { \keys_set:nn { exsheets / question } { #1 } }
    % ID:
    \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
          {
            \prop_gput:NVV \g__exsheets_questions_id_prop
              \g__exsheets_questions_id_int
              \g__exsheets_questions_id_int
            \bool_if:NT \l__exsheets_questions_use_bool
              {
                \prop_gput:NVV \g__exsheets_questions_used_prop
                  \g__exsheets_questions_id_int
                  \g__exsheets_questions_id_int
                \int_gincr:N \g__exsheets_questions_used_int
              }
            \tl_gset:Nx \g__exsheets_questions_current_id_tl
              { \int_use:N \g__exsheets_questions_id_int }
          }
          {
            \prop_gput:NVV \g__exsheets_questions_id_prop
              \l__exsheets_questions_id_tl
              \g__exsheets_questions_id_int
            \bool_if:NT \l__exsheets_questions_use_bool
              {
                \prop_gput:NVV \g__exsheets_questions_used_prop
                  \l__exsheets_questions_id_tl
                  \g__exsheets_questions_id_int
                \int_gincr:N \g__exsheets_questions_used_int
              }
            \tl_gset:Nx \g__exsheets_questions_current_id_tl
              { \tl_use:N \l__exsheets_questions_id_tl }
          }
        \tl_if_blank:VTF \l__exsheets_questions_label_tl
          {
            \bool_if:NT \l__exsheets_auto_label_bool
              {
                \exp_args:Nx \label { qu : \g__exsheets_questions_current_id_tl }
                \exp_args:Nx \SetQuestionProperties
                  {
                    ref = \exp_not:N \ref { qu : \g__exsheets_questions_current_id_tl } ,
                    pageref = \exp_not:N \pageref { qu : \g__exsheets_questions_current_id_tl }
                  }
              }
          }
          {
            \exp_args:Nx \label { \l__exsheets_questions_label_tl }
            \exp_args:Nx \SetQuestionProperties
              {
                ref = \exp_not:N \ref { \l__exsheets_questions_label_tl } ,
                pageref = \exp_not:N \pageref { \l__exsheets_questions_label_tl }
              }
          }
      }
    % Punktevergabe:
    \IfNoValueTF { #2 }
      {
        \__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
            \exp_args:Nx \SetQuestionProperties
              { points = \fp_to_tl:N \l__exsheets_points_default_fp }
          }
      }
      {
        \__exsheets_read_points:n { #2 }
        \SetQuestionProperties{points=#2}
      }
    \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
      }
    % meta:
    \tl_if_blank:VF \l__exsheets_questions_meta_tl
      {
        \prop_gput:NVV \g__exsheets_questions_meta_prop
          \g__exsheets_questions_current_id_tl
          \l__exsheets_questions_meta_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: }
      }
    \bool_if:nT
      {
        \g__exsheets_questions_use_bool &&
        !\l__exsheets_questions_deactivate_bool
      }
      {
        \tl_clear:N \l__exsheets_step_counter_tl
        % das ist etwas mühsam: abhängig von der Nutzung der verschiedenen
        % Gruppierungsmöglichkeiten muss der Counter erhöht werden:
        \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_put_right:Nn \l__exsheets_step_counter_tl { y } }
              { \tl_put_right:Nn \l__exsheets_step_counter_tl { n } }
          }
        % erhöhe jetzt, wenn kein Nein dabei war:
        \tl_if_in:NnF \l__exsheets_step_counter_tl { n }
          { \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_add_points:V \l__exsheets_question_points_fp
            \exsheets_add_bonus:V  \l__exsheets_question_bonus_fp
          }
        \bool_if:NT \l__exsheets_questions_print_bool
          {
            \bool_if:NTF \l__exsheets_exam_bool
              { \tl_set_eq:NN \l__exsheets_title_tl \l__exsheets_questions_name_tl }
              { \tl_set_eq:NN \l__exsheets_title_tl \l__exsheets_exsheets_name_tl }
            \__exsheets_use_heading:VVVnn
              \l__exsheets_question_heading_instance_tl
              \l__exsheets_title_tl
              \l__exsheets_qu_counter_interpretation_tl
              { \l__exsheets_question_points_fp }
              { \l__exsheets_question_bonus_fp }
          }
      }
    \__exsheets_questions_internal:
  }
  { \end__exsheets_questions_internal: }

% current question number:
\prop_new:N \g__exsheets_question_number_prop

\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 }
    \iow_now:Nx \@auxout { \exsheets@save@number { #2 } { #3 } }
  }
\cs_generate_variant:Nn \prop_get:NnNTF { Nx }

\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} }
          }
      }
  }

\cs_new:Npn \__exsheets_restore_number_from_and_do:Nnn #1#2#3
  {
    \prop_get:NnN #1 { #2 } \l__exsheets_tmpc_tl
    \tl_if_eq:NNF \l__exsheets_tmpc_tl \q_no_value
      {
        \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 }

\NewDocumentCommand \QuestionNumber { m }
  { \exsheets_question_number:n { #1 } }

\cs_new_protected:Npn \exsheets_question_number:n #1
  {
    \prop_get:NnNTF \g__exsheets_questions_id_prop { #1 } \l__exsheets_tmpa_tl
      { \__exsheets_question_number:c { exsheets@question@\l__exsheets_tmpa_tl } }
      { \textbf{??} }
  }
 
\cs_new: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 }
  }

% ----------------------------------------------------------------------------
% title of a question:
\input { exsheets_headings.def }
\bool_if:NT \l__exsheets_load_headings_bool
  { \input { exsheets_headings.cfg } }
% #1: instance
% #2: title
% #3: number
% #4: points
% #5: bonus
\cs_new_nopar:Npn \__exsheets_use_heading:nnnnn #1#2#3#4#5
  {
    \IfInstanceExistTF { exsheets-heading } { #1 }
      { \UseInstance { exsheets-heading } { #1 } }
      {
        \msg_warning:nnx { exsheets} { headings } { #1 }
        \UseInstance { exsheets-heading } { block }
      }
    { #2 } { #3 } { #4 } { #5 }
  }
\cs_generate_variant:Nn \__exsheets_use_heading:nnnnn { V , VV , VVV }

\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

% 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_exsheets_name_tl { #1 }
      \tl_set:Nn \l__exsheets_questions_name_tl { #1 } ,
    headings        .tl_set:N    = \l__exsheets_question_heading_instance_tl ,
    meta            .tl_set:N    = \l__exsheets_questions_meta_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
  }

% ----------------------------------------------------------------------------
% 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
  }

\NewDocumentCommand \SetQuestionProperties { m }
  { \exsheets_set_question_properties:n { #1 } }

\cs_new_protected:Npn \__exsheets_question_set_property:nn #1#2
  {
    \prop_gput:cVn { g__exsheets_question_property_#1_prop }
      \g__exsheets_questions_current_id_tl { #2 }
  }

\NewDocumentCommand \GetQuestionProperty { mm }
  { \exsheets_get_question_property:nn { #1 } { #2 } }

\cs_new:Npn \exsheets_get_question_property:nn #1#2
  {
    \prop_if_in:cnT { g__exsheets_question_property_#1_prop } { #2 }
      { \prop_get:cn { g__exsheets_question_property_#1_prop } { #2 } }
  }

\int_new:N \g__exsheets_tmpa_int
\cs_new_protected:Npn \ForEachQuestion #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 }
  }

\cs_new:Npn \iflastquestion
  {
    \int_compare:nTF
      { \g__exsheets_questions_used_int = \g__exsheets_tmpa_int }
  }
  
\cs_new:Npn \numberofquestions
  { \int_use:N \g__exsheets_questions_used_int }

% ----------------------------------------------------------------------------
% debug-Info:
\bool_new:N       \l__exsheets_questions_debug_bool
\bool_set_false:N \l__exsheets_questions_debug_bool

\colorlet { exsheetsdebugcolor } { yellow }

\cs_new:Npn \exsheets_debug_box:nn #1#2
  {
    \exsheets_par:
    \noindent
    \group_begin:
      \normalfont\normalsize\normalcolor
      \colorbox { exsheetsdebugcolor }
        { \parbox { \dim_eval:n { #1  - 2 \fboxsep } } { #2 } }
    \group_end:
    \exsheets_par:
  }

\cs_new:Npn \__exsheets_list_comma: {}

\cs_new_nopar:Npn \exsheets_questions_debug:
  {
    \bool_if:nT
      { \l__exsheets_questions_debug_bool && \l__exsheets_inside_question_bool }
      {
        \exsheets_debug_box:nn { \linewidth }
          {
            \fbox
              {
                ID:~
                \textit
                  {
                    \tl_if_blank:VTF \l__exsheets_questions_id_tl
                      { \int_use:N \g__exsheets_questions_id_int }
                      { \tl_use:N \l__exsheets_questions_id_tl }
                  }
              }
            \cs_set_protected:Npn \__exsheets_list_comma:
              { ~ \cs_set:Npn \__exsheets_list_comma: { ,~ } }
            \prop_map_inline:Nn \l__exsheets_class_prop
              {
                \bool_if:cT { l__exsheets_questions_##2_bool }
                  {
                    \__exsheets_list_comma: ##2:~
                    \textit { \tl_use:c { l__exsheets_questions_##2_tl } }
                  }
              }
          }
      }
  }

\NewDocumentCommand \DebugExSheets { G{true} }
  { \use:c { bool_set_#1:N } \l__exsheets_questions_debug_bool }

\cs_new:Npn \CurrentQuestionID { \g__exsheets_questions_current_id_tl }

% ----------------------------------------------------------------------------
% include random/selected questions from a file:
\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_set_true:N \l__exsheets_include_all_bool
\prop_new:N      \g__exsheets_selected_questions_prop
\clist_new:N     \l__exsheets_include_id_clist
\clist_new:N     \l__exsheets_exclude_id_clist
\clist_new:N     \questionsincludedlast
\int_new:N       \l__exsheets_include_random_int
\int_zero:N      \l__exsheets_include_random_int

\cs_new:Npn \exsheets_file_input_if_exist:n #1
  { \file_if_exist:nT { #1 } { \file_input:n { #1 } } }

\cs_new_protected:Npn \exsheets_prop_count:N #1
  {
    \__exsheets_prop_count:NN #1 \l_tmpa_int
    \int_use:N \l_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
    \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_tmpc_int \g__exsheets_questions_id_int
        \exsheets_file_input_if_exist:n { ##1 }
        \__exsheets_prop_count:NN
          \g__exsheets_selected_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_selected_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_selected_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
        \__exsheets_select_question_random:n { ##1 }
        \clist_gclear:N \questionsincludedlast
        \bool_if:nTF
          { \l__exsheets_include_random_bool || \l__exsheets_include_by_id_bool }
          {
            \clist_gset_eq:NN
              \questionsincludedlast
              \l__exsheets_include_id_clist
          }
          {
            \prop_map_inline:Nn \g__exsheets_selected_questions_prop
              {
                \clist_if_in:NnF \l__exsheets_exclude_id_clist { ####2 }
                  { \clist_gput_right:Nn \questionsincludedlast { ####2 } }
              }
          }
        \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_selected_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
      }
    \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 following option does _not_ set \l__exsheets_include_random_bool
    % so it can be combined with the `random' option:
    exclude .code:n     =
      \bool_set_false:N \l__exsheets_include_all_bool
      \bool_set_false:N \l__exsheets_include_by_id_bool
      \clist_set:Nn \l__exsheets_exclude_id_clist { #1 } ,
    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 }
  }

\int_new:N \g__exsheets_selection_number_int

\cs_new_protected:Npn \__exsheets_select_question:n #1
  {
    \bool_if:NT \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
                \exp_args:NNx
                \prop_gput:Nnn \g__exsheets_selected_questions_prop
                  { \int_use:N \g__exsheets_selection_number_int } { #1 }
              }
          }
          {
            \int_gincr:N \g__exsheets_questions_id_int
            \int_set:Nn \l__exsheets_tmpa_int
              {
                \int_mod:nn
                  { \g__exsheets_questions_id_int }
                  { \g__exsheets_selection_number_int }
              }
            \int_compare:nT { \l__exsheets_tmpa_int = 0 }
              {
                \int_set_eq:NN
                  \l__exsheets_tmpa_int
                  \g__exsheets_selection_number_int
              }
            \prop_get:NxN \g__exsheets_selected_questions_prop
              {  \int_use:N \l__exsheets_tmpa_int }
              \l__exsheets_tmpa_tl
            \bool_if:NF \l__exsheets_include_all_bool
              { \__exsheets_select_question_by_id:V \l__exsheets_tmpa_tl }
          }
      }
  }
\cs_generate_variant:Nn \__exsheets_select_question:n { V }
\cs_generate_variant:Nn \prop_get:NnN { Nx }

\cs_new_protected:Npn \__exsheets_select_question_by_id:n #1
  {
    \bool_if:nTF
      { \l__exsheets_include_by_id_bool || \l__exsheets_include_random_bool }
      {% parsing list of included IDs
        \clist_if_in:NnTF
          \l__exsheets_include_id_clist
          { #1 }
          { \bool_gset_true:N  \g__exsheets_questions_use_bool }
          { \bool_gset_false:N \g__exsheets_questions_use_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 }
      }
  }
\cs_generate_variant:Nn \__exsheets_select_question_by_id:n { V }

\tl_new:N \l__exsheets_include_id_tl
\bool_new:N \l__exsheets_use_selection_bool
% 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_selected_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_selected_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_selected_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 } }
                                  }
                              }
                          }
                        \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
                              }
                          }
                      }
                  }
              }
          }
      }
  }

\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:
\bool_new:N       \l__exsheets_solutions_print_bool
\bool_set_false:N \l__exsheets_solutions_print_bool
\bool_new:N       \l__exsheets_solutions_print_here_bool
\bool_set_false:N \l__exsheets_solutions_print_here_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

% \prop_new:N       \g__exsheets_question_number_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

\tl_new:N         \l__exsheets_solutions_name_tl
\tl_set:Nn        \l__exsheets_solutions_name_tl { Solution }

\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:Nff \g__exsheets_solutions_content_prop
      { \int_use:N \g__exsheets_questions_id_int }
      { #1 }
    \prop_gput:Nff \g__exsheets_solutions_questions_id_prop
      { \int_use:N \g__exsheets_questions_id_int }
      { \tl_use:N \g__exsheets_questions_current_id_tl }
    \prop_gput:Nff \g__exsheets_solutions_names_prop
      { \int_use:N \g__exsheets_questions_id_int }
      { \tl_use:N \l__exsheets_solutions_name_tl }
    % print here
    \bool_if:NT \l__exsheets_solutions_print_here_bool
      {
        \int_set:Nn \l__exsheets_counter_qu_int { \arabic{question} }
        \__exsheets_get_sectioning_numbers:
        \__exsheets_solutions_name:VV
          \l__exsheets_qu_counter_interpretation_tl
          \l__exsheets_solutions_name_tl
        \use:n { #1 }
        \cs_if_eq:NNTF \exsheets_par: \scan_stop:
          { \c_space_tl }
          {
            \exsheets_par:
            \dim_compare:nNnT { \parskip } = { 0pt }
              { \exsheets_glue:N \l__exsheets_solutions_skip_below_dim }
          }
      }
  }
\cs_generate_variant:Nn \prop_gput:Nnn { Nff,Nfx,Nfn,Nxx }
\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 }
  }

\bool_new:N       \l__exsheets_inside_solution_bool
\bool_set_false:N \l__exsheets_inside_solution_bool

\tl_new:N \l__exsheets_use_solution_tl

\NewDocumentEnvironment { __exsheets_solution: } { g }
  {
    \tl_clear:N \l__exsheets_use_solution_tl
    \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 { l__exsheets_##2_active_bool }
            )
             ||
            ! \bool_if_p:c { g__exsheets_use_##1_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: }

\bool_new:N       \l__exsheets_solutions_runin_bool
\bool_set_false:N \l__exsheets_solutions_runin_bool

\cs_new_nopar:Npn \__exsheets_solutions_name:nn #1#2
  {
    \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:Vnnnn
      \l__exsheets_solution_heading_instance_tl
      { #2 } { #1 } { 0 } { 0 }
  }
\cs_generate_variant:Nn \__exsheets_solutions_name:nn { VV }

\tl_new:N  \l__exsheets_solutions_name_style_tl
\tl_set:Nn \l__exsheets_solutions_name_style_tl { \normalsize \bfseries }

\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
    \iow_now:Nx \@auxout
      {
        \token_to_str:N \newlabel { exse:#1 }
          { { \arabic { section } } { \thepage } }
      }
    \cs_if_exist:NT \thechapter
      {
        \iow_now:Nx \@auxout
          {
            \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_ref:n #1
  {
    \cs_if_exist:cTF { r@#1 }
     { \__exsheets_ref_aux:n { #1 } }
     {
       1\relax
       \protect\G@refundefinedtrue
       \@latex@warning{exlabel `#1' on page \thepage \space undefined}%
     }
  }

\cs_new:Npn \__exsheets_ref_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_ref: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 } }
  }

\int_new:N \l__exsheets_counter_ch_int
\int_new:N \l__exsheets_counter_sec_int
\int_new:N \l__exsheets_counter_qu_int

\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} }
  }

\cs_new:Npn \__exsheets_print_solution_if:nn #1#2
  {
    \exp_args:No \int_compare:nT { #2 }
      {
        \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
        \eSaveCounterPatternFrom [ exsheets ]
          \l__exsheets_current_pattern_interpretation_tl
          \l__exsheets_current_pattern_tl
          \l__exsheets_qu_counter_pattern_tl
        \exsheets_solutions_print_name:VV
          \l__exsheets_current_pattern_tl
          \l__exsheets_tmpa_tl
        \tl_use:N \l__exsheets_tmpb_tl
        \cs_if_eq:NNTF \exsheets_par: \scan_stop:
          { \c_space_tl }
          {
            \exsheets_par:
            \dim_compare:nNnT { \parskip } = { 0pt }
              { \exsheets_glue:N \l__exsheets_solutions_skip_below_dim }
          }
      }
  }

% print by section:
\cs_new:Npn \exsheets_print_solutions_section:n #1
  {
    \tl_if_blank:nTF { #1 }
      {
        \prop_map_inline:Nn \g__exsheets_question_number_prop
          {
            \prop_if_in:NnT \g__exsheets_solutions_names_prop { ##1 }
              {
                \__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_number_prop
              {
                \prop_if_in:NnT \g__exsheets_solutions_names_prop { ##1 }
                  {
                    \__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_number_prop
          {
            \prop_if_in:NnT \g__exsheets_solutions_names_prop { ##1 }
              { \__exsheets_print_solutions_section:nnn { ##1 } { ##2 } { #1 } }
          }
      }
  }

\cs_new:Npn \__exsheets_print_solutions_section:nnn #1#2#3
  {
    \__exsheets_read_number:w #2 \q_stop
    \__exsheets_print_solution_if:nn { #1 }
      { \l__exsheets_counter_sec_int = #3 }
  }

% print by chapter:
\cs_new:Npn \exsheets_print_solutions_chapter:n #1
  {
    \tl_if_blank:nTF { #1 }
      {
        \prop_map_inline:Nn \g__exsheets_question_number_prop
          {
            \prop_if_in:NnT \g__exsheets_solutions_names_prop { ##1 }
              {
                \__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_number_prop
              {
                \prop_if_in:NnT \g__exsheets_solutions_names_prop { ##1 }
                  {
                    \__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_number_prop
          {
            \prop_if_in:NnT \g__exsheets_solutions_names_prop { ##1 }
              { \__exsheets_print_solutions_chapter:nnn { ##1 } { ##2 } { #1 } }
          }
      }
  }

\cs_new:Npn \__exsheets_print_solutions_chapter:nnn #1#2#3
  {
    \__exsheets_read_number:w #2 \q_stop
    \__exsheets_print_solution_if:nn { #1 }
      { \l__exsheets_counter_ch_int = #3 }
  }

% print all:
\cs_new:Npn \exsheets_print_solutions_all:
  {
    \prop_map_function:NN \g__exsheets_question_number_prop
      \__exsheets_print_solutions_all:nn
  }

\cs_new_protected:Npn \__exsheets_print_solutions_all:nn #1#2
  {
    \__exsheets_read_number:w #2 \q_stop
    \prop_get:NnNT \g__exsheets_solutions_names_prop
      { #1 } \l__exsheets_tmpa_tl
      {
        \tl_set_eq:NN \l__exsheets_solutions_name_tl \l__exsheets_tmpa_tl
        \prop_get:NnN \g__exsheets_solutions_content_prop
          { #1 } \l__exsheets_tmpb_tl
        \eSaveCounterPatternFrom [ exsheets ]
          \l__exsheets_current_pattern_interpretation_tl
          \l__exsheets_current_pattern_tl
          \l__exsheets_qu_counter_pattern_tl
        \exsheets_solutions_print_name:VV
          \l__exsheets_current_pattern_tl
          \l__exsheets_tmpa_tl
        \tl_use:N \l__exsheets_tmpb_tl
        \cs_if_eq:NNTF \exsheets_par: \scan_stop:
          { \c_space_tl }
          {
            \exsheets_par:
            \dim_compare:nNnT { \parskip } = { 0pt }
              { \exsheets_glue:N \l__exsheets_solutions_skip_below_dim }
          }
      }
  }

% 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_reversed: }
              { \sort_ordered: }
          }
      }
    \seq_map_inline:Nn \l__exsheets_tmpa_seq
      {
        \group_begin:
          \tl_if_eq:nnF { ##1 } { \q_no_value }
            {
              \prop_get:NnNT \g__exsheets_solutions_names_prop
                { ##1 } \l__exsheets_tmpa_tl
                {
                  \prop_get:NnN \g__exsheets_solutions_content_prop
                    { ##1 } \l__exsheets_tmpb_tl
                  \__exsheets_restore_number_from_and_do:Nnn
                    \g__exsheets_question_number_prop
                    { ##1 }
                    {
                      \eSaveCounterPatternFrom [ exsheets ]
                        \l__exsheets_current_pattern_interpretation_tl
                        \l__exsheets_current_pattern_tl
                        \l__exsheets_qu_counter_pattern_tl
                      \exsheets_solutions_print_name:VV
                        \l__exsheets_current_pattern_tl
                        \l__exsheets_tmpa_tl
                      \tl_use:N \l__exsheets_tmpb_tl
                      \cs_if_eq:NNTF \exsheets_par: \scan_stop:
                        { \c_space_tl }
                        {
                          \exsheets_par:
                           \dim_compare:nNnT { \parskip } = { 0pt }
                             { \exsheets_glue:N \l__exsheets_solutions_skip_below_dim }
                        }
                    }
                }
            }
        \group_end:
      }
  }

\cs_new_nopar: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_nopar:Npn \exsheets_solutions_print_name:nn #1#2
  {
    \tl_set_rescan:Nnn \l__exsheets_tmpa_tl
      { \char_set_catcode_letter:N \@ } { #1 }
    \tl_if_in:nnTF { #1 } { @@@ }
      { \__exsheets_solutions_name:nn { } { #2 } }
      { \__exsheets_solutions_name:nn { #1 } { #2  } }
    \tex_penalty:D \c_ten_thousand
  }
\cs_generate_variant:Nn \exsheets_solutions_print_name:nn { VV }

\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 }

\bool_new:N      \l__exsheets_print_byID_sorted_bool
\bool_set_true:N \l__exsheets_print_byID_sorted_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_true:N  \l__exsheets_solutions_print_here_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
  }

% ----------------------------------------------------------------------------
% create question/solution pairs
\cs_new:Npn \__exsheets_new_qu_sol_pair:nnnn #1#2#3#4
  {
    \NewDocumentEnvironment { #1 } { O{}G{} }
      { \__exsheets_question: {#2,##1} {##2} }
      { \end__exsheets_question: }
    \NewDocumentEnvironment { #3 } { O{} }
      { \__exsheets_solution: {#4,##1} }
      { \end__exsheets_solution: }
  }

\cs_new:Npn \__exsheets_renew_qu_sol_pair:nnnn #1#2#3#4
  {
    \RenewDocumentEnvironment { #1 } { O{}G{} }
      { \__exsheets_question: {#2,##1} {##2} }
      { \end__exsheets_question: }
    \RenewDocumentEnvironment { #3 } { O{} }
      { \__exsheets_solution: {#4,##1} }
      { \end__exsheets_solution: }
  }

\NewDocumentCommand \NewQuSolPair { mO{}mO{} }
  { \__exsheets_new_qu_sol_pair:nnnn { #1 } { #2 } { #3 } { #4 } }
\@onlypreamble \NewQuSolPair

\NewDocumentCommand \RenewQuSolPair { mO{}mO{} }
  { \__exsheets_renew_qu_sol_pair:nnnn { #1 } { #2 } { #3 } { #4 } }
\@onlypreamble \RenewQuSolPair

% ----------------------------------------------------------------------------
% the `tasks' list
\bool_if:NTF \l__exsheets_load_tasks_bool
  { \RequirePackage [ more ] { tasks } }
  { \RequirePackage { tasks } }
\AddCounterPattern* [ tasks ] { question } { qu }
\ReadCounterFrom [ tasks ] { question } \l__exsheets_counter_qu_int

% ----------------------------------------------------------------------------
% the \blank{<words>} command
\RequirePackage { ulem } \normalem
\dim_new:N  \l__exsheets_blank_dim
\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 }
\box_new:N  \l__exsheets_blank_box
\bool_new:N \l__exsheets_blank_width_bool
\bool_new:N \l__exsheets_blank_linespread_bool

\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 }
  }

\NewDocumentCommand \blank { som }
  {
    \group_begin:
      \IfNoValueF { #2 } { \keys_set:nn { exsheets / blank } { #2 } }
      \mode_if_horizontal:TF
        { \exsheets_blank:n { #3 } }
        {
          \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
            }
        }
    \group_end:
  }

\cs_new_protected:Npn \exsheets_blank:n #1
  {
    \box_clear:N \l__exsheets_blank_box
    \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_tmpa_fp { \dim_to_fp:n { #1 } }
        \fp_mul:Nn \l_tmpa_fp { \l__exsheets_blank_scale_tl }
        \dim_set:Nn \l__exsheets_tmpa_dim { \fp_to_dim:N \l_tmpa_fp }
      }
    \dim_compare:nTF { \l__exsheets_tmpa_dim > 2em }
      {
        \exsheets_write_blank:n { \skip_horizontal:n { 1em } }
        \dim_sub:Nn \l__exsheets_tmpa_dim { 2em }
        \dim_do_while:nn { \l__exsheets_tmpa_dim > \c_zero_dim }
          {
            \tex_penalty:D \hyphenpenalty
            \dim_compare:nTF { \l__exsheets_tmpa_dim < 1pt }
              { \exsheets_write_blank:n { \skip_horizontal:N \l__exsheets_tmpa_dim } }
              { \exsheets_write_blank:n { \skip_horizontal:n { 1pt } } }
            \dim_sub:Nn \l__exsheets_tmpa_dim { 1pt }
          }
        \exsheets_write_blank:n { \skip_horizontal:n { 1em } }
      }
      { \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:
% 
% \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:
    \group_begin:
      \dim_set:Nn \l_tmpa_dim { #2 }
      \dim_set:Nn \l_tmpb_dim { \pagegoal - \pagetotal }
      \dim_compare:nTF { \l_tmpa_dim > \l_tmpb_dim }
        {
          \vfil \break
          \IfBooleanF { #1 }
            {
              \dim_sub:Nn \l_tmpa_dim { \l_tmpb_dim }
              \vspace* { \l_tmpa_dim }
            }
        }
        { \vspace* { #2 } }
    \group_end:
  }
\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{points}
\bool_if:NT \l__exsheets_auto_label_bool
  {
    \DeclareQuestionProperty{ref}
    \DeclareQuestionProperty{pageref}
  }

% classs:
\DeclareQuestionClass{class}{classes}
\DeclareQuestionClass{topic}{topics}

% ----------------------------------------------------------------------------
% Sprachanpassungen
\file_if_exist:nT { translations.sty }
  {
    \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 } { Exercise     }
    \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 } { \O{}velse    }
    \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 { 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 } { Opl\o{}sning }
    \DeclareTranslation { Portuges  } { exsheets-solution-name } { Solu\c c\~ao }
    % the actual translating
    \tl_set:Nn \l__exsheets_exsheets_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
  {
    \iow_now:Nx \@auxout
      {
        \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 } }
      }
  }

% ----------------------------------------------------------------------------
% 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
                       - `translations' got \LoadDictionary and \LoadDictionaryFor
                         added and loads of languages defined.
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
                       - translations: new command \DeclareDictTranslation
                       - 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       - translations: bug fix in \DeclareDictTranslation
                       - exsheets: added Portuguese translations
                       - tasks: corrected \seq_length:N => \seq_count:N

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TODO:
- points/decimal-marker, points/frac (?), points/format (?,im interface)
