0% found this document useful (0 votes)
4 views85 pages

Ex Frame

The exframe package is a LATEX 2ε framework designed for typesetting exercises and exam questions along with their solutions, featuring customizable layouts, point management, and metadata handling. It supports various environments for problems, subproblems, and solutions, allowing for flexible display options and consistent numbering. The package is aimed primarily at educational contexts but is adaptable for broader uses.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views85 pages

Ex Frame

The exframe package is a LATEX 2ε framework designed for typesetting exercises and exam questions along with their solutions, featuring customizable layouts, point management, and metadata handling. It supports various environments for problems, subproblems, and solutions, allowing for flexible display options and consistent numbering. The package is aimed primarily at educational contexts but is adaptable for broader uses.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 85

The exframe Package

Niklas Beisert

Institut für Theoretische Physik


Eidgenössische Technische Hochschule Zürich
Wolfgang-Pauli-Strasse 27, 8093 Zürich, Switzerland
[email protected]

2020/02/24, v3.4

Abstract
exframe is a LATEX 2ε package which provides a general purpose framework to describe
and typeset exercises and exam questions along with their solutions. The package
features mechanisms to hide or postpone solutions, to assign and handle points, to
collect problems on exercise sheets, to store and use metadata and to implement a
consistent numbering. It also provides a very flexible interface for configuring and
customising the formatting, layout and representation of the exercise content.

Contents
1 Introduction 2

2 Usage 3
2.1 Exercise Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Solution and Problem Display . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4 Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.5 Labels and Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.6 Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7 Exercise Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.8 Package Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3 Information 16
3.1 Copyright . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2 Files and Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Related Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.4 Feature Suggestions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.5 Revision History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

A Standalone Sample 20

B Multipart Sample 27
B.1 Main File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
B.2 Sheet File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
B.3 Individual Problem Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
B.4 Make Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

1
C Implementation 38
C.1 General Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
C.2 Package Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
C.3 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
C.4 Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
C.5 Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
C.6 Counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
C.7 Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
C.8 Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
C.9 Tag Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
C.10 Sheet Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
C.11 Problem Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
C.12 Problem Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
C.13 Subproblem Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
C.14 Solution Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
C.15 Solution Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
C.16 Interaction with metastr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

1 Introduction
This package provides a framework to describe and typeset exercises (homework problems,
classroom exercises, quizzes, exam questions, exercise questions in books and lecture notes,
. . . ) and their solutions or answers. The aim of this package is to set up a few LATEX
environments into which questions and corresponding answers can be filled conveniently.
The main task of the package is to manage the text and data that are provided in the
source document, perform some common operations on them, and then output the content
appropriately. The package has the following goals, tasks and features:

• The package is designed with generality in mind. It is meant to be usable in many


different situations. The primary target is science and education, but it may well be
useful in other areas.
• The package defines a basic functional layout for the output and provides many options
to reshape the layout and formatting according to the author’s needs and wishes.
• The package can handle two layers of exercises: main problems and subproblems. The
use of subproblems is optional.
• The display of solutions can be configured: Solutions can be hidden for a hand-out
version of exercise sheets. When displayed, they may appear immediately, collectively
after the problem, at the end of each sheet or at some manually defined location.
• The package can handle exercise sheets which combine several exercise problems: A
LATEX document can consist of an individual sheet or of a collection of sheets (e.g.
spanning a lecture course). In the latter case, the document files can be set up such
that single sheets as well as a collection of all sheets can be compiled; the package
childdoc may be of assistance.
• The package can handle points to be credited: Points will be displayed according to
the layout. Overall points for a problem or a sheet can be added automatically. Points
can also be stored and used elsewhere.
• The package provides an interface to specify exercise metadata (author, source, . . . ):
Some basic types of metadata are predefined and more specific metadata categories
can be added.

2
• The package can use alternative counters for equations within solutions (and prob-
lems). This is to ensure a consistent numbering independently of whether solutions
are output or not.

2 Usage
To use the package exframe add the command

\usepackage{exframe}

to the preamble of the LATEX document.

2.1 Exercise Environments


The package provides four environments to describe the main entities of exercise problems.
Additional information on the exercises can be provided in the optional arguments to these
environments which will be discussed in the following sections. Furthermore, a limited set
of commands is provided for control and extra features, see the sections below for details.
problem The problem environment describes an exercise problem:

\begin{problem}[opts]
problem text and subproblems
\end{problem}

As one of the many available options opts, one can provide a title for the exercise by speci-
fying title={title}. If no title is given, the problem number will be displayed instead. See
section 2.3 and section 2.4 for a description of the available options.
subproblem The subproblem environment describes a subproblem, part or an individual question of an
exercise problem:

\begin{subproblem}[opts]
subproblem text
\end{subproblem}

A subproblem environment must be contained within a problem environment (however, a


problem block need not contain subproblem blocks).
solution The solution environment describes the solution to a problem or a subproblem:

\begin{solution}[opts]
solution text
\end{solution}

A solution environment should be at the end of a subproblem or problem environment


(it is not mandatory to provide a solution). It can be contained within the corresponding
environment or it can follow it. Depending on the choice of solution display, see section
2.2, the output may have a slightly different layout. In terms of logic, it is preferred to
define a solution within the corresponding environment; this may also have some technical
advantages and produce a slightly better result in terms of layout.
sheet The sheet environment describes an exercise sheet:
\begin{sheet}[opts]
sheet text and problems
\end{sheet}

3
A sheet typically contains one or several problems (it is not mandatory to group problems
into a sheet). There may or may not be additional auxiliary text introducing the problems.
A header will be added to the sheet according to the specified layout.

2.2 Solution and Problem Display


There are several options to control the output of solutions and of problems.
solutions Most importantly, the display of solutions can be disabled or enabled altogether:

\exercisesetup{solutions[=true|false]}

Solutions are hidden by default, and their display needs to be activated explicitly (it suffices
to specify the option solutions without the value true). It is also possible to control the
display by an analogous package option solutions, see section 2.8 for further information.
\ifsolutions The display of solutions is reflected by the conditional \ifsolutions. As the hiding of
onlysolutions solutions is performed automatically, the conditional would typically be used to change
some details, e.g. for adjusting titles:

\ifsolutions Solutions\else Exercises\fi

Alternatively, content to be processed only in solutions mode can be enclosed in an


onlysolutions block:

\begin{onlysolutions}
...
\end{onlysolutions}

This structure can be useful to hide auxiliary text or material if all solution content is to
be stripped from a source file, e.g. by an automated sed filter rule (doubling of backslashes
required for sed as well as for shell script strings):

sed "/\\\\begin{solution}/,/\\\\end{solution}/d;"\
"/\\\\begin{onlysolutions}/,/\\\\end{onlysolutions}/d"

solutionequation As solutions can contain numbered equations while the display of solutions can be switched
on and off, it is important to assign a different counter for equations within solutions in order
for the equation numbers to be stable. A separate counter for equations within solutions is
enabled by default. It can be disabled by:

\exercisestyle{solutionequation=false}

This option prepends the letter ‘S’ to equation numbers within solutions which are counted
separately; the display can be configured differently, see section 2.6.
solutionbelow The package allows to collect solutions and defer their display to particular locations:
\insertsolutions
\exercisestyle{solutionbelow=pos}

The available choices for pos are to display solutions where they are defined (here), de-
fer them to the end of the current subproblem (subproblem), problem (problem) or sheet
(sheet) or display them at a manually chosen location (manual). Note that typically so-
lutions are defined at the end of a (sub)problem and therefore the choice here is similar
to (sub)problem. The latter form, however, makes sure that a solution does not inherit

4
the margin of the parent environment. The alternate modes problem* and subproblem*
positions the solution after the (sub)problem environment such that it does not inherit
any layout, but also no definitions made in the parent environment. In manual mode, all
solutions are collected (with appropriate headers) until they are output by the directive
\insertsolutions. If no solutions are stored in the buffer (or if the mode is not manual),
\insertsolutions has no effect.
\writesolutions Another option to handle solutions is to write them to a file for later use. Writing to a file
is initiated by:

\writesolutions[filename]

The optional argument describes the filename as filename.sol; no argument defaults to


the main tex filename as \jobname.sol; the extension .sol can be customised by the
configuration extsolutions. This mode overrides the solutionbelow behaviour described
above; all subsequent solutions are written to the file. The file is closed by \closesolutions
and the display of solutions returns to manual mode. It is not necessary to close a file as it
will be closed automatically by reading from a file, writing to another file or by the end of
the document.
\readsolutions Solutions are read from a file by:

\readsolutions[filename]

This command outputs a sectional title and reads the file via \input{filename.sol}.

solutionbuf The package offers similar functionality to control the display of problems. In order to
problembuf have any control over the content of problem environments, the latter needs to be read into
an internal buffer. Reading of solutions and problems to internal buffers is activated or
deactivated by:

\exercisesetup{solutionbuf[=true|false]}
\exercisesetup{problembuf[=true|false]}

By default, solution environments are read to an internal buffer, while the content
of problem environments is processed directly by the TEX engine. Therefore, the fol-
lowing options to control the display of problem environments require the statement
\exercisesetup{problembuf}.
problemmanual The immediate display of problem environments is controlled by:
\insertproblems
\exercisestyle{problemmanual[=true|false]}

In the default automatic mode, problems are displayed directly where they are declared. In
manual mode, problems are collected to an internal buffer, and only displayed by issuing
\insertproblems.
Note that solution environments should be declared within the corresponding problem
environment in order to preserve their appropriate association. The solution environment
is then processed at the place where the problem environment is displayed, and it may (or
may not) be deferred further.
\writeproblems Problems can be written out to an external file for later usage. The functionality is analogous
\readproblems to solutions and uses the macros:

\writeproblems[filename]
\readproblems[filename]

5
The optional argument describes the filename as filename.prb; no argument defaults to
the main tex filename as \jobname.prb; the extension .prb can be customised by the
configuration extproblems.
disable The display of a particular problem can be suppressed altogether by an optional argument:
insertproblemselect
\begin{problem}[disable]

This option can be exploited to automatically suppress certain classes of problems as follows:
A hook function insertproblemselect declared by:

\exerciseconfig{insertproblemselect}[1]{code}

can call \setproblemdata{disable} whenever a problem is to be suppressed. In order to


decide, the optional argument of the problem environment is passed on to the hook function
as the single argument. Note that the argument needs to be processed manually.

2.3 Metadata
In a collection of exercise problems it makes sense to keep track of metadata for the overall
collection as well as for individual problems and potentially display some of them. The
framework defines a standard set of metadata fields and offers functionality to add more
specialised metadata fields.
\exercisedata Global metadata is specified by the command:

\exercisedata{data}

The argument data is a comma-separated list of metadata specifications in the form


key={value}. The standard set of global metadata keys consists of:

• author: principal author(s) of the exercise collection; also invokes the LATEX command
\author; will be written to pdf documents.
• title: title of the exercise collection; also invokes the LATEX command \title; will
be written to pdf documents.
• date: date of the exercise collection; also invokes the LATEX command \date; will be
written to pdf documents.
• subject: subject area of the exercise collection; will be written to pdf documents.
• keyword: keyword(s) for the exercise collection; will be written to pdf documents.
• course: title of the course (class, lecture, module, . . . ) for the exercise collection.
• institution: institution (school, department, institute, university, . . . ) offering the
course or exercise collection.
• instructor: instructor(s) for the course or exercise; this field refers to person(s) who
organise the corresponding course or exercises whereas author refers to the principal
creator of the material.
• period: period (year, season, date, term identifier, . . . ) of the corresponding course.
• material: type of material (exercises, homework assignments, exam, quizzes, solu-
tions, . . . ).

\defexercisedata Additional custom fields for global metadata can be created with:

\defexercisedata{key}

6
\getexercisedata Global metadata should typically be specified somewhere at the top of the main document,
\exercisedataempty and it can be inserted wherever needed. There are two commands to read and process
metadata. To insert the value of metadata field key use:

\getexercisedata{key}

In some situations the output should depend on whether a metadata has been filled (e.g.
to fill a default value or to display something else instead). This can be checked with the
conditional:

\exercisedataempty{key}{empty code}{filled code}

The empty code is executed if no value or an empty value has been specified; otherwise the
filled code is executed.
sheet The package offers a similar mechanism to describe and use metadata for sheets and prob-
problem lems:

\begin{sheet}[opts]
\begin{problem}[opts]

The argument opt is a comma-separated list which can contain metadata specifications in
the form key={value}. The standard set of metadata keys for sheets consists of:

• due: indication of the due date for the exercise sheet.


• handout: indication of the handout date for the exercise sheet.
• title: specifies a title for the sheet; when reading value (see below), returns composed
title; untitled sheets will be displayed by their number; title will be written to pdf
documents.
• rawtitle (for reading only): contains the raw title as specified by title.
• author: author(s) of the sheet; will be written to pdf documents.
• editor: editor(s) of the sheet; this field refers to a person who makes adjustments to
the sheet whereas author refers to the creator of the sheet.
• editdate: indication of the date when the sheet was last edited.

The standard set of metadata keys for problems consists of:

• title: specifies a title for the problem; when reading value (see below), returns com-
posed title; untitled problems will be displayed by their number.
• rawtitle (for reading only): contains the raw title as specified by title.

\defsheetdata Metadata for sheets can be used in the same way as the global metadata. The following
\setsheetdata directives are analogous to \defexercisedata, \exercisedata, \getexercisedata and
\getsheetdata \exercisedataempty:
\sheetdataempty
\defproblemdata \defsheetdata{key}
\setproblemdata \setsheetdata{data}
\getproblemdata \getsheetdata{key}
\problemdataempty \sheetdataempty{key}{empty code}{filled code}
\defproblemdata{key}
\setproblemdata{data}
\getproblemdata{key}
\problemdataempty{key}{empty code}{filled code}

7
pdfdata The most relevant metadata can be written to the metadata section of pdf files (using
\writeexercisedata pdfLATEX and the package hyperref whenever loaded). This feature is configured by:

\exercisesetup{pdfdata[=auto|manual|sheet|off]}

The option auto writes the global metadata title, author, subject and keyword to the
corresponding fields in the pdf file. To make this work, these must be defined before the
\begin{document} directive. The option manual allows to manually write these metadata
by the command \writeexercisedata. It should be issued after the metadata have been
set, but before any content is written to the pdf file. In other words, it can be anywhere in
the document preamble directly after \begin{document}, or following a couple of content-
free definitions at the beginning of the document body (in case the metadata should be set
within the document body for some reason). The option sheet writes out the metadata
at the beginning of the first sheet environment (which should follow \begin{document}
without any content in between). This option is primarily for filling the author and title
fields with metadata of a sheet rather than a collection of exercises. Note that if no author
is defined for the sheet, the global metadata author is used. The option off disables all
writing of metadata.
problem There is an additional mechanism to keep track of metadata for problems, subproblems and
subproblem solutions which can be displayed in the opening line of these entities. Displayed metadata
solution serve two purposes: they are used to describe the quality of a problem or they are intended
for internal documentation purposes. Their output can be controlled individually, e.g. only
in development versions of a document. Note that specifying a key more than once will
display the content multiple times in the order in which they are encountered. Displayed
metadata are specified at the top of the corresponding environment:

\begin{problem}[opts]
\begin{subproblem}[opts]
\begin{solution}[opts]

The standard set of displayed metadata keys consists of:

• author: author(s) of the problem (or subproblem, solution).


• editor: editor(s) of the problem; this field refers to a person who has made adjust-
ments to the problem whereas author refers to the creator of the problem.
• source: source of the problem; in case the problem has been taken from elsewhere
(conceptually or literally).
• difficulty: indication of the level of difficulty of the problem.
• keyword: keyword(s) for the problem;
• comment: some comment on the problem.
• optional (display enabled by default): whether addressing the problem is mandatory
or optional; by default the text will be displayed after the title in italic shape.

By default, only the optional items are displayed, all other types of items are hidden;
controlling the display for each type of item is described below.
extdata Further displayed metadata keys are defined by the package option extdata, see section 2.8:

• review: field to review the aspects of the problem (quality, length, appropriateness,
difficulty, . . . ).
• recycle: indication of previous instances where this problem was used.
• timesolve: indication of the time needed to solve this problem (or subproblem).

8
• timepresent: indication of the time needed to present this problem (or subproblem,
solution).

\showprobleminfo The display of the above metadata fields for a problem (or subproblem, solution) is controlled
by:

\showprobleminfo{keys}

Here keys is a comma-separated list of keys to be activated (key or key=true) or deactivated


(key=false).
\defprobleminfo Displayable metadata can be defined or adjusted by:

\defprobleminfo{key}{code}

Here key specifies the metadata field and code the code to display this type of metadata
where the argument #1 represents the data to be displayed.
insertprobleminfo Additional information can be injected into the opening line of problems and solutions by
nsertsubprobleminfo the definitions:
insertsolutioninfo
\addprobleminfo \exerciseconfig{insertprobleminfo}{code}
\addprobleminfo* \exerciseconfig{insertsubprobleminfo}{code}
\exerciseconfig{insertsolutioninfo}{code}

The hook code code will be called after processing the environment arguments. Information
can be added to the opening line by:

\addprobleminfo{info}
\addprobleminfo*{info}

The unstarred command adds information at the end of the opening line, the starred version
at the beginning (but after the title or identifier).

2.4 Points
points Exercise problems or certain parts of them can be credited with points (credits, awards, . . . ).
The package provides an interface to specify and manage such points. Points are declared
by the option points=points for the environments sheet, problem and subproblem. These
numbers will be printed to the opening line of problems and subproblems.
Note that the points should normally be integer numbers. Fractional points are permissible
as well, but the internal storage by the TEX engine is somewhat limited, so that only fractions
with powers of two as denominators (.5, multiples of .25, .125, .0625, . . . ) are reliable. More
general fractional decimal numbers such as multiples of 0.2 will be subject to rounding errors
and will not display nicely.
Bonus points can be specified in the format points=[regular ][+bonus]. By default, such
points will be printed as [regular ][+bonus] where 0 components are omitted.
problempointsat The location where points of problems and subproblems shall be displayed can be adjusted
subproblempointsat individually by:
solutionpointsat
\exercisestyle{problempointsat=start|start*|margin|end|manual|off}
\exercisestyle{subproblempointsat=start|start*|margin|end|manual|off}
\exercisestyle{solutionpointsat=start|start*|margin|end|manual|off}

9
The default values are start and end for problems and subproblems, respectively. The
option start displays points at the very end of the opening line; the option start* displays
them at the start of it. The option end displays points at the end of the problem or
subproblem text. The option margin displays points in the margin. The option manual
displays points at a manually chosen location specified by the directive \showpoints. Note
that \showpoints can also be used for the option end to display the points prematurely
(e.g. if the text ends with a displayed equation, it may make sense to display the points just
before the equation). The option off disables the display of points.
\getsheetdata Points for sheets are only stored by the package; they must displayed manually. Within the
corresponding sheet environment the points can be accessed by:

\getsheetdata{points}

\getsheetpoints The package allows to read the point totals for other sheets and problems:
\getproblempoints
getsubproblempoints \getsheetpoints{[tag]}
\getsolutionpoints \getproblempoints{[tag]}
\extractpoints \getsubproblempoints{[tag]}
\switchpoints \getsolutionpoints{}

Here tag is the tag assigned to the corresponding sheet or problem, see section 2.5. An empty
argument tag refers to the current sheet, (sub)problem or solution. If bonus points are used,
the points will be returned in the format [regular ][+bonus]; the components regular and bonus
can be extracted from the returned expression by \extractpoints and \extractpoints*,
respectively. A convenient case switch of the returned value can be performed by:

\switchpoints{reg}{bonus}{both}{none}{val }

Here val is the value returned from the points register, reg is displayed for purely regular
points, bonus is displayed for purely bonus points, both is displayed for mixed points, none
is displayed for no points. In each of the four expressions, #1 will be replaced by the regular
points and #2 by the bonus points.
\awardpoints Grading instructions with points to be awarded can be specified in the solution text by:

\awardpoints[details]{points}
\awardpoints*[details]{points}

Here details is an optional text with further details, e.g. to explain under which conditions
these points are to be awarded. The starred form is used to specify optional points or
alternative paths with alternative grading instructions. These points will be marked and
not be used for the computation of a total.
warntext The package attempts to add up the points of subproblems to the problem total and likewise
the points of problems to the sheet total. The package also performs some sanity checks
on the provided numbers: If points are specified for both subproblems and problems or
for both problems and sheets, they will be compared. Also the points within solutions
(excluding optional or alternative points) are added up and compared to the corresponding
problem or subproblem. Furthermore the package checks whether points are defined for all
subproblems within a problem or all problems within a sheet. Mismatches are reported as
package warnings. As point mismatches can be rather severe, there is an option to write
such warnings directly into the output document (to be removed before distribution):

\exercisesetup{warntext[=true|false]}

10
fracpoints The package offers pretty display of fractional points with denominators 2, 4 and 8 by writing
the decimal part as a fraction, e.g. 1.75 → 13/4 . This feature is enabled by:

\exercisestyle{fracpoints}

2.5 Labels and Tags


label LATEX provides labels to make references to remote parts of the text. Labels can be set as
usual by \label{label } within the problem, subproblems and sheet environments. Alter-
natively, they can be specified as the environment option:

label={label }

tag The package provides an additional mechanism to tag sheets and problems. Each sheet,
\sheettag problem and subproblem can be assigned a unique tag tag by the environment option:
\problemtag
\subproblemtag tag={tag}

This tag is used for reading point totals as described in section 2.4. Furthermore, the macro
\sheettag, \problemtag or \subproblemtag is set to the tag tag within the current envi-
ronment. If no tag is specified it defaults to the number of the current sheet or (sub)problem;
note that this number can change by reordering sheets and problems and therefore it should
not be used to identify the entity from other parts of the document.
A useful application for tags is to encapsulate labels within individual sheets and problems
which are part of a collection of exercises. Labels which are composed as \sheettag-label
or \problemtag-label can be considered local and will not clash with labels defined within
a different environment. Within the same sheet or problem, local labels can be accessed by
the same construction. They can also be accessed from remote parts of the document by
fully expanding \sheettag or \problemtag for the desired target environment.
autolabelsheet If unique tags are specified, the package can automatically create labels for sheets
autolabelproblem (sheet:tag) and problems (prob:tag) by:

\exercisesetup{autolabelsheet[=true|false]}
\exercisesetup{autolabelproblem[=true|false]}
\getsheetlist Tags can also be used to process a list of sheets, problems and subproblems:
\getproblemlist
\getsubproblemlist \getsheetlist{}
\getproblemlist{[sheet-tag]|*}
\getsubproblemlist{[problem-tag]}
These commands return a list of sheets, problems and subproblems tags, where each item
is encapsulated in braces. The commands \get[sub]problemlist return the (sub)problems
within the specified sheet or problem. If no argument is given, the current sheet or problem
is assumed. \getproblemlist* returns the list of all problems.
\exerciseloop The package defines two commands to walk through such a list:
\exerciseloopstr
\exerciseloopret \exerciseloop{items}{cmd }
exerciseloop \exerciseloopstr[ret]{items}{str }
Here, items is a list of items in braces, and \exerciseloop evaluates cmd for each item of
the list where ‘#1’ is replaced by the item. The command \exerciseloopstr concatenates
the evaluations of str and returns the resulting string in the macro ret (which defaults to
\exerciseloopret). Both commands maintain a counter of items exerciseloop which
can be accessed within cmd /str or after \exerciseloop[str] to obtain the total number of
items in the list.

11
2.6 Layout
The package provides a large number of parameters to adjust the display of exercises to a
desired layout.
\exerciseconfig Configuration settings are declared and modified by the command:

\exerciseconfig{key}[narg]{value}

Here key is a key and value is its assigned value. Configuration options can also be macros
with arguments in which case narg is the number of arguments and value is the macro
definition using arguments #n. The command \exerciseconfig therefore is analogous
to \(re)newcommand except that the definitions are encapsulated by the package and any
previous definition is overwritten without checking.
xerciseconfigappend In some cases it may be useful to be able to append or prepend to a (parameterless) definition
erciseconfigprepend by:

\exerciseconfigappend{key}{value}
\exerciseconfigprepend{key}{value}

\getexerciseconfig Configuration definitions can be read by:


exerciseconfigempty
\getexerciseconfig{key}[arguments]

The number of arguments after {key} must match the optional argument nargs of the
definition. Furthermore, it can be checked whether a configuration definition is empty:

\exerciseconfigempty{key}{empty code}{filled code}

The empty code is executed if no value or an empty value has been specified. Otherwise the
filled code is executed.
The package defines numerous layout configuration options. They are listed along with their
original definition and a brief description in section C.3. They include options to:

• adjust the language for the principal entities of this package like ‘sheet(s)’, ‘problem(s)’,
‘solution(s)’, ‘points(s)’;
• adjust the fonts styles of various parts of the text;
• adjust the spacing above, below, between various elements;
• define code to process data and insert text at various locations;
• compose text to be used in various situations;
• adjust the appearance of counters;
• adjust some other behaviour of the package.

The following will highlight only few examples.


insertsheettitle An important setting is:

\exerciseconfig{insertsheettitle}{code}

The code code is meant to print the title or header of an exercise sheet. The minimalistic
default code \centerline{\getsheetdata{title}} merely prints the sheet title “Sheet
#” at the centre of a line. Commonly, one would replace this by a more elaborate header
(potentially with some more information, appealing layout, logos, . . . ). In order to design a

12
header template, it makes sense to retrieve data via \getexercisedata and \getsheetdata
described in section 2.3. Likewise \exercisedataempty and \sheetdataempty can be used
to display default values or alternative data if some particular data is not provided. An
example is given by the plainheader extended style option defined in section C.4.
composetitleproblem Another noteworthy example is composetitleproblem to compose the title for a problem.
It takes two parameters, the number and the title. The (somewhat simplified) default
declaration is:

\exerciseconfig{composetitleproblem}[2]{\exerciseifempty{#2}
{\getexerciseconfig{termproblem}
\getexerciseconfig{composeitemproblem}{#1}}
{\getexerciseconfig{composeitemproblem}{#1} #2}}

This checks whether the title is empty. If no title is given use “Problem #.”, otherwise use
“#. title”. Here the term “Problem” is made abstract by the configuration termproblem
(e.g. to support internationalisation) and the problem number is further composed obtained
by the configuration composeitemproblem which takes the bare number as argument and
returns it followed by a dot.
\exerciseifempty Handy conditionals command to check whether an expression expr is empty are:
\exerciseifnotempty
\exerciseifempty{expr }{empty code}{filled code}
\exerciseifnotempty{expr }{filled code}

Their main purpose is to test whether some provided expression expt is empty. They expand
to the common TEX constructs \if&#1&#2\else#3\fi and \if&#1&\else#2\fi which work
assuming that expr is not too exotic (e.g. it should not start with the character ‘&’ and other
special TEX characters or macros are potentially dangerous; also using this within tables can
be troublesome; the character ‘&’ can be reconfigured by the package option emptytestchar).

2.7 Exercise Styles


The package provides a mechanism to define exercise styles which customise the display of
exercises in some coordinated fashion.
\exercisestyle Style(s) are activated by the command:

\exercisestyle{styles}

Here styles is a comma-separated list of styles, where each style is given by a pair
style[={argument}]. The package defines a couple of standard styles:

• solutionbelow=pos (can take values here, subproblem, subproblem*, problem,


problem*, sheet and manual; initially set to subproblem) – positions the solutions
below the indicated environments; see section 2.2 for details.
• problempointsat=pos (can take values start, start*, margin, end and manual; ini-
tially set to start) – displays points in problems at the indicated location; see section
2.4 for details.
• subproblempointsat=pos (can take values start, start*, margin, end and manual;
initially set to end) – displays points in subproblems at the indicated location; see
section 2.4 for details.
• solutionpointsat=pos (can take values start, start*, margin, end and manual;
initially set to end) – displays points in solutions at the indicated location; see section
2.4 for details.

13
• problemby={counter } – number problems with the prefix counter, i.e. reset the prob-
lem counter whenever counter increases and use a composite label counter .problem
to identify problems.
• equationby={counter } – number the dedicated equation counters for sheets, problems
and solutions with the prefix counter.
• problembysheet – number problems by sheet.
• equationbysheet – number dedicated equations for sheets, problems and solu-
tions by sheet; note that the main equation counter is unaffected by this set-
ting, it therefore makes sense to also activate the style sheetequation or use
\counterwithin{equation}{sheet}.
• pagebysheet – number pages by sheet and denote pages by sheet.page; this style is
useful to generate stable page numbers for a collection of sheets.
• sheetequation[=true|false] (no value implies true, initially set to false) – use a
dedicated equation counter within sheets.
• problemequation[=true|false] (no value implies true, initially set to false) – use a
dedicated equation counter within problems.
• solutionequation[=true|false] (no value implies true, initially set to true) – use a
dedicated equation counter within solutions.
• fracpoints[=true|false] (no value implies true, initially set to false) – display
fractional points for denominators 2, 4, 8; see section 2.4 for details.
• twoside[=true|false] (no value implies true, initially set to false) – enable/disable
two-sided layout; in two-sided layout, sheets will start on odd pages and empty pages
are added at the end of sheets to produce an even number of pages.

extstyle Further exercise styles are defined by the package option extstyle, see section 2.8:

• plainheader – define a plain sheet header to display some essential exercise and sheet
data: course, institution, instructor, period (optional), sheet title, see section
2.3; the line below the header, font styles and spaces can be adjusted, see the definition
in section C.4.
• contents – display sheets and problems in the table of contents (as sections and
subsections).
• solutionsf – display solutions in sans serif font family.
• solutiondimproblem – dim the problem text whenever solutions are displayed.
• solutionsep – separate the solutions from the remaining text by horizontal lines.

\defexercisestyle Custom styles can be defined by:

\defexercisestyle{style}{init}
\defexercisestylearg[default]{style}{init}

This feature can be used to predefine certain aspects of the exercises layout. For example,
different default page layouts could be declared in this way. The first version declares a style
which is initialised by the code item upon activation by \exercisestyle{style[=true]}.
Note that \exercisestyle{style=false} does nothing. The second version declares a style
which is activated by \exercisestyle{style[={arg}]} and which calls item with the argu-
ment #1 referring to arg (or default if no argument is given).

14
2.8 Package Options
\exercisesetup Features and options of general nature can be selected by the commands:

\usepackage[opts]{exframe}
or \PassOptionsToPackage{opts}{exframe}
or \exercisesetup{opts}

\PassOptionsToPackage must be used before \usepackage; \exercisesetup must be used


afterwards. opts is a comma-separated list of options.
The following options are available only when loading the package, i.e. they will not work
within \exercisesetup:

• extdata[=true|false] (no value implies true, initially set to false) – define some
more advanced metadata entries.
• extstyle[=true|false] (no value implies true, initially set to false) – define some
more advanced styles.
• metastr[=true|false] (no value implies true, initially set to false) – load metastr
package and use to handle PDF metadata and basic internationalisation, see section
C.16 for details.
• problemenv=name – redefine environment name problem. This and the following alike
options may be useful in quickly adjusting existing sources to the exframe framework
if the original framework works similarly and no special features are used. Otherwise,
it is highly advisable to leave the names of environments and counters defined by the
package untouched.
• subproblemenv=name – redefine environment name subproblem.
• solutionenv=name – redefine environment name solution.
• sheetenv=name – redefine environment name sheet.
• problemcounter=name – redefine counter name problem.
• subproblemcounter=name – redefine counter name subproblem.
• solutioncounter=name – redefine counter name solution.
• sheetcounter=name – redefine counter name sheet.

The following options can be specified by all three methods described above:

• solutions[=true|false] (no value implies true, initially set to false) – En-


able/disable display of solutions. Sets the conditional \ifsolutions accordingly.
• pdfdata[=auto|manual|sheet|off] (no value implies auto, initially set to auto) – con-
trol writing most relevant metadata to pdf files; has no effect without package hyperref.
• lineno[=true|false] (no value implies true, initially set to false) – enable/disable
writing of line numbers as comments into solution files.
• twoside[=true|false] (no value implies true, initially set to false) – enable/disable
two-sided layout; see section 2.7 for details.
• solutionhref[=true|true] (no value implies true, initially set to false) – en-
able/disable use of hyper-references from solutions to the corresponding problems;
has no effect without package hyperref.
• warntext[=true|false] (no value implies true, initially set to false) – enable/disable
writing of relevant warning messages (points mismatch, point sums require update)
into the document output for easier detection.

15
• autolabelsheet[=true|false] (no value implies true, initially set to false) – en-
able/disable automatically assigning labels (sheet:\sheettag; can be adjusted) to
sheets according to their tag \sheettag.
• autolabelproblem[=true|false] (no value implies true, initially set to false) – en-
able/disable automatically assigning labels (prob:\problemtag; can be adjusted) to
problems according to their tag \problemtag.
• solutionbuf[=true|false] (no value implies true, initially set to true) – en-
able/disable buffering for solution environments in order to control their display;
disabling buffering can be helpful in debugging faulty solution environments; it
might also resolve some tokenisation issues in special circumstances; note that the
display of solutions cannot be suppressed with \exercisesetup{solutions=false}
when buffering if disabled.
• problembuf[=true|false] (no value implies true, initially set to false) – en-
able/disable buffering for problem environments in order to control their display.
• emptytestchar=char (initially set to ‘&’) – character to use for testing whether an
argument #1 is empty via \if&#1&...\fi; if ‘&’ causes trouble within tables, could
try ‘@’ instead.

3 Information
3.1 Copyright
Copyright © 2011–2020 Niklas Beisert
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 Niklas Beisert.
This work consists of the files README.txt, exframe.ins and exframe.dtx as well as the
derived files exframe.sty, exfsamp.tex, exfserm.tex, exfsernn.tex (nn=01, 02, 03, aa),
exfserpe.tex, exfserpf.tex, exfsermk.sh, exfsermk.mak and exframe.pdf.

3.2 Files and Installation


The package consists of the files:

16
README.txt readme file
exframe.ins installation file
exframe.dtx source file
exframe.sty package file
exfsamp.tex sample file
exfserm.tex multipart sample main file
exfser01.tex multipart sample sheet 1
exfser02.tex multipart sample sheet 2
exfser03.tex multipart sample sheet 3
exfseraa.tex multipart sample unused problems
exfserpe.tex multipart sample problem E
exfserpf.tex multipart sample problem F
exfsermk.sh multipart sample compile script
exfsermk.mak multipart sample makefile
exframe.pdf manual

The distribution consists of the files README.txt, exframe.ins and exframe.dtx.

• Run (pdf)LATEX on exframe.dtx to compile the manual exframe.pdf (this file).


• Run LATEX on exframe.ins to create the package exframe.sty and the samples con-
sisting of exfsamp.tex, exfserm.tex, exfser01.tex, exfser02.tex, exfser03.tex,
exfseraa.tex, exfserpe.tex, exfserpf.tex, exfsermk.sh, exfsermk.mak. Copy
the file exframe.sty to an appropriate directory of your LATEX distribution, e.g. texmf-
root/tex/latex/exframe.

3.3 Related Packages


The package makes use of other packages available at CTAN:

• This package relies on some functionality of the package verbatim to read verbatim
code from the LATEX source without expansion of macros. Compatibility with the
verbatim package has been tested with v1.5q (2014/10/28).
• This package uses the package xkeyval to process the options for the package, environ-
ments and macros. Compatibility with the xkeyval package has been tested with v2.7a
(2014/12/03).
• This package can use the package hyperref to include hyperlinks between problems
and solutions. Compatibility with the hyperref package has been tested with v6.88e
(2018/11/30).
• This package can use the package amstext (which is automatically loaded by amsmath)
to display text within equations. Compatibility with the amstext package has been
tested with v2.01 (2000/06/29).
• This package uses the command \currfilename provided by the package currfile (if
available and loaded) to indicate the LATEX source file in the generated metapost file.
Compatibility with the currfile package has been tested with v0.7c (2015/04/23).
• This package can use the package metastr to write PDF metadata and to handle
basic translations. Compatibility with the metastr package has been tested with v1.0
(2020/02/06).

There are several other LATEX packages which offer a similar functionality varying largely in
scope and sophistication:

17
• The package exsheets and its successor xsim provide a LATEX 3 style for typesetting
exercises with solutions. They offer options to hide or delay solutions, print only
specific problems, deal with points, specify metadata, handle exercise collections, as
well as some more specific options. They allow to adjust the layout and choose among
predefined ones.
• The package exercise provides a style for typesetting exercises with solutions. It offers
many options to hide or delay solutions, print only specific problems, specify some
metadata as well as some more specific options. It allows to customise the layout.
• The package exercises provides a style for typesetting exercises with solutions. It offers
options to hide solutions and deal with points. It allows basic customisation of the
layout.
• The package exam provides a document class for typesetting exams conveniently. It
offers many options to hide solutions, deal with points and deal with other exam-
specific tasks. It allows to adjust the layout and choose among predefined ones.
• The package probsoln provides a style for typesetting exercises with solutions which
are stored in a collection. It offers options to hide solutions and to assemble problems
from an external collection.
• The packages uebungsblatt, uassign, mathexam, exsol, homework, jhwhw provide basic
functionality for somewhat more particular situations.

See CTAN categories exercise and exam for further up-to-date packages.
The philosophy of the present package is to define a low-level framework to describe exercises
with solutions to be used in various situations. The aim is to provide the means to describe
the content (problems, solutions, sheets) in a simple fashion and separate it from the various
layout definitions and choices which will define the appearance of the content. The interface
was designed to reduce potential conflict with other packages and definitions. The package
itself does not define an elaborate layout, but it provides means to adjust it in many ways
and to predefine custom layout schemes. The package offers most of the functionality of the
above packages, but (presently) misses out on some more advanced features, see section 3.4.

3.4 Feature Suggestions


The following is a list of features which may be useful for future versions of this package:

• Add a section on useful combinations of customisation settings to achieve specific goals.


Please send suggestions.
• Option to hide problem text while maintaining access to embedded solutions (for a
version containing only solutions): this is difficult to implement because the problem
environment cannot simply be discarded, but would have to be scanned very care-
fully for the embedded solution; instead process problems to some document and save
solutions to file, then read solutions from different document.
• Define structures for multiple-choice questions.

3.5 Revision History


v3.4: 2020/02/24

• lists of sheets, problems and subproblems; list iterators


• tags for subproblems, tag customisation

18
• interaction with package metastr
• minor fixes

v3.31: 2020/01/11

• onlysolutions environment for solution mode content


• sample multipart setup streamlined

v3.3: 2019/06/15

• control display of problem environments via package option problembuf: manual


display, write to file, disable individual problems
• solutionbelow mode here* superseded by package option solutionbuf
• display total points within solution: solutionpointsat (thanks to Till Bargheer for
suggestion)
• read points for current sheet, (sub)problem and solution (thanks to Johannes Hahn
for suggestion)
• case switch for bonus points (thanks to Johannes Hahn for suggestion)
• option to disable particular problems, control by hook function (thanks to Manuel
Benz for suggestion)
• provided interface \showfracpoints and \exerciseconfig{frac} for fractional
points display
• filename extensions configurable

v3.2: 2019/05/01

• bonus points can be specified as points=[regular ][+bonus]


• solutionbelow mode here* added for direct processing of the solution environment
• multipart sample added

v3.11: 2019/04/15

• fix interaction with package calc (thanks to Johannes Hahn for bug report)
• fix style fracpoints in combination with some [sub]problempointsat choices (thanks
to Johannes Hahn for bug report)
• fix spacing for [sub]problempointsat=margin (thanks to Johannes Hahn for bug re-
port)

v3.1: 2019/01/21

• alternate placement modes for solutions


• fixed expansion of problem title
• reset font size for problem text

19
v3.0: 2019/01/16

• renamed to exframe.sty
• first version published on CTAN
• overhaul and streamline interface
• solution processing remodelled
• changed metadata handling
• changed and generalised points handling
• generalised sectioning layout
• changed layout specification model
• insert hyperlinks using hyperref
• manual, example and installation package added

v2.0 – v2.6: 2014/10/03 – 2018/11/05

• changed metadata interface


• broadened scope
• added more layout options
• added more metadata
• added sheet and problem tags
• add and remember points

v1.1 – v1.6: 2014/08/07 – 2014/09/14

• renamed to nbprob.sty
• added metadata
• added points
• added layout configuration
• removed specific macros

v1.0 – v1.02: 2011/09/23 – 2013/03/17

• first version as problems.cls


• dedicated layout and macros for author’s exercise sheets

A Standalone Sample
This section provides an example of how to use some of the exframe features. The resulting
layout will be somewhat messy due to a random selection of features.
This example file describes a single exercise sheet. The other sheet of the series would be
declared analogously in independent documents.

20
Preamble. Standard document class:
1 \documentclass[12pt]{article}

Use package geometry to set the page layout; adjust the paragraph shape:
2 \usepackage{geometry}
3 \geometry{layout=a4paper}
4 \geometry{paper=a4paper}
5 \geometry{margin=2.5cm}
6 \parindent0pt
7 \parskip0.5ex

Include amsmath, hyperref packages:


8 \usepackage{amsmath}
9 \usepackage{hyperref}

May include metastr package; below code adjusts to whether or not present:
10 \PassOptionsToPackage{loadlang=en|de}{metastr}
11 \PassOptionsToPackage{course=true}{metastr}
12 %%\usepackage{metastr}
13 %%\metasetlang{de}

Include exframe package:


14 \usepackage[extstyle]{exframe}

Solutions Switch. It will be useful to have the switch to turn on/off the display of
solutions near the top of the source file, potentially with the opposite setting commented
out:
15 %%\exercisesetup{solutions=true}
16 \exercisesetup{solutions=false}

Automatically put labels for (sub)problems:


17 \exercisesetup{autolabelproblem=true}

Layout Declarations. The following layout declarations adjust the general layout of
exercise sheets. They may as well be moved into an include file.
Declare a header for exercise sheets to display several relevant pieces of data; display points
total:
18 \exercisestyle{plainheader}
19 \exerciseconfig{composeheaderbelowright}{\getsheetdata{points}}%

Redefine the appearance of some counters; sheets should be labelled by capital roman nu-
merals, subproblems by lowercase roman numerals; declare the widest subproblem item to
be expected:
20 \exerciseconfig{countersheet}{\Roman{sheet}}
21 \exerciseconfig{countersubproblem}{\roman{subproblem})}
22 \exerciseconfig{countersubproblemmax}{vii)}

Automatically display an asterisk for all subproblems with bonus points only; remove space
to separate items:
23 \exerciseconfig{insertsubprobleminfo}{%
24 \switchpoints{}{\addprobleminfo*{%

21
25 \hspace{-\getexerciseconfig{skipsubprobleminfo}}*}}%
26 {}{}{\getsubproblempoints{}}}

Redefine the terms to be used for sheet(s); here, a German version:


27 \ifdefined\metaset
28 \metasetterm[en]{sheet}{Exercise Sheet}
29 \metasetterm[en]{sheets}{Exercise Sheets}
30 \metasetterm[de]{sheet}{\"Ubungsblatt}
31 \metasetterm[de]{sheets}{\"Ubungsbl\"atter}
32 \else
33 \exerciseconfig{termsheet}{\"Ubungsblatt}
34 \exerciseconfig{termsheets}{\"Ubungsbl\"atter}
35 \fi

Display points for problems in the margin; change margin display to use the left margin;
use the abbreviated form ‘np.’:
36 \exercisestyle{problempointsat=margin}
37 \reversemarginpar
38 \exerciseconfig{composepointsmargin}[1]{#1p.}
39 \exerciseconfig{composepointspairmargin}[2]{%
40 \ifdim#2pt=0pt#1p.%
41 \else\ifdim#1pt=0pt+#2p.%
42 \else#1+#2p.%
43 \fi\fi}

Change the basic font style for all titles to be bold sans-serif:
44 \exerciseconfig{styletitle}{\sffamily\bfseries}

Add a significant amount of space below problems:


45 \exerciseconfig{skipproblembelow}{1.5cm}

Display half points as fractions:


46 \exercisestyle{fracpoints}

Show solutions below each problem (may try alternatives subproblem or sheet):
47 \exercisestyle{solutionbelow=problem}

Separate solutions by horizontal lines (extended style):


48 \exercisestyle{solutionsep}

Write metadata for sheet:


49 \exercisesetup{pdfdata=sheet}

Set title and author for pdf metadata; title is course plus material or sheet title; author
is instructor or sheet author plus institution:
50 \ifdefined\metaset
51 \metaset[sep]{subtitle}{, }
52 \metaset{subtitle}{\ifsolutions\metatranslate[#1]{solutions} \fi%
53 \metaif[use]{sheettitle}
54 {\metapick[#1]{sheettitle}}
55 {\metapick[#1]{material}}}
56 \metaset{author}{\exerciseifempty{\getsheetdata{author}}%
57 {\metapick[#1]{instructor}}{\metapick[#1]{sheetauthor}},
58 \metapick[#1]{institution}}
59 \else

22
60 \exerciseconfig{composemetasheet}[2]{\getexercisedata{course},
61 \ifsolutions\getexerciseconfig{termsolutions} \fi%
62 \exerciseifempty{#2}{\getexerciseconfig{termsheet} #1}{#2}}
63 \exercisedata{title=%
64 {\getexercisedata{course},
65 \ifsolutions\getexercisedata{solutions} \fi%
66 \getexercisedata{material}}}
67 \exercisedata{author=%
68 {\getexercisedata{instructor}, \getexercisedata{institution}}}
69 \fi

Exercise Series Data. Set some data on the current series:


70 \ifdefined\metaset
71 \metaset{institution}{Katharinen-Volksschule}
72 \metaset[de]{course}{Mathematik}
73 \metaset[en]{course}{Mathematics}
74 \metaset{instructor}{J.\ G.\ B\"uttner}
75 \metaset{period}{ca.\ 1786}
76 \metaset[de]{material}{\"Ubungsaufgaben}
77 \metaset[en]{material}{Exercise Problems}
78 \else
79 \exercisedata{institution={Katharinen-Volksschule}}
80 \exercisedata{course={Mathematik}}
81 \exercisedata{instructor={J.\ G.\ B\"uttner}}
82 \exercisedata{period={ca.\ 1786}}
83 \exercisedata{material={\"Ubungsaufgaben}}
84 \fi

Body.
85 \begin{document}

Start sheet number 5:


86 \begin{sheet}[number=5,label={sheet5}]

Start a problem with a title:


87 \begin{problem}[title={Sums},points=99+4]

Summary of points:
88 \exerciseloopstr{\getsubproblemlist{}}{c}%
89 \hfill\begin{tabular}{c|\exerciseloopret|c}
90 \exerciseloop{\getsubproblemlist{}}
91 {&\ref{\getexerciseconfig{labelsubproblem}{#1}}}
92 &\ref{prob:\problemtag}\\\hline
93 \getexerciseconfig{termpoints}
94 \exerciseloop{\getsubproblemlist{}}{&\extractpoints{\getsubproblempoints{#1}}}
95 &\extractpoints{\getproblempoints{}}
96 \\
97 extra
98 \exerciseloop{\getsubproblemlist{}}{&\extractpoints*{\getsubproblempoints{#1}}}
99 &\extractpoints*{\getproblempoints{}}
100 \end{tabular}

Some introduction to the problem:


101 This problem deals with sums and series.

23
A subproblem with a local label:
102 \begin{subproblem}[points=2,difficulty=simple,label={\problemtag-simplesum}]
103 Compute the sum
104 \showpoints
105 \begin{equation}
106 1+2+3.
107 \end{equation}

Provide a solution for the subproblem (within the subproblem environment):


108 \begin{solution}
109 The result is
110 \begin{equation}
111 1+2+3=6.
112 \end{equation}
113 \end{solution}

End subproblem:
114 \end{subproblem}

Another subproblem:
115 \begin{subproblem}[points=97+0.5,difficulty=lengthy]
116 Compute the sum
117 \begin{equation}
118 1+2+3+\ldots+98+99+100.
119 \end{equation}
120 Keep calm and calculate!
121 %%That ought to keep him occupied for a while
122 \end{subproblem}

Provide a solution for the previous subproblem (layout may differ slightly from declaration
within); declare author:
123 \begin{solution}[author={C.\ F.\ Gau\ss}]
124 We use the result $1+2+3=6$ from part \ref{\problemtag-simplesum}
125 to jumpstart the calculation. The remaining sums yield
126 \awardpoints*[1 for each remaining sum]{97}
127 \begin{equation}
128 6+4+5+\ldots+99+100=5050.
129 \end{equation}
130 Alternatively the summands can be grouped into pairs as follows:
131 \begin{align}
132 1+100&=101,\\
133 2+99&=101,\\
134 3+98&=101,\\
135 \ldots &\nonumber\\
136 50+51&=101.
137 \end{align}
138 These amount to 50 times the same number 101.
139 Therefore the sum equals
140 \begin{equation}
141 1+2+\ldots+99+100=50\cdot 101=5050.
142 \end{equation}
143 \textit{Ligget se!} \awardpoints{97+0.5}
144 \end{solution}

Some text between subproblems:


145 You may give the final part a try:

24
Final subproblem; this one is optional:
146 \begin{subproblem}[optional={optional},
147 difficulty={requires inspiration},points={+3.5}]
148 Compute the series
149 \showpoints
150 \begin{equation}
151 1+2+3+\ldots
152 \end{equation}

Provide a solution:
153 \begin{solution}
154 The series is divergent, so the result is $\infty$ \awardpoints{+1}.
155 \par
156 However, after subtracting the divergent part,
157 the result clearly is
158 \begin{equation}
159 \zeta(-1)=-\frac{1}{12}\,,
160 \end{equation}
161 where the zeta-function $\zeta(s)$ is defined by
162 \begin{equation}
163 \zeta(s):=\sum_{k=1}^\infty \frac{1}{k^s}\,.
164 \end{equation}
165 This definition holds only for $s>1$ where the sum is convergent,
166 but one can continue the complex analytic function to $s<0$
167 \awardpoints{+1.5}.
168 \par
169 Another way of understanding the result
170 is to use the indefinite summation formula
171 for arbitrary exponent $s$ in the summand
172 (which also follows from the Euler--MacLaurin formula)
173 \begin{equation}
174 \sum_n n^s
175 = \frac{n^{s+1}}{s+1}
176 -\sum_{j=0}^s \frac{\zeta(j-s)\,s!}{(s-j)!\,j!}\,n^j
177 = \ldots - \zeta(-s)\,n^0.
178 \end{equation}
179 Curiously, the constant term with $j=0$ is just the desired result
180 but with the wrong sign
181 (in fact, the constant term of an indefinite sum is ambiguous;
182 for the claim we merely set $j=0$
183 in the expression which holds for others values of $j$)
184 \awardpoints{+0.5}.
185 In order to understand the sign,
186 we propose that the above formula describes the regularised result
187 for the sum with limits $+\infty$ and $n$
188 \begin{equation}
189 \sum_{k=+\infty}^n k^s
190 \simeq \frac{n^{s+1}}{s+1}
191 -\sum_{j=0}^s \frac{\zeta(j-s)\,s!}{(s-j)!\,j!}\,n^j.
192 \end{equation}
193 Then we flip the summation limits of the desired sum
194 to bring it into the above form
195 \awardpoints{+0.5}
196 \begin{equation}
197 \sum_{k=1}^\infty k^s
198 = -\sum_{k=\infty}^0 k^s
199 \simeq \zeta(-s).

25
200 \end{equation}
201 \end{solution}

End subproblem:
202 \end{subproblem}

End problem:
203 \end{problem}

Another problem; this one is untitled:


204 \begin{problem}[points=1, difficulty=insane]
205 Show that the equation
206 \begin{equation}
207 a^3+b^3=c^3
208 \end{equation}
209 has no positive integer solutions.
210 \end{problem}

A solution can also follow a problem (but the layout may be slightly different, e.g. here the
space below the problem will appear before the solution):
211 \begin{solution}
212 \normalmarginpar
213 This is beyond the scope of this example.
214 \marginpar{\footnotesize\raggedright does not fit here.\par}
215 \end{solution}

Summary of points per problem and per subproblem for grading:


216 \ifsolutions\else
217 \textbf{Grading:}\par
218 \exerciseloopstr{\getproblemlist{}}{|c}
219 \begin{tabular}{|c|\exerciseloopret||c|}\hline
220 \getexerciseconfig{termsheet} \ref{sheet5}
221 \exerciseloop{\getproblemlist{*}}
222 {&\ref{\getexerciseconfig{labelproblem}{#1}}}
223 &total
224 \\\hline
225 value
226 \exerciseloop{\getproblemlist{*}}
227 {&\extractpoints{\getproblempoints{#1}}}%
228 &\extractpoints{\getsheetpoints{}}
229 \\\hline
230 \exerciseloop{\getproblemlist{*}}{&}
231 &\\\hline
232 \end{tabular}\qquad
233 \exerciseloop{\getproblemlist{*}}{
234 \exerciseloopstr{\getsubproblemlist{#1}}{|c}
235 \ifnum\value{exerciseloop}>0\relax
236 \begin{tabular}{|c|\exerciseloopret||c|}\hline
237 \getexerciseconfig{termproblem} \ref{\getexerciseconfig{labelproblem}{#1}}
238 \exerciseloop{\getsubproblemlist{#1}}
239 {&\ref{\getexerciseconfig{labelsubproblem}{##1}}}
240 &total
241 \\\hline
242 value
243 \exerciseloop{\getsubproblemlist{#1}}
244 {&\extractpoints{\getsubproblempoints{##1}}}%
245 &\extractpoints{\getproblempoints{#1}}

26
246 \\\hline
247 \exerciseloop{\getsubproblemlist{#1}}{&}
248 &\\\hline
249 \end{tabular}\quad
250 \fi
251 }
252 \fi

End sheet:
253 \end{sheet}

End of document body:


254 \end{document}

B Multipart Sample
The second example describes a series of exercise sheets which can be compiled as a collection
or as individual sheets. This example describes a versatile setup with several convenient
features; most of these features can be adjusted or removed easily as they mostly enhance
the setup and do not interact with each other strongly.

B.1 Main File


The main source file is called exfserm.tex. It is referenced at several places within the
setup, and when changing the name they need to be adjusted accordingly.

childdoc Mechanism. The setup uses the package childdoc to allow compilation of the
series as a whole or in parts and with various sets of options:
255 \input{childdoc.def}
256 \childdocmain{exfserm}

The parameter of \childdocmain must match the main file name exfserm.

Compilation Switches. Define compilation switches and declare their default settings.
\printsol controls whether solutions should be printed or not; by default solutions are
activated for compilation of a part, but not for the complete document. \draftver controls
whether the final version of the document is to be compiled; concretely this affects the
compilations of metapost figures, see below:
257 \ifchilddoc
258 \providecommand{\printsol}{y}
259 \else
260 \providecommand{\printsol}{n}
261 \fi
262 \providecommand{\draftver}{y}
263 \newif\ifdraft\if\draftver y\drafttrue\else\draftfalse\fi

Preamble. Standard document class:


264 \documentclass[12pt]{article}

265 % \textsf{graphicx} package to display license logo:


266 \RequirePackage{graphicx}

27
hyperref Package. Use the hyperref package. Declare some options, e.g. use bookmarks
only for complete document:
267 \PassOptionsToPackage{bookmarks=\ifchilddoc false\else true\fi}{hyperref}
268 \PassOptionsToPackage{bookmarksopen=true}{hyperref}
269 \RequirePackage{hyperref}

metastr Package. Use the metastr package to handle metadata and copyright informa-
tion; disable usage of hyperxmp package if not installed; write auxiliary PDF metadata and
rights information:
270 \ifdraft
271 \PassOptionsToPackage{draft}{metastr}
272 \fi
273 \IfFileExists{hyperxmp.sty}{}{\PassOptionsToPackage{hyperxmp=false}{metastr}}
274 \RequirePackage[course]{metastr}
275 \metaset[aux]{writepdf}{}
276 \metaset[rights]{writepdf}{}

exframe Package. Invoke exframe with extended data and styles:


277 \RequirePackage[extdata,extstyle]{exframe}

Set solutions switch and declare two-sided layout only if no solutions are printed; do not use
solution buffer in draft mode for easier identification of potential compile errors:
278 \if\printsol n
279 \exercisesetup{solutions=false}
280 \exercisesetup{twoside=true}
281 \else
282 \exercisesetup{solutions=true}
283 \exercisesetup{twoside=false}
284 \ifdraft
285 \exercisesetup{solutionbuf=false}
286 \fi
287 \fi

Might want to display some metadata (only for partial compile):


288 %%\if\printsol n\else\showprobleminfo{author,source,recycle}\fi

Set some options. Automatically assign labels to problems. Include sheets and problems in
table of contents. Separate solutions by horizontal rules. Count problems, equations and
pages by sheet (unless compiling single problem). Collect solutions below each problem.
Write pdf metadata for sheet when compiling single sheet:
289 \exercisesetup{autolabelproblem}
290 \exercisestyle{contents,solutionsep}
291 \ifchilddocmanual\else
292 \exercisestyle{pagebysheet,problembysheet,equationbysheet,sheetequation}
293 \fi
294 \exercisestyle{solutionbelow={problem}}
295 \ifchilddoc\ifchilddocmanual\else\exercisesetup{pdfdata=sheet}\fi\fi

Language. Redefine some terms:


296 \metasetlang{en-GB}
297
298 \metasetterm[en]{sheet}{sheet}

28
299 \metasetterm[en]{sheets}{sample sheets}
300 \metasetterm[en]{solution}{Solution}
301 \metasetterm[en]{solutions}{solutions}

Layout Definitions. Set page dimensions and layout:


302 \RequirePackage[a4paper,margin=2.5cm]{geometry}
303 \pagestyle{plain}

Remove paragraph indentation:


304 \setlength\parindent{0pt}
305 \setlength\parskip{\smallskipamount}

Show overfull lines:


306 \setlength\overfullrule{5pt}

Define turn page over mark; hide when printing solutions:


307 \newcommand{\turnover}{\ifsolutions\else\vfill%
308 \hfill{\mathversion{bold}$\longrightarrow$}\newpage\fi}

Sheet Banner. Use standard sheet banner; show sheet editdate below banner (if de-
clared); when compiling single sheet, display sheet due date instead:
309 \exercisestyle{plainheader}
310 \exerciseconfig{composeheaderbelowright}
311 {\sheetdataempty{editdate}{}{version: \getsheetdata{editdate}}}
312 \ifchilddoc\ifsolutions\else
313 \exerciseconfig{composeheaderbelowright}
314 {\sheetdataempty{due}{}{due: \getsheetdata{due}}}
315 \fi\fi

Lorem. Define a macro \lorem to write out some paragraph of text for the example:
316 \def\lorem{Lorem ipsum dolor sit amet, consectetur adipisici elit,
317 sed eiusmod tempor incidunt ut labore et dolore magna aliqua.
318 Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
319 nisi ut aliquid ex ea commodi consequat.
320 Quis aute iure reprehenderit in voluptate velit esse
321 cillum dolore eu fugiat nulla pariatur.
322 Excepteur sint obcaecat cupiditat non proident,
323 sunt in culpa qui officia deserunt mollit anim id est laborum.\par}

metapost Setup. Use package mpostinl (if available) to include some metapost figures
within the source of the problems:
324 \IfFileExists{mpostinl.sty}{\RequirePackage{mpostinl}}{}
325 \ifdefined\mpostsetup

Setup mpostinl. Use checksums to invoke metapost only when figures change. Process all
figures individually and immediately when in draft mode for child documents (avoids a
second compilation pass). Number figures within sheet to provide a stable numbering upon
insertion/deletion of new figures or partial compilation:
326 \mpostsetup{checksum}
327 \ifchilddoc\ifdraft\mpostsetup{now,nowall}\fi\fi
328 \ifchilddocmanual\else\mpostsetup{numberwithin={sheet}}\fi

29
Global metapost definitions. Define some latex macro to demonstrate usage of latex for
typesetting labels. Define some global metapost variables, paths is an array of path vari-
ables, xu serves as a length unit to scale individual figures (use interim xu:=...; to set
scale for local figure only), pensize changes the size of the pen, fillshape fills and outlines
a shape:
329 \mpostsetup{globaldef=true}
330 \begin{mposttex}
331 \def\figure{figure}
332 \end{mposttex}
333 \begin{mpostdef}
334 path paths[];
335 newinternal numeric xu;
336 xu:=1cm;
337 def pensize(expr s)=withpen pencircle scaled s enddef;
338 def fillshape(expr p,c)=
339 fill p withcolor c;
340 draw p
341 enddef;
342 \end{mpostdef}
343 \mpostsetup{globaldef=false}

Close optional mpostinl processing:


344 \fi

Document Data. Set document data for series of problem sheets:


345 \metaset{course}{exframe package samples}
346 \metaset{instructor}{N.\ Beisert}
347 \metaset{author}{Niklas Beisert, \metapick[#1]{institution}}
348 \metaset{institution}{exframe academy}
349 \metaset{period}{spring 2019}
350 \metaset{copyrightdate}{2019--2020}

Assemble some entries from given data:


351 \metaset{material}{\metatranslate[#1]{sheets}}
352 \exerciseconfig{composetitlesheet}[2]{\exerciseifempty{#2}%
353 {\ifsolutions\metaterm{solutions}\else%
354 \metaterm{sheet}\fi\ #1}%
355 {\ifsolutions\metaterm{solutions} \fi #2}}

For child documents declare part of:


356 \ifchilddoc
357 \metaset{partof}{\metatranslate[#1]{sheets} \metapick[#1]{course}}
358 \fi

Set general purpose metadata:


359 \metaset[sep]{draft}{ -- }
360 \metaset[sep]{subtitle}{, }
361 \metaset{subtitle}{\ifsolutions\metatranslate[#1]{solutions} \fi%
362 \metaif[use]{sheettitle}{\metapick[#1]{sheettitle}}{\metapick[#1]{material}}}
363 \metaset{subject}{Lecture Series,
364 \metapick[#1]{institution}, \metapick[#1]{period}}

License. It is good practice to specify a copyright line and a license for the document:

30
365 \metaset{copyrightowner}{\metapick[#1]{author}}
366 \ifchilddoc
367 \metacopyright{doc}
368 \else
369 \metacopyright{doc-parts}
370 \fi
371 \metaset{licenseprovider}{of \metapick[#1]{institution}}
372 \metalicense{consent}

Apply Creative Commons BY-SA license under certain conditions (no solutions, final ver-
sion):
373 \ifsolutions\else\ifdraft\else
374 \metalicensecc{by-sa}
375 \fi\fi

Body. Start document body:


376 \begin{document}

Single Problem Display. The following code handles the compilation of individual
problems from their own source file. Make sure to leave the conditional before issuing
\end{document}:
377 \def\tmp{}
378 \ifchilddocmanual
379 \def\tmp{\end{document}}
380 \input{\childdocname}
381 \fi\tmp

Frontmatter. Do not print frontmatter for individual sheets. Define a plain page counter
for frontmatter:
382 \setcounter{section}{-1}
383 \begingroup\ifchilddoc\else
384 \renewcommand{\thepage}{\arabic{page}}

Prepare a title page to display some relevant data:


385 \pdfbookmark[1]{\metaterm{title}}{title}
386 \thispagestyle{empty}
387 \vspace*{\fill}
388 \begin{center}
389 \metapick[course]{titletext}
390 \end{center}
391 \vspace*{\fill}\vspace*{\fill}
392 \newpage

Prepare a copyright and license page using data specified above:


393 \phantomsection\pdfbookmark[1]{\metaterm{copyright}}{copyright}
394 \thispagestyle{empty}
395 \vspace*{\fill}\vspace*{\fill}
396 \begin{center}\begin{minipage}{11cm}\raggedright
397 \metapick[print]{rightstext}
398 \end{minipage}\end{center}
399 \vspace*{\fill}\vspace*{\fill}\vspace*{\fill}
400 \newpage

31
Print table of contents:
401 \makeatletter\renewcommand\@pnumwidth{2.4em}\makeatother
402 \setcounter{tocdepth}{2}
403 \phantomsection\pdfbookmark[1]{\metaterm{contents}}{contents}
404 {\parskip0pt\tableofcontents}
405 \exercisecleardoublepage\setcounter{page}{1}

End of frontmatter:
406 \fi\endgroup

Include Sheets. Include problem sheets:


407 \include{exfser01}
408 \include{exfser02}
409 \include{exfser03}

Include sheet to collect unused problems (only process for individual sheets, i.e. itself):
410 \def\jobnameunused{exfseraa}
411 \ifx\childdocname\jobnameunused\include{\jobnameunused}\fi

End. End of document body:


412 \end{document}

B.2 Sheet File


Provide some source files exfser01.tex, exfser02.tex, exfser03.tex, exfseraa.tex for
problem sheets.

childdoc Mechanism. Instruct the package childdoc to compile only the present sheet if
source is compiled by latex:
413 %%\providecommand{\printsol}{n}
414 \input{childdoc.def}
415 \childdocof{exfserm}

The parameter of \childdocof must match the main file name exfserm. Uncommenting
the commented line suppressed printing of the solution.

Sheet Environment. Declare a sheet with intended due date:


416 \begin{sheet}[due={2019-04-29}]

Adjust due date for each sheet. For sheet containing unused problems exfseraa.tex, declare
a sheet title={unused problems} instead of due date.

Problems. Start a problem:


417 \begin{problem}[title={Sample A}]

Let us declare a figure using mpostinl (if available). Denote it by the label tag-fig, where
tag is the tag of the problem (in order to avoid potential conflicts with other problems; tag is
assigned automatically or by specifying the option tag for the problem environment). Also
declare a figure tag-solfig for use within the solution:

32
418 \ifdefined\mpostuse
419 \begin{mpostfig}[label={\problemtag-fig}]
420 interim xu:=1.5cm;
421 paths[1]:=fullcircle scaled 1xu;
422 fillshape(paths[1], 0.7white) pensize(1pt);
423 label(btex \figure etex, center(paths[1]));
424 \end{mpostfig}
425 \begin{onlysolutions}
426 \begin{mpostfig}[label={\problemtag-solfig}]
427 interim xu:=1.5cm;
428 paths[1]:=fullcircle scaled 1xu;
429 paths[2]:=((subpath (-2,2) of paths[1])--cycle) shifted (+0.5xu,0);
430 paths[3]:=((subpath (2,6) of paths[1])--cycle) shifted (-0.5xu,0);
431 fillshape(paths[2], 0.7white) pensize(1pt);
432 fillshape(paths[3], 0.7white) pensize(1pt);
433 \end{mpostfig}
434 \end{onlysolutions}
435 \fi

Write a problem body with figure, some subproblems and a solution:


436 \lorem
437
438 \begin{subproblem}
439 \lorem
440 \begin{center}
441 \ifdefined\mpostuse\mpostuse{\problemtag-fig}\else figure\fi
442 \end{center}
443 \lorem
444 \end{subproblem}
445
446 \begin{solution}
447 \lorem
448 \begin{center}
449 \ifdefined\mpostuse\mpostuse{\problemtag-solfig}\else figure\fi
450 \end{center}
451 \lorem
452 \end{solution}
453
454 \begin{subproblem}
455 \lorem
456 \end{subproblem}
457
458 \begin{solution}
459 \lorem
460 \end{solution}
461
462 \lorem
463
464 \begin{subproblem}
465 \lorem
466 \end{subproblem}
467
468 \begin{solution}
469 \lorem
470 \end{solution}

End the problem:


471 \end{problem}

33
Start new page:
472 \turnover

Write a second problem to accompany the first one:


473 \begin{problem}[title={Sample B}]

Problem body without a figure; this time the solution environments are included in the
subproblem environments:
474 \lorem
475
476 \begin{subproblem}
477 \lorem
478 \begin{solution}
479 \lorem
480 \end{solution}
481 \end{subproblem}
482
483 \begin{subproblem}
484 \lorem
485 \begin{solution}
486 \lorem
487 \end{solution}
488 \end{subproblem}

End the problem:


489 \end{problem}

End Sheet. End the sheet:


490 \end{sheet}

B.3 Individual Problem Files


It may be more convenient to define each problem in an individual file, so that a sheet
can be composed by including the appropriate problem files. In such a setup, the childdoc
mechanism allows to compile each problem individually.
To that end, prepare a file exfserpnn.tex containing the problem environment. This file
should start with:
491 %%\providecommand{\printsol}{n}
492 \input{childdoc.def}
493 \childdocby{exfserm}

and end with \endinput. Then compose the problem sheet by including the appropriate
set of problem files via \input{exfserpnn}.
In the example, a sheet file exfser03.tex includes two problem files exfserpe.tex and
exfserpf.tex.

B.4 Make Scripts


The setup allows the compilation in various modes for editing purposes. In order to generate
and update a complete set of documents for distribution (all individual sheets and a collection
of sheets; with and without solutions), it makes sense to use the software development utility
make. The compilation of individual components is simplified by a bash shell script.

34
Compile Script. The bash shell script exfsermk.sh compiles one part of the collection
of problem sheets in a given mode.
Shebang for bash script:
494 #!/bin/bash

Configure and declare variables with default values. srcmain defines the name of the main
source file; srcsecnn defines the name of the sheet source file; trglist defines the target
file names; trgsol defines the target modes; sheets is a list of allowable sheet identifiers
nn:
495 srcmain="exfserm"
496 srcsec="exfser"
497 trglist=(Problems Solutions)
498 trgsol=(n y)
499 secnum="01 02 03 aa"

Display usage:
500 if [ -z $1 ]
501 then
502 echo "Usage:
503 $0 number [version]
504 number: number of sheet, 0 for combined document
505 version: 0 for problems, 1 for solutions
506 $0 filename
507 filename: target file to be compiled"
508 exit 1
509 fi

Configure and declare variables with default values. num takes the sheet number; ver takes
the compile mode;
510 num="$1"
511 ver="$2"
512 nl=$’\n’
513 secokay=""
514 make=".pdf"

Check if the parameter matches any of the acceptable output file names:
515 for v in "${trglist[@]}"
516 do
517 if [[ $num =~ ^$v ]]
518 then
519 ver=$v
520 num=${num#$v}
521 if [[ $num =~ ^.*\.tex$ ]]; then make=".tex"; fi
522 num=${num%%.*}
523 fi
524 done

Ensure that num is a two-digit number, prepend ‘0’ otherwise:


525 if [[ $num =~ ^[0-9]$ ]]; then num="0$num"; fi
526 if [[ $num == "00" ]]; then num=""; fi

Check whether num is acceptable:


527 if [[ -z $num ]]; then secokay="okay"; fi
528 for v in $secnum
529 do

35
530 if [[ "$num" == "$v" ]]; then secokay="okay"; fi
531 done

Otherwise display error message and exit:


532 if [[ -z $secokay ]]
533 then
534 echo "error: unknown sheet"
535 exit 1
536 fi

Disable newline character for command line tex code:


537 if [[ "$make" == ".pdf" ]]; then nl=""; fi

Function to compile a component. Set up childdoc mechanism according to desired com-


ponent. Compile two passes, first in -draftmode. Suppress messages by mpost. Display
warning messages in log file:
538 function docompile
539 {
540 if [[ -z $num ]]
541 then
542 job="$srcmain"
543 fwd="\\childdocforward{$srcmain}"
544 else
545 job="$srcsec$num"
546 fwd="\\childdocforward[$srcmain]{$srcsec$num}"
547 fi
548 body="\\def\\jobname{$job}$optdef\\input{childdoc.def}$fwd"
549 for pass in first main extra
550 do
551 par="";
552 if [[ "$pass" == "first" ]]; then par="-draftmode"; fi
553 drop="This is|entering extended mode|\\write18"
554 drop="$drop|Preloading the plain mem file|mpost\.mp|plain\.mp"
555 pdflatex -shell-escape -interaction=batchmode $par \
556 -jobname "$trg" "$body" | grep -vE "$drop"
557 if [[ "$pass" != "main" ]]; then continue; fi
558 if ! (grep -E -q "may have changed|rerunfilecheck Warning" "$trg.log")
559 then break; fi
560 done
561 grep -E "^! |Warning|Error|Undefined|Overfull|Underfull" "$trg.log"
562 }

Function to generate a childdoc compile file with specific options:


563 function writesource
564 {
565 if [[ -z $num ]]
566 then
567 fwd="\\childdocforward{$srcmain}"
568 else
569 fwd="\\childdocforwardprefix[$srcmain]{$target}{$srcsec}"
570 fi
571 body="$optdef\\input{childdoc.def}$nl$fwd"
572 echo "$body" > $trg.tex
573 }

Translate versions to parameter values, configure variables and select appropriate function
for intended task:

36
574 for i in "${!trglist[@]}"
575 do
576 if [[ -z $ver || "$ver" == "${trglist[$i]}" || $ver = $i ]]
577 then
578 target="${trglist[$i]}"
579 sol="${trgsol[$i]}"
580 trg="$target$num"
581 optdef="\\def\\draftver{n}$nl\\def\\printsol{$sol}$nl"
582 if [[ "$make" == ".pdf" ]]; then docompile; else writesource; fi
583 fi
584 done

Finish with blank line:


585 echo

Makefile. Define a make file exfsermk.mak for the project. The compilation is then
started by make -f exfsermk.mak . . . . More conveniently, in a single-project setup within
the directory, this file would be called Makefile in which case it suffices to just run make
....
Configuration definitions:
586 SRCMAIN = exfserm
587 SRCSEC = exfser
588 SRCPRB = exfserp
589 SCRIPT = exfsermk.sh
590 MAKEFILE = exfsermk.mak
591 TRGLIST = Problems Solutions
592 SECNUM = 01 02 03 aa
593 PREREQS = $(SRCMAIN).tex
594
595 SRCSECFILES = $(SECNUM:%=$(SRCSEC)%.tex)
596 TRGMAINFILES = $(foreach trg,$(TRGLIST),$(trg).pdf)
597 TRGSECFILES = $(foreach trg,$(TRGLIST),$(trg).pdf $(SECNUM:%=$(trg)%.pdf))
598 GENFILES = $(foreach trg,$(TRGLIST),$(trg).tex $(SECNUM:%=$(trg)%.tex))
599 BAKFILES = $(PREREQS) $(SRCSECFILES) $(GENFILES)\
600 $(MAKEFILE) $(SCRIPT) $(SRCPRB)*

Define some abstract targets; default is the default target when no parameters are given:
601 default: sheets ;
602 main: $(TRGMAINFILES) ;
603 sheets: $(TRGSECFILES) ;
604 sheet%: $(foreach trg,$(TRGLIST),$(trg)%.pdf) ;
605 all: main sheets ;
606 sources: $(GENFILES) ;

Compile particular files via exfsermk.sh bash script. Note that command lines have to
start with a tab character (represented by 8 spaces here):
607 $(TRGMAINFILES): $(SRCSECFILES) $(PREREQS)
608 bash ./$(SCRIPT) $@
609 $(word 1,$(TRGLIST))%.pdf: $(SRCSEC)%.tex $(PREREQS)
610 bash ./$(SCRIPT) $@
611 $(word 2,$(TRGLIST))%.pdf: $(SRCSEC)%.tex $(PREREQS)
612 bash ./$(SCRIPT) $@
613 $(GENFILES):
614 bash ./$(SCRIPT) $@

37
Touch main file for recompile:
615 touch:
616 touch $(SRCMAIN).tex

Define clean target to remove all intermediate compilation files:


617 clean:
618 rm -f $(foreach ext,.aux .log,$(SECNUM:%=$(SRCSEC)%$(ext)))
619 rm -f $(foreach trg,$(TRGLIST),$(SECNUM:%=$(trg)%.log) $(trg).log)
620 rm -f $(foreach ext,.aux .log .out .toc,$(SRCMAIN)$(ext))
621 rm -f $(foreach ext,.mp .mpx -*.mps,$(SRCMAIN)$(ext))
622 rm -f $(foreach ext,-tmp.log -tmp.mp -tmp.mpx,$(SRCMAIN)$(ext))
623 rm -f mpxerr.tex mpxerr.log mpxerr.dvi texput.log
624 rm -f $(patsubst %,$(SRCPRB)*%,.aux .log .mp .mpx -*.mps)
625 rm -f $(patsubst %,$(SRCPRB)*%,-tmp.log -tmp.mp -tmp.mpx)

Define clean-bak target to remove all backup files ending in ‘~’ or ‘.bak’:
626 clean-bak:
627 rm -f $(BAKFILES:%=%~) $(BAKFILES:%=%.bak)

Define clean-all target to remove all generated files for a clean source directory:
628 clean-all: clean
629 rm -f $(TRGSECFILES) $(TRGMAINFILES) $(GENFILES)
630 rm -f $(SECNUM:%=$(SRCSEC)%.pdf) $(SRCMAIN).pdf
631 rm -f $(SRCPRB)*.pdf

C Implementation
This section describes the package exframe.sty.

C.1 General Definitions


Required Packages. The package loads the package verbatim and xkeyval if not yet
present. verbatim is used for solution environment reading and xkeyval is used for extended
options processing:
632 \RequirePackage{verbatim}
633 \RequirePackage{xkeyval}

General Definitions.

\exf@empty Define an empty macro for comparison by \ifx:


634 \def\exf@empty{}

\exf@tmpdim Define a length for temporary storage:


635 \newlength\exf@tmpdim

\exf@exptwo A macro to conveniently expand the third token in line:


636 \def\exf@exptwo#1{\expandafter#1\expandafter}

\exf@exparg A macro to conveniently expand the first token of an argument following arbitrary code:

38
637 \long\def\exf@expswitch#1#2{#2{#1}}
638 \long\def\exf@exparg#1#2{\exf@exptwo\exf@expswitch{#2}{#1}}

\exf@csdo Some macros to conveniently expand \csname arguments before expanding the macro:
\exf@csdotwo
639 \def\exf@csdo#1#2{\expandafter#1\csname#2\endcsname}
640 \def\exf@csdotwo#1#2#3{\exf@exptwo#1#2\csname#3\endcsname}

\exf@csor A macro to return \csname or default if not exists:


641 \def\exf@csor#1#2{\ifcsname#1\endcsname\csname#1\endcsname\else#2\fi}

\exf@append@def Add definitions to macros (after or before original content):


\exf@prepend@def
642 \long\def\exf@append@def#1#2{\exf@exptwo\def#1\expandafter{#1#2}}
643 \long\def\exf@prepend@switch#1#2#3{#2{#3#1}}
644 \long\def\exf@prepend@def#1#2{\exf@exptwo\exf@prepend@switch{#1}{\def#1}{#2}}

\exf@expsetkeys A version of \setkeys from xkeyval which expands first:


645 \newcommand{\exf@expsetkeys}[2]{\edef\exf@tmp{#2}%
646 \exf@exparg{\setkeys{#1}}{\exf@tmp}}

\exf@isif Execute #3 if content of macro #1 equals #2:


647 \newcommand{\exf@ifis}[3]%
648 {\def\exf@tmp{#2}\ifx#1\exf@tmp#3\fi}

\exf@href Display text with hyperreference passed by macro #1 (in case hyperref is loaded and the
reference is defined and not empty):
649 \newcommand{\exf@href}[2]{%
650 \ifdefined#1\ifx#1\exf@empty#2\else%
651 \ifdefined\hyperlink\protect\hyperlink{#1}{#2}\else#2\fi\fi\else#2\fi}

\exf@text Two macros to display text in math mode. exf@text is a wrapper for \text of amstext in
\exf@ensuretext case the latter package is loaded. exf@ensuretext makes sure the text is set in text mode
or within an \mbox in math math:
652 \newcommand{\exf@text}[1]{\ifdefined\text\text{#1}\else#1\fi}
653 \newcommand{\exf@ensuretext}[1]{\ifmmode\mbox{#1}\else#1\fi}

\exf@addcontentsline Add a line to the table of contents unless macro in argument #1 is empty:
654 \newcommand{\exf@addcontentsline}[2]{%
655 \ifx#1\exf@empty\else\addcontentsline{toc}{#1}{#2}\fi}

Auxiliary File Data Storage.

\exf@notedata Process stored data by handler:


656 \newcommand{\exf@notedata}[3]{\csname exf@notedata@#1\endcsname{#2}{#3}}

Make sure the macros in code written to the .aux file exist:
657 \AtBeginDocument{\immediate\write\@auxout{%
658 \string\providecommand{\string\exf@notedata}[3]{}}}

\exf@writedata Write data to the .aux file:


659 \newcommand{\exf@writedata}[3]%
660 {\immediate\write\@auxout{\string\exf@notedata{#1}{#2}{#3}}}

39
C.2 Package Setup
Initialisation Options.

exframe.sty Some setup options are available while loading the package only.
Configure names of main environments and counters:
661 \def\exf@problemname{problem}
662 \def\exf@subproblemname{sub\exf@problemname}
663 \def\exf@solutionname{solution}
664 \def\exf@sheetname{sheet}
665 \def\exf@problemcounter{problem}
666 \def\exf@subproblemcounter{sub\exf@problemcounter}
667 \def\exf@solutioncounter{solution}
668 \def\exf@sheetcounter{sheet}
669 \define@key{exframe.sty}{problemenv}{\def\exf@problemname{#1}}
670 \define@key{exframe.sty}{subproblemenv}{\def\exf@subproblemname{#1}}
671 \define@key{exframe.sty}{solutionenv}{\def\exf@solutionname{#1}}
672 \define@key{exframe.sty}{sheetenv}{\def\exf@sheetname{#1}}
673 \define@key{exframe.sty}{problemcounter}{\def\exf@problemcounter{#1}}
674 \define@key{exframe.sty}{subproblemcounter}{\def\exf@subproblemcounter{#1}}
675 \define@key{exframe.sty}{solutioncounter}{\def\exf@solutioncounter{#1}}
676 \define@key{exframe.sty}{sheetcounter}{\def\exf@sheetcounter{#1}}

Whether to provide some extended configuration options (available while loading only):
677 \define@boolkey{exframe.sty}[exf@]{extdata}[true]{}
678 \define@boolkey{exframe.sty}[exf@]{extstyle}[true]{}

Whether to load package metastr (available while loading only):


679 \define@boolkey{exframe.sty}[exf@]{metastr}[true]{}

Setup Options.

exf@setup All remaining setup options are available also when the package is already loaded.
Main switch for solutions:
680 \define@boolkey{exf@setup}[]{solutions}[true]{}

Switch for writing pdf metadata:


681 \define@choicekey{exf@setup}{pdfdata}%
682 {auto,manual,sheet,off}[auto]{\def\exf@metadata{#1}}
683 \def\exf@metadata{auto}

Write line number indicators to output file:


684 \define@boolkey{exf@setup}[exf@]{lineno}[true]{}

Prepare two-sided sheets:


685 \define@boolkey{exf@setup}[exf@]{twoside}[true]{}

Generate hyperreferences from solutions to corresponding problems:


686 \define@boolkey{exf@setup}[exf@]{solutionhref}[true]{}
687 \exf@solutionhreftrue

Automatically generate labels for sheets and problems:


688 \define@boolkey{exf@setup}[exf@]{autolabelsheet}[true]{}
689 \define@boolkey{exf@setup}[exf@]{autolabelproblem}[true]{}

40
Write warning message to document for better detection of inconsistencies:
690 \define@boolkey{exf@setup}[exf@]{warntext}[true]{}

Activate buffering of solutions:


691 \define@boolkey{exf@setup}[exf@]{solutionbuf}[true]{}
692 \exf@solutionbuftrue

Activate buffering of problems:


693 \define@boolkey{exf@setup}[exf@]{problembuf}[true]{}

\exf@emptytestchar Redefine character for testing emptyness:


694 \def\exf@emptytestchar{&}
695 \define@key{exf@setup}{emptytestchar}{\def\exf@emptytestchar{#1}}

Processing. Process global options while loading package:


696 \ProcessOptionsX<exframe.sty,exf@setup>

\exercisesetup Configure package when package is already loaded:


697 \newcommand{\exercisesetup}[1]{\exf@expsetkeys{exf@setup}{#1}}

Additional Packages. Load metastr package if desired:


698 \ifexf@metastr
699 \PassOptionsToPackage{course=true}{metastr}
700 \RequirePackage{metastr}
701 \fi

Solutions Only Processing.

onlysolutions Process block only in solutions mode:


702 \newenvironment{onlysolutions}%
703 {\ifsolutions\else%
704 \let\endonlysolutions\endcomment%
705 \expandafter\comment\fi}%
706 {}

C.3 Configuration
This section defines and describes the various configuration options provided by the package.
It also serves as a manual, and most code can be recycled and adjusted for individual
configurations:

Definitions.

\exerciseconfig Set a configuration macro; store definition in exf@config@#2; use \newcommand for macros
with arguments, but (non-long) \def for plain definitions:
707 \newcommand{\exerciseconfig}[1]{%
708 \@ifnextchar[{\exf@configopt{#1}}{\exf@confignoopt{#1}}}
709 \long\def\exf@configopt#1[#2]#3{%

41
710 \exf@csdo\def{exf@config@#1}{}%
711 \exf@csdo\renewcommand{exf@config@#1}[#2]{#3}}%
712 \long\def\exf@confignoopt#1#2{\exf@csdo\def{exf@config@#1}{#2}}

exerciseconfigappend Append to a (parameterless) configuration macro:


xerciseconfigprepend
713 \newcommand{\exerciseconfigappend}[2]{%
714 \exf@csdo\exf@append@def{exf@config@#1}{#2}}
715 \newcommand{\exerciseconfigprepend}[2]{%
716 \exf@csdo\exf@prepend@def{exf@config@#1}{#2}}

\getexerciseconfig Get configuration macro:


717 \newcommand{\getexerciseconfig}[1]{\csname exf@config@#1\endcsname}

\exerciseconfigempty Test whether configuration macro #1 is empty; execute #2 if empty, otherwise execute #3:
718 \newcommand{\exerciseconfigempty}[3]{\exf@csdo\ifx{exf@config@#1}\exf@empty%
719 #2\else#3\fi}

\exerciseifemtpy Code to test whether #1 (expanded) is empty; execute #2 if empty, otherwise execute #3:
\exerciseifnotempty
720 \long\def\exerciseifempty#1#2#3{%
721 \if\exf@emptytestchar#1\exf@emptytestchar#2\else#3\fi}
722 \long\def\exerciseifnotempty#1#2{%
723 \if\exf@emptytestchar#1\exf@emptytestchar\else#2\fi}

Terms.

term... Terms for sheet, problem, solution and points (for adjustment or internationalisation):
724 \exerciseconfig{termsheet}{Sheet}
725 \exerciseconfig{termsheets}{Sheets}
726 \exerciseconfig{termproblem}{Problem}
727 \exerciseconfig{termproblems}{Problems}
728 \exerciseconfig{termsolution}{Solution}
729 \exerciseconfig{termsolutions}{Solutions}
730 \exerciseconfig{termpoint}{point}
731 \exerciseconfig{termpoints}{points}

Formatting Styles.

style... Formatting styles to be applied for various parts of text. Different styles will be applied in
sequence from more general to more specific.
Basic style for all exercise text:
732 \exerciseconfig{styletext}{\normalsize\normalfont}

Style for problems:


733 \exerciseconfig{styletextproblem}{}

Style for solutions:


734 \exerciseconfig{styletextsolution}{\footnotesize}

Basic style for titles:


735 \exerciseconfig{styletitle}{\bfseries}

42
Style for problem titles:
736 \exerciseconfig{styletitleproblem}{\large}

Style for subproblem titles:


737 \exerciseconfig{styletitlesubproblem}{}

Style for solution titles:


738 \exerciseconfig{styletitlesolution}{}

Style for problem section title in solution block:


739 \exerciseconfig{styletitlesolutionsproblem}{\small}

Style for solution block title:


740 \exerciseconfig{styletitlesolutions}{\normalsize}

Style for problem block title:


741 \exerciseconfig{styletitleproblems}{\Large}

Spacing.

skip... Spaces related to various elements. Vertical space is typically combined with space declared
elsewhere using \addvspace.
Space above problem environment:
742 \exerciseconfig{skipproblemabove}{3.25ex plus 1ex minus 1.5ex}

Space below problem environment:


743 \exerciseconfig{skipproblembelow}{3pt plus 1pt minus 1pt}

Space below or after problem title; positive numbers generate vertical space (problem body
is started in new paragraph), negative numbers generate horizontal space (problem body
continues on opening line):
744 \exerciseconfig{skipproblemtitle}{3pt plus 1pt minus 1pt}

Horizontal space between items in the problem opening line:


745 \exerciseconfig{skipprobleminfo}{0.5em}

Space for problem item and indentation; 0pt means no indentation and direct display of
title; positive numbers define an absolute amount; -1pt (or any negative number) computes
the amount of indentation from the width of (standard) item plus separator:
746 \exerciseconfig{skipproblemitem}{0pt}

Spaces related to subproblem environment; analogous to spaces related to problem environ-


ment, see above:
747 \exerciseconfig{skipsubproblemabove}{1.5ex plus 0.5ex minus 1ex}
748 \exerciseconfig{skipsubproblembelow}{1.5ex plus 0.5ex minus 1ex}
749 \exerciseconfig{skipsubproblemtitle}{-1em}
750 \exerciseconfig{skipsubprobleminfo}{0.25em}
751 \exerciseconfig{skipsubproblemitem}{-1pt}

Spaces related to solution environment; analogous to spaces related to problem environment,


752 \exerciseconfig{skipsolutionabove}{0ex}

43
753 \exerciseconfig{skipsolutionbelow}{1.5ex plus 0.5ex minus 1ex}
754 \exerciseconfig{skipsolutiontitle}{-0.5em}
755 \exerciseconfig{skipsolutioninfo}{0.25em}

skipsolutionitem and skipsolutionitemsub are analogous to skipproblemitem de-


scribed above; they apply to solutions corresponding to problems and subproblems, re-
spectively:
756 \exerciseconfig{skipsolutionitem}{0pt}
757 \exerciseconfig{skipsolutionitemsub}{0pt}

Spaces related to solution blocks; space above and below a solution block:
758 \exerciseconfig{skipsolutionsabove}{1.5ex plus 0.5ex minus 1ex}
759 \exerciseconfig{skipsolutionsbelow}{1.5ex plus 0.5ex minus 1ex}

Space above problem titles in a solution block:


760 \exerciseconfig{skipsolutionsproblemabove}{1.0ex plus 0ex minus 0.5ex}

Space following problem titles in a solution block (with legacy definition):


761 \exerciseconfig{skipsolutionsproblemtitle}{1.0ex plus 0ex minus 0.5ex}
762 \exerciseconfig{skipsolutionsproblem}{\exf@config@skipsolutionsproblemtitle}

Space following title of a solution block:


763 \exerciseconfig{skipsolutionstitle}{1.0ex plus 0ex minus 0.5ex}

Spaces related to problem blocks; space above and below a problem block:
764 \exerciseconfig{skipproblemsabove}{1.5ex plus 0.5ex minus 1ex}
765 \exerciseconfig{skipproblemsbelow}{1.5ex plus 0.5ex minus 1ex}

Space following title of a problem block:


766 \exerciseconfig{skipproblemstitle}{1.0ex plus 0ex minus 0.5ex}

Hook Code.

insert... Code to process data and to insert text at various points of processing.
Code to generate the title for a sheet; minimalistic default to display the sheet title:
767 \exerciseconfig{insertsheettitle}{\centerline{\getsheetdata{title}}}

Code to clear the page at the start and at the end of a new sheet:
768 \exerciseconfig{insertsheetclearpage}{\exercisecleardoublepage}

Code to insert before a sheet is displayed:


769 \exerciseconfig{insertsheetbefore}{}

Code to insert after a sheet is displayed:


770 \exerciseconfig{insertsheetafter}{}

Code to insert before a solution block is displayed:


771 \exerciseconfig{insertsolutionsbefore}{}

Code to insert after a solution block is displayed:


772 \exerciseconfig{insertsolutionsafter}{}

44
Code to insert before a problem block is displayed:
773 \exerciseconfig{insertproblemsbefore}{}

Code to insert after a problem block is displayed:


774 \exerciseconfig{insertproblemsafter}{}

Code to insert before a problem is displayed:


775 \exerciseconfig{insertproblembefore}{}

Code to insert after a problem is displayed:


776 \exerciseconfig{insertproblemafter}{}

Code to insert between a problem and its solution (if style solutionbelow is problem):
777 \exerciseconfig{insertproblemsolution}{}

Code to insert text into the problem opening line by means of \addprobleminfo:
778 \exerciseconfig{insertprobleminfo}{}

Code to determine the display of problems:


779 \exerciseconfig{insertproblemselect}[1]{}

Analogous definitions for subproblems:


780 \exerciseconfig{insertsubproblembefore}{}
781 \exerciseconfig{insertsubproblemafter}{}
782 \exerciseconfig{insertsubprobleminfo}{}
783 \exerciseconfig{insertsubproblemsolution}{}

Analogous definitions for solutions:


784 \exerciseconfig{insertsolutionbefore}{}
785 \exerciseconfig{insertsolutionafter}{}
786 \exerciseconfig{insertsolutioninfo}{}

Text Composition for Environments.

compose... Macros to generate text for various situations. Preferably the output is plain text without
formatting, but in some situations it may be required to address formatting in these macros.
Default separator for items:
787 \exerciseconfig{composeitemsep}{\ }

Compose sheet title; arguments are sheet number and raw title (empty if not specified);
default is “Sheet #1” or given title “#2”:
788 \exerciseconfig{composetitlesheet}[2]%
789 {\exerciseifempty{#2}{\getexerciseconfig{termsheet} #1}{#2}}

Compose sheet title for pdf metadata; arguments are sheet number and raw title:
790 \exerciseconfig{composemetasheet}[2]%
791 {\getexerciseconfig{composetitlesheet}{#1}{#2}}

Compose sheet title for table of contents; arguments are sheet number and raw title:
792 \exerciseconfig{composetocsheet}[2]%
793 {\exerciseifempty{#2}{\getexerciseconfig{termsheet} #1}{#1. #2}}

45
Compose problem item; argument is problem number:
794 \exerciseconfig{composeitemproblem}[1]{#1.}

Problem item separator:


795 \exerciseconfig{composeitemproblemsep}%
796 {\getexerciseconfig{composeitemsep}}

Compose problem title; arguments are problem number (empty if item is split off) and raw
title (empty if not specified); default is “Problem #1.” or “#1. #2”:
797 \exerciseconfig{composetitleproblem}[2]{\exerciseifempty{#1}%
798 {\exerciseifempty{#2}{}{#2}}%
799 {\exerciseifempty{#2}{\getexerciseconfig{termproblem}\ %
800 \getexerciseconfig{composeitemproblem}{#1}}%
801 {\getexerciseconfig{composeitemproblem}{#1} #2}}}

Compose problem title for table of contents; arguments are problem number and raw title:
802 \exerciseconfig{composetocproblem}[2]%
803 {\exerciseifempty{#2}{\getexerciseconfig{termproblem} #1}{#1. #2}}

Compose subproblem item; argument is subproblem number:


804 \exerciseconfig{composeitemsubproblem}[1]{#1}

Subproblem item separator:


805 \exerciseconfig{composeitemsubproblemsep}%
806 {\getexerciseconfig{composeitemsep}}

Compose subproblem title; argument is subproblem number:


807 \exerciseconfig{composetitlesubproblem}[1]{#1}

Compose solution item; arguments are problem and subproblem number:


808 \exerciseconfig{composeitemsolution}[2]{#1.}
809 \exerciseconfig{composeitemsolutionsub}[2]{#2}

Solution item separator:


810 \exerciseconfig{composeitemsolutionsep}%
811 {\getexerciseconfig{composeitemsep}}

Compose title for single solution; arguments are corresponding problem and subproblem
number:
812 \exerciseconfig{composetitlesolutionsingle}[2]%
813 {\getexerciseconfig{termsolution}:}

Compose title for one out of several solutions; arguments are corresponding problem and
subproblem number:
814 \exerciseconfig{composetitlesolutionmulti}[2]{#2}

Compose table of contents line for solution; arguments are problem number and raw title:
815 \exerciseconfig{composetocsolution}[2]%
816 {\getexerciseconfig{composetocproblem}{#1}{#2}}

Compose title for solution block:


817 \exerciseconfig{composetitlesolutions}%
818 {\getexerciseconfig{termsolutions}}

46
Compose title for problem block:
819 \exerciseconfig{composetitleproblems}%
820 {\getexerciseconfig{termproblems}}

Compose table of contents line for solution block:


821 \exerciseconfig{composetocsolutions}%
822 {\getexerciseconfig{composetitlesolutions}}

Compose table of contents line for problem block:


823 \exerciseconfig{composetocproblems}%
824 {\getexerciseconfig{composetitleproblems}}

Compose sectional title for solution following a single problem; arguments are problem
number and raw title:
825 \exerciseconfig{composetitlesolutionsproblemsingle}[2]%
826 {\getexerciseconfig{termsolution}}

Compose sectional title for solution of one problem within a solution block; arguments are
problem number and raw title:
827 \exerciseconfig{composetitlesolutionsproblemmulti}[2]%
828 {\exerciseifempty{#2}{\getexerciseconfig{termproblem} #1}{#1. #2}}

Compose label:
829 \exerciseconfig{composeitemsolutionlabel}[2]{#1#2}

Points. Compose number of points:


830 \exerciseconfig{composepointsnum}[1]{#1}

Compose number of points followed by ‘points’; use singular ‘point’ for 1:


831 \exerciseconfig{composepoints}[1]{\getexerciseconfig{composepointsnum}{#1}~%
832 \ifdim #1pt=1pt\getexerciseconfig{termpoint}%
833 \else\getexerciseconfig{termpoints}\fi}

Compose points declaration for use in opening line:


834 \exerciseconfig{composepointsstart}[1]{(\getexerciseconfig{composepoints}{#1})}

Compose points declaration for use in margin:


835 \exerciseconfig{composepointsmargin}[1]{\getexerciseconfig{composepoints}{#1}}

Compose points declaration for use in text:


836 \exerciseconfig{composepointsbody}[1]{(\getexerciseconfig{composepoints}{#1})}

Compose points declaration for use in sheet data:


837 \exerciseconfig{composepointssheet}[1]{%
838 \exerciseifnotempty{#1}{\getexerciseconfig{composepoints}{#1}}}

Compose points declaration for solution with comment:


839 \exerciseconfig{composepointsaward}[2]%
840 {(\getexerciseconfig{composepoints}{#1}\exerciseifnotempty{#2}{; #2})}

Compose alternative points for solution declaration with comment:


841 \exerciseconfig{composepointsawardalt}[2]%
842 {(\getexerciseconfig{composepoints}{#1}*\exerciseifnotempty{#2}{; #2})}

47
Compose pairs of points; omit 0 components:
843 \exerciseconfig{composepointspair}[2]{%
844 \ifdim#2pt=0pt%
845 \getexerciseconfig{composepoints}{#1}%
846 \else\ifdim#1pt=0pt%
847 +\getexerciseconfig{composepoints}{#2}%
848 \else%
849 \getexerciseconfig{composepointsnum}{#1}+%
850 \getexerciseconfig{composepointsnum}{#2}~%
851 \getexerciseconfig{termpoints}%
852 \fi\fi}

Compose pairs of points for designated use; recycle plain definition if no bonus points given:
853 \exerciseconfig{composepointspairbody}[2]{%
854 \ifdim#2pt=0pt\getexerciseconfig{composepointsbody}{#1}\else%
855 (\getexerciseconfig{composepointspair}{#1}{#2})\fi}
856 \exerciseconfig{composepointspairstart}[2]{%
857 \ifdim#2pt=0pt\getexerciseconfig{composepointsstart}{#1}\else%
858 (\getexerciseconfig{composepointspair}{#1}{#2})\fi}
859 \exerciseconfig{composepointspairmargin}[2]{%
860 \ifdim#2pt=0pt\getexerciseconfig{composepointsmargin}{#1}\else%
861 \getexerciseconfig{composepointspair}{#1}{#2}\fi}
862 \exerciseconfig{composepointspairsheet}[2]{%
863 \ifdim#2pt=0pt\getexerciseconfig{composepointssheet}{#1}\else%
864 \getexerciseconfig{composepointspair}{#1}{#2}\fi}
865 \exerciseconfig{composepointspairaward}[3]{%
866 \ifdim#2pt=0pt\getexerciseconfig{composepointsaward}{#1}{#3}\else%
867 (\getexerciseconfig{composepointspair}{#1}{#2}%
868 \exerciseifnotempty{#3}{; #3})\fi}
869 \exerciseconfig{composepointspairawardalt}[3]{%
870 \ifdim#2pt=0pt\getexerciseconfig{composepointsawardalt}{#1}{#3}\else%
871 (\getexerciseconfig{composepointspair}{#1}{#2}*%
872 \exerciseifnotempty{#3}{; #3})\fi}

Compose pairs of points for designated situations:


873 \exerciseconfig{composepointspairbodyproblem}[2]{%
874 \getexerciseconfig{composepointspairbody}{#1}{#2}}
875 \exerciseconfig{composepointspairbodysubproblem}[2]{%
876 \getexerciseconfig{composepointspairbody}{#1}{#2}}
877 \exerciseconfig{composepointspairbodysolution}[2]{%
878 \getexerciseconfig{composepointspairbody}{#1}{#2}}
879 \exerciseconfig{composepointspairstartproblem}[2]{%
880 \getexerciseconfig{composepointspairstart}{#1}{#2}}
881 \exerciseconfig{composepointspairstartsubproblem}[2]{%
882 \getexerciseconfig{composepointspairstart}{#1}{#2}}
883 \exerciseconfig{composepointspairstartsolution}[2]{%
884 \getexerciseconfig{composepointspairstart}{#1}{#2}}

Display points in the margin:


885 \exerciseconfig{insertpointsmargin}[1]{\marginpar{\footnotesize #1}}

Display warning about points mismatch:


886 \exerciseconfig{insertwarnpoints}[3]
887 {\textbf{points mismatch for #1 (#2 determined vs.\ #3 given)}}

Display warning about points changed:

48
888 \exerciseconfig{insertwarnpointsrerun}[1]
889 {\textbf{points changed for #1 (please recompile)}}

Counters. Define counter display via configuration interface:


890 \exerciseconfig{countersheet}{\arabic{\exf@sheetcounter}}
891 \exerciseconfig{counterproblem}{\arabic{\exf@problemcounter}}
892 \exerciseconfig{counterproblemmax}{10}
893 \exerciseconfig{countersubproblem}{\alph{\exf@subproblemcounter})}
894 \exerciseconfig{countersubproblemmax}{m)}
895 \exerciseconfig{countersheetequation}{\arabic{equation}}
896 \exerciseconfig{counterproblemequation}{P\arabic{equation}}
897 \exerciseconfig{countersolutionequation}{S\arabic{equation}}

Further Definitions.

tagsheet Templates for automatic generation of tags:


tagproblem
898 \exerciseconfig{tagsheet}{\arabic{\exf@sheetcounter}}
tagsubproblem
899 \exerciseconfig{tagproblem}{\csname the\exf@problemcounter\endcsname}
900 \exerciseconfig{tagsubproblem}{\problemtag-\arabic{\exf@subproblemcounter}}

labelsheet Templates for automatic generation of labels from tags:


labelproblem
901 \exerciseconfig{labelsheet}[1]{sheet:#1}
labelsubproblem
902 \exerciseconfig{labelproblem}[1]{prob:#1}
903 \exerciseconfig{labelsubproblem}[1]{\getexerciseconfig{labelproblem}{#1}}

toclevel... Table of contents levels for sheets, problems, solutions of problems and solution blocks;
empty means no writing to table of contents:
904 \exerciseconfig{toclevelsheet}{}
905 \exerciseconfig{toclevelproblem}{}
906 \exerciseconfig{toclevelproblems}{}
907 \exerciseconfig{toclevelsolution}{}
908 \exerciseconfig{toclevelsolutions}{}

extsolutions Filename extension for solution and problem blocks:


extproblems
909 \exerciseconfig{extsolutions}{.sol}
910 \exerciseconfig{extproblems}{.prb}

C.4 Styles
Styles are meant as a way to adjust several configuration options at the same time to achieve a
consistent layout in some regard. Useful examples can be found among the extended exercise
styles. They can serve a starting point for further custom styles.

Exercise Styles Code.

\defexercisestylearg Define a style with an argument:


911 \newcommand{\defexercisestylearg}[3][]{%
912 \def\exf@tmp{#1}\ifx\exf@tmp\exf@empty%
913 \define@key{exf@style}{#2}{#3}\else%
914 \define@key{exf@style}{#2}[#1]{#3}\fi}

49
\defexercisestyle Define a style with a boolean argument; execute code onlf if true:
915 \newcommand{\defexercisestyle}[2]{%
916 \exf@csdotwo\long\def{exf@style@code@#1}{#2}%
917 \exf@exparg{\define@boolkey{exf@style}[exf@style@]{#1}[true]}%
918 {\csname ifexf@style@#1\endcsname\csname exf@style@code@#1\endcsname\fi}}

\exercisestyle Process styles:


919 \newcommand{\exercisestyle}[1]{\exf@expsetkeys{exf@style}{#1}}

Default Exercise Styles.

problemmanual Delay display of problems:


920 \define@boolkey{exf@style}[exf@]{problemmanual}[true]{}
921 \exf@problemmanualfalse

solutionbelow Choose location for solutions:


922 \def\exf@solutionbelow{subproblem}
923 \define@choicekey{exf@style}{solutionbelow}%
924 {here,subproblem,subproblem*,problem,problem*,sheet,manual}%
925 {\ifexf@solfile@open\else\gdef\exf@solutionbelow{#1}\fi}

sheetequation Use separate equation counters for sheets, problems and solutions:
problemequation
926 \defexercisestyle{sheetequation}{}
solutionequation
927 \defexercisestyle{problemequation}{}
928 \defexercisestyle{solutionequation}{}
929 \exf@style@solutionequationtrue

problempointsat Choose where points of (sub)problems and solutions are displayed:


subproblempointsat
930 \def\exf@pointsat{start}
solutionpointsat
931 \define@choicekey{exf@style}{problempointsat}%
932 {start,start*,margin,end,manual,off}{\def\exf@pointsat{#1}}
933 \define@choicekey{exf@style}{pointsat}%
934 {start,start*,margin,end,manual,off}{\def\exf@pointsat{#1}}
935 \def\exf@subpointsat{end}
936 \define@choicekey{exf@style}{subproblempointsat}%
937 {start,start*,margin,end,manual,off}{\def\exf@subpointsat{#1}}
938 \define@choicekey{exf@style}{subpointsat}%
939 {start,start*,margin,end,manual,off}{\def\exf@subpointsat{#1}}
940 \def\exf@solpointsat{off}
941 \define@choicekey{exf@style}{solutionpointsat}%
942 {start,start*,margin,end,manual,off}{\def\exf@solpointsat{#1}}
943 \define@choicekey{exf@style}{solpointsat}%
944 {start,start*,margin,end,manual,off}{\def\exf@solpointsat{#1}}

problemby Declare problems or equations as subcounter of other counter:


equationby
945 \defexercisestylearg{problemby}{\exf@numberproblemwithin{#1}}
946 \defexercisestylearg{equationby}{\exf@numberequationwithin{#1}}

pagebysheet Number pages, problems or equations by sheet:


problembysheet
947 \defexercisestyle{pagebysheet}{%
equationbysheet
948 \def\thepage{\csname the\exf@sheetcounter\endcsname.\arabic{page}}%

50
949 \def\theHpage{\csname theH\exf@sheetcounter\endcsname.\arabic{page}}%
950 \exerciseconfigappend{insertsheetbefore}{\setcounter{page}{1}}}
951 \defexercisestyle{problembysheet}%
952 {\exf@numberproblemwithin{\exf@sheetcounter}}
953 \defexercisestyle{equationbysheet}%
954 {\exf@numberequationwithin{\exf@sheetcounter}}

fracpoints Use vulgar fractions to display binary fractional points:


955 \defexercisestyle{fracpoints}%
956 {\exerciseconfig{composepointsnum}[1]{\protect\showfracpoints{##1}}}

twoside Use two-sided layout for sheets:


957 \defexercisestylearg[true]{twoside}{\exercisesetup{twoside={#1}}}

Extended Exercise Styles. Declare more specific styles:


958 \ifexf@extstyle

contents Add sheets and problems to table of contents:


959 \defexercisestyle{contents}{%
960 \exerciseconfig{toclevelsheet}{section}%
961 \exerciseconfig{toclevelproblem}{subsection}}

solutionsf Use sans serif font for solutions:


962 \defexercisestyle{solutionsf}{%
963 \exerciseconfigappend{styletextsolution}{\sffamily\let\itshape\slshape}}

solutiondimproblem Dim problem text if solutions are displayed:


964 \defexercisestyle{solutiondimproblem}{%
965 \RequirePackage{color}%
966 \exerciseconfigappend{styletextsolution}{\color[gray]{0}}%
967 \exerciseconfigappend{styletextproblem}{\color[gray]{0.2}}}

solutionsep Separate solutions by horizontal lines:


968 \defexercisestyle{solutionsep}{%
969 \exerciseconfig{insertsolutionsbefore}{\hrule\nopagebreak[3]\vspace{0.5ex}}%
970 \exerciseconfig{insertsolutionsafter}%
971 {\removelastskip\nopagebreak[3]\vspace{1.0ex}\hrule}}

plainheader Declare a simple sheet header with some configurable options; the configuration options
styleheader... define font styles, skipheaderbelow the space below the header and
composeheaderbelow... some auxiliary text to be displayed on the line below the header:
972 \defexercisestyle{plainheader}{%
973 \exerciseconfig{styleheadertitle}{\Large\bfseries}%
974 \exerciseconfig{styleheadercourse}{\sffamily}%
975 \exerciseconfig{styleheaderbelow}{\footnotesize}%
976 \exerciseconfig{skipheaderbelow}{3ex}%
977 \exerciseconfig{composeheaderbelowleft}{}%
978 \exerciseconfig{composeheaderbelowright}{}%
979 \exerciseconfig{composeheaderbelowcenter}{}%
980 \exerciseconfig{insertsheettitle}{\noindent%

51
981 \begin{minipage}{\textwidth}%
982 {\getexerciseconfig{styleheadertitle}%
983 \makebox[0pt][l]{\getexercisedata{course}}%
984 \hfill\makebox[0pt][r]{\getsheetdata{title}}\par}%
985 {\getexerciseconfig{styleheadercourse}%
986 \makebox[0pt][l]{\getexercisedata{institution}%
987 \exercisedataempty{period}{}{, \getexercisedata{period}}}%
988 \hfill\makebox[0pt][r]{\getexercisedata{instructor}}%
989 \vphantom{g}\par}%
990 \hrule%
991 {\def\tmp{}%
992 \exerciseconfigempty{composeheaderbelowleft}{}{\def\tmp{.}}%
993 \exerciseconfigempty{composeheaderbelowcenter}{}{\def\tmp{.}}%
994 \exerciseconfigempty{composeheaderbelowright}{}{\def\tmp{.}}%
995 \exerciseifnotempty{\tmp}%
996 {\getexerciseconfig{styleheaderbelow}\vphantom{\^A}%
997 \makebox[0pt][l]{\getexerciseconfig{composeheaderbelowleft}}%
998 \hfill\makebox[0pt][c]{\getexerciseconfig{composeheaderbelowcenter}}%
999 \hfill\makebox[0pt][r]{\getexerciseconfig{composeheaderbelowright}}%
1000 \vspace*{-\baselineskip}\vspace*{-\parskip}\par}}%
1001 \end{minipage}%
1002 \par\addvspace{\getexerciseconfig{skipheaderbelow}}}}

Done with extended styles:


1003 \fi

C.5 Metadata
Global Metadata Code.

\defexercisedata Declare global metadata field by defining a key key in category exf@data that stores the
chosen value in \exf@data@key:
1004 \newcommand{\defexercisedata}[1]{%
1005 \exf@csdo\def{exf@data@#1}{}%
1006 \define@key{exf@data}{#1}%
1007 {\exf@csdo\gdef{exf@data@#1}{##1}}}

\exercisedata Process key-value pairs:


1008 \newcommand{\exercisedata}[1]{\setkeys{exf@data}{#1}}

\getexercisedata Read global metadata:


1009 \newcommand{\getexercisedata}[1]{\csname exf@data@#1\endcsname}

\exercisedataempty Check whether the field is empty:


1010 \newcommand{\exercisedataempty}[3]{\exf@csdo\ifx{exf@data@#1}\exf@empty%
1011 #2\else#3\fi}

Global Metadata Declarations. Declare fields corresponding to standard pdf metadata:


1012 \defexercisedata{author}
1013 \defexercisedata{title}
1014 \defexercisedata{subject}
1015 \defexercisedata{keyword}

52
Declare additional general purpose fields:
1016 \defexercisedata{date}

Declare metadata related to courses:


1017 \defexercisedata{instructor}
1018 \defexercisedata{course}
1019 \defexercisedata{institution}
1020 \defexercisedata{period}
1021 \defexercisedata{material}

Overwrite standard definitions for author, title, date to also fill ordinary LATEX structures:
1022 \define@key{exf@data}{author}{\gdef\exf@data@author{#1}\author{#1}}
1023 \define@key{exf@data}{title}{\gdef\exf@data@title{#1}\title{#1}}
1024 \define@key{exf@data}{date}{\gdef\exf@data@date{#1}\date{#1}}

Sheet Metadata.

\defsheetdata Declare sheet metadata field by defining a key key in category exf@sheet that stores the
chosen value in \exf@data@sheet@key:
1025 \newcommand{\defsheetdata}[1]{%
1026 \exf@csdo\def{exf@data@sheet@#1}{}%
1027 \define@key{exf@sheet}{#1}%
1028 {\exf@csdo\def{exf@data@sheet@#1}{##1}}}

\setsheetdata Set sheet metadata:


1029 \newcommand{\setsheetdata}[1]{\setkeys{exf@sheet}{#1}}

\getsheetdata Read sheet metadata:


1030 \newcommand{\getsheetdata}[1]{\csname exf@data@sheet@#1\endcsname}

\sheetdataempty Check whether the field is empty:


1031 \newcommand{\sheetdataempty}[3]{\exf@csdo\ifx{exf@data@sheet@#1}\exf@empty%
1032 #2\else#3\fi}

Declare general purpose fields:


1033 \defsheetdata{due}
1034 \defsheetdata{handout}
1035 \defsheetdata{editdate}
1036 \defsheetdata{author}
1037 \defsheetdata{editor}

Special title processing:


1038 \def\exf@data@sheet@rawtitle{}
1039 \define@key{exf@sheet}{title}{\def\exf@data@sheet@rawtitle{#1}}
1040 \def\exf@data@sheet@title{\exf@config@composetitlesheet%
1041 {\csname the\exf@sheetcounter\endcsname}{\exf@data@sheet@rawtitle}}%

Special points processing:


1042 \def\exf@data@sheet@points{\ifdefined\exf@sheet@points%
1043 \expandafter\exf@config@composepointspairsheet\exf@sheet@points\fi}%

53
Problem Metadata.

\defproblemdata Declare problem metadata field by defining a key key in category exf@problem that stores
the chosen value in \exf@data@problem@key:
1044 \newcommand{\defproblemdata}[1]{%
1045 \exf@csdo\def{exf@data@problem@#1}{}%
1046 \define@key{exf@problem}{#1}%
1047 {\exf@csdo\def{exf@data@problem@#1}{##1}}}

\setproblemdata Set problem metadata:


1048 \newcommand{\setproblemdata}[1]{\setkeys{exf@problem,exf@scanproblem}{#1}}

\getproblemdata Read problem metadata:


1049 \newcommand{\getproblemdata}[1]{\csname exf@data@problem@#1\endcsname}

\problemdataempty Check whether the field is empty:


1050 \newcommand{\problemdataempty}[3]{\exf@csdo\ifx{exf@data@problem@#1}\exf@empty%
1051 #2\else#3\fi}

Special title processing:


1052 \def\exf@data@problem@rawtitle{}
1053 \define@key{exf@problem}{title}{\def\exf@data@problem@rawtitle{#1}}
1054 \def\exf@data@problem@title{\exf@config@composetitleproblem{%
1055 \csname the\exf@problemcounter\endcsname}{\exf@data@problem@rawtitle}}%

Problem Environment Code.

\exf@addmargin Define a length for environment margin:


1056 \newlength\exf@addmargin

\exf@section Write out problem opening line followed by some amount of skip (positive dimensions add
vertical space, negative dimensions add horizontal space); protected expand argument if
in horizontal mode (because it will be held until text is output and some definitions may
become invalid):
1057 \newcommand{\exf@section}[2]{\setlength\exf@tmpdim{#1}%
1058 \ifdim\exf@tmpdim<0pt%
1059 \protected@edef\exf@tmp{#2}%
1060 \else%
1061 \def\exf@tmp{#2}%
1062 \fi%
1063 \exf@exparg{\@startsection{}{}{0pt}{0pt}{#1}{}*}{\exf@tmp}}

\exf@init@block Clean info buffer, define amount of skip between items:


1064 \newcommand{\exf@init@block}[1]{%
1065 \def\exf@intro{}\def\exf@intro@skip{#1}%
1066 \exf@addmargin0pt\def\exf@introitem{}}

\exf@append@intro Append to info buffer:


1067 \newcommand{\exf@append@intro}[1]%
1068 {\exf@append@def\exf@intro{#1\hspace{\exf@intro@skip}}}

54
\exf@prepend@intro Prepend to info buffer:
1069 \newcommand{\exf@prepend@intro}[1]%
1070 {\exf@prepend@def\exf@intro{#1\hspace{\exf@intro@skip}}}

\exf@open@block Open environment, set margin, compose opening line:


1071 \newcommand{\exf@open@block}[1]{%
1072 \advance\leftskip\exf@addmargin%
1073 \advance\linewidth-\exf@addmargin%
1074 \advance\@totalleftmargin\exf@addmargin%
1075 \ifx\exf@intro\exf@empty%
1076 \exf@section{0pt}{\exf@introitem}%
1077 \else%
1078 \exf@section{#1}{\exf@introitem\exf@intro\unskip}%
1079 \fi}%

\exf@close@block Close environment, undo margin:


1080 \newcommand{\exf@close@block}{%
1081 \advance\leftskip-\exf@addmargin%
1082 \advance\linewidth\exf@addmargin%
1083 \advance\@totalleftmargin-\exf@addmargin}%

\addprobleminfo Interface to append or prepend to info buffer:


1084 \newcommand{\addprobleminfo}{\@ifstar\exf@prepend@intro\exf@append@intro}

\exf@addinfoswitch Add a switch for displaying problem info:


1085 \newcommand{\exf@addinfoswitch}[1]%
1086 {\define@boolkey{exf@infoswitch}[exf@showdata@]{#1}[true]{}}

\defprobleminfo Declare a problem info field, add corresponding info switch, process key-value pair if switch
activated:
1087 \newcommand{\defprobleminfo}[2]{%
1088 \exf@addinfoswitch{#1}%
1089 \exerciseconfig{compose@probleminfo@#1}[1]{#2}%
1090 \exf@exparg{\define@key{exf@probleminfo}{#1}}%
1091 {\csname ifexf@showdata@#1\endcsname\exf@append@intro{%
1092 \csname exf@config@compose@probleminfo@#1\endcsname{##1}}\fi}}

\showprobleminfo Process info switches, expand argument first:


1093 \newcommand{\showprobleminfo}[1]{\exf@expsetkeys{exf@infoswitch}{#1}}

Problem Info Declarations. Declare general purpose fields:


1094 \defprobleminfo{optional}{\emph{#1:}}
1095 \showprobleminfo{optional}
1096 \defprobleminfo{difficulty}{(#1)}

Declare fields for internal information (mostly):


1097 \defprobleminfo{comment}{#1}
1098 \defprobleminfo{author}{$\langle$#1$\rangle$}
1099 \defprobleminfo{editor}{$\{$#1$\}$}
1100 \defprobleminfo{source}{[#1]}
1101 \defprobleminfo{keyword}{\#(#1)}

55
Declare more specific fields:
1102 \ifexf@extdata
1103 \defprobleminfo{review}{#1}
1104 \defprobleminfo{recycle}{[[#1]]}
1105 \defprobleminfo{timesolve}{\{#1\}}
1106 \defprobleminfo{timepresent}{\{\!\{#1\}\!\}}
1107 \fi

Write Metadata to PDF Files.

\exf@writemetadata Write Metadata to PDF Files in case hyperref is available:


1108 \newcommand{\exf@writemetadata}{%
1109 \ifdefined\hypersetup%

Write author, title, subject and keywords:


1110 \ifx\exf@data@author\exf@empty\else%
1111 \hypersetup{pdfauthor={\exf@data@author}}\fi%
1112 \ifx\exf@data@title\exf@empty\else%
1113 \hypersetup{pdftitle={\exf@data@title}}\fi%
1114 \ifx\exf@data@subject\exf@empty\else%
1115 \hypersetup{pdfsubject={\exf@data@subject}}\fi%
1116 \ifx\exf@data@keyword\exf@empty\else%
1117 \hypersetup{pdfkeywords={\exf@data@keyword}}\fi%
1118 \fi}

Automatic writing at \begin{document}:


1119 \AtBeginDocument{\exf@ifis\exf@metadata{auto}%
1120 {\exf@writemetadata\gdef\exf@metadata{off}}}

\writeexercisedata Write metadata manually:


1121 \newcommand{\writeexercisedata}{\exf@ifis\exf@metadata{manual}%
1122 {\exf@writemetadata\gdef\exf@metadata{off}}}

C.6 Counters
sheet Define main counters (with customised names if necessary) and equation counters:
problem
1123 \newcounter{\exf@sheetcounter}
subproblem
1124 \newcounter{\exf@problemcounter}
solution 1125 \newcounter{\exf@subproblemcounter}[\exf@problemcounter]
1126 \newcounter{\exf@solutioncounter}[\exf@problemcounter]
1127 \newcount\exf@eqsav
1128 \newcounter{exf@sheetequation}
1129 \newcounter{exf@problemequation}
1130 \newcounter{exf@solutionequation}

Implement counter display; take care of corresponding hyperref labels:


1131 \exf@csdo\def{the\exf@sheetcounter}{\exf@config@countersheet}
1132 \exf@csdo\def{the\exf@problemcounter}{\exf@config@counterproblem}
1133 \exf@csdo\def{the\exf@subproblemcounter}{\exf@config@countersubproblem}
1134 \def\theexf@sheetequation{\exf@config@countersheetequation}
1135 \def\theHexf@sheetequation{sheet.\arabic{equation}}
1136 \def\theexf@problemequation{\exf@config@counterproblemequation}
1137 \def\theHexf@problemequation{prob.\arabic{equation}}

56
1138 \def\theexf@solutionequation{\exf@config@countersolutionequation}
1139 \def\theHexf@solutionequation{sol.\arabic{equation}}

@numberproblemwithin Declare problem counter as subcounter of #1:


1140 \newcommand{\exf@numberproblemwithin}[1]{%
1141 \@addtoreset{\exf@problemcounter}{#1}%
1142 \exf@csdo\def{the\exf@problemcounter}%
1143 {\csname the#1\endcsname.\exf@config@counterproblem}%
1144 \edef\exf@tmp{#1}%
1145 \ifx\exf@tmp\exf@sheetcounter%
1146 \exerciseconfig{tagproblem}{\ifdefined\sheettag\sheettag-\fi%
1147 \arabic{\exf@problemcounter}}%
1148 \else%
1149 \exerciseconfig{tagproblem}{\csname the#1\endcsname-%
1150 \arabic{\exf@problemcounter}}%
1151 \fi}

numberequationwithin Declare various new equation counters as subcounter of #1; take care of corresponding
hyperref labels:
1152 \newcommand{\exf@numberequationwithin}[1]{%
1153 \@addtoreset{exf@sheetequation}{#1}%
1154 \def\theexf@sheetequation%
1155 {\csname the#1\endcsname.\exf@config@countersheetequation}%
1156 \def\theHexf@sheetequation%
1157 {\csname theH#1\endcsname.sheet.\arabic{equation}}%
1158 \@addtoreset{exf@problemequation}{#1}%
1159 \def\theexf@problemequation%
1160 {\csname the#1\endcsname.\exf@config@counterproblemequation}%
1161 \def\theHexf@problemequation%
1162 {\csname theH#1\endcsname.prob.\arabic{equation}}%
1163 \@addtoreset{exf@solutionequation}{#1}%
1164 \def\theexf@solutionequation%
1165 {\csname the#1\endcsname.\exf@config@countersolutionequation}%
1166 \def\theHexf@solutionequation%
1167 {\csname theH#1\endcsname.sol.\arabic{equation}}}

C.7 Buffers
File Output.

\ifexf@solfile@open Conditional whether output files are presently in use:


1168 \newif\ifexf@solfile@open\exf@solfile@openfalse
1169 \newif\ifexf@probfile@open\exf@probfile@openfalse

\exf@solfile Reserve file handles:


1170 \newwrite\exf@solfile
1171 \newwrite\exf@probfile

\exf@writeline Write a line to the file:


1172 \newcommand{\exf@writeline}[2]{\immediate\write#1{#2}}

\exf@linesep Return a separator line:

57
1173 \newcommand{\exf@linesep}%
1174 {\@percentchar---------------------------------------}

\exf@lineno Return current position in source file; display line number and source file name (if available
via package currfile):
1175 \newcommand{\exf@lineno}{\@percentchar%
1176 \ifdefined\currfilename\currfilename\space\fi%
1177 l.\the\inputlineno}

\exf@start@solfile Open a new solution file #1.sol (do nothing if already open); indicate source, switch to
manual solution display mode:
1178 \newcommand{\exf@start@solfile}[1]{%
1179 \ifexf@solfile@open\else%
1180 \exercisestyle{solutionbelow=manual}%
1181 \global\exf@solfile@opentrue%
1182 \edef\exf@tmp{#1}%
1183 \immediate\openout\exf@solfile\exf@tmp\exf@config@extsolutions\relax%
1184 \exf@writeline\exf@solfile{\@percentchar%
1185 generated from file ‘\jobname’ by exframe.sty}%
1186 \ifexf@lineno\exf@writeline\exf@solfile{\exf@lineno}\fi%
1187 \exf@writeline\exf@solfile{}%
1188 \fi}

\exf@close@solfile Close solution file (if open); indicate position, close and reset variables:
1189 \newcommand{\exf@close@solfile}{%
1190 \ifexf@solfile@open%
1191 \ifexf@lineno\exf@writeline\exf@solfile{\exf@linesep}%
1192 \exf@writeline\exf@solfile{\exf@lineno}\fi%
1193 \exf@writeline\exf@solfile{\@backslashchar endinput}%
1194 \immediate\closeout\exf@solfile%
1195 \global\exf@solfile@openfalse%
1196 \fi}

\exf@start@probfile Open a new problem file #1.prb (do nothing if already open); indicate source, switch to
manual problem display mode:
1197 \newcommand{\exf@start@probfile}[1]{%
1198 \ifexf@probfile@open\else%
1199 \global\exf@probfile@opentrue%
1200 \edef\exf@tmp{#1}%
1201 \immediate\openout\exf@probfile\exf@tmp\exf@config@extproblems\relax%
1202 \exf@writeline\exf@probfile{\@percentchar%
1203 generated from file ‘\jobname’ by exframe.sty}%
1204 \ifexf@lineno\exf@writeline\exf@probfile{\exf@lineno}\fi%
1205 \exf@writeline\exf@probfile{}%
1206 \fi}

\exf@close@probfile Close problem file (if open); indicate position, close and reset variables:
1207 \newcommand{\exf@close@probfile}{%
1208 \ifexf@probfile@open%
1209 \ifexf@lineno\exf@writeline\exf@probfile{\exf@linesep}%
1210 \exf@writeline\exf@probfile{\exf@lineno}\fi%
1211 \exf@writeline\exf@probfile{\@backslashchar endinput}%
1212 \immediate\closeout\exf@probfile%
1213 \global\exf@probfile@openfalse%
1214 \fi}

58
Make sure to properly close files at the end:
1215 \AtEndDocument{\exf@close@solfile\exf@close@probfile}

Buffers.

\exf@solbuf Declare token buffers for storing problems and solutions and conditionals indicating whether
\exf@probbuf the buffers have been used:
\ifexf@solbuf@clean
1216 \newtoks\exf@solbuf
\ifexf@probbuf@clean
1217 \newtoks\exf@probbuf
1218 \newif\ifexf@solbuf@clean\exf@solbuf@cleantrue
1219 \newif\ifexf@probbuf@clean\exf@probbuf@cleantrue

\exf@clear@solbuf Clear a buffer and mark clean:


\exf@clear@probbuf
1220 \def\exf@clear@solbuf{\global\exf@solbuf@cleantrue\global\exf@solbuf={}}
1221 \def\exf@clear@probbuf{\global\exf@probbuf@cleantrue\global\exf@probbuf={}}

\exf@append@buf Append tokens to buffer:


1222 \def\exf@append@buf#1#2{\global#1=\expandafter{\the#1#2}}

\exf@addline Add a protected expanded line to the buffer:


1223 \def\exf@addline#1#2{{\protected@edef\exf@tmp{#2}%
1224 \exf@exparg{\exf@append@buf#1}{\exf@tmp^^J}}}

\exf@source@buf Source a buffer into the document:


1225 \def\exf@source@buf#1{\exf@exptwo\scantokens{\the#1}}

\exf@write@buf Write the buffer into the solution file:


1226 \def\exf@write@buf#1#2{\exf@writeline#1{\the#2}}

Verbatim Processing.

\exf@verbatim Start reading the buffer from the environment body:


1227 \newcommand{\exf@verbatim}{%
1228 \begingroup%
1229 \@bsphack%
1230 \let\do\@makeother\dospecials%
1231 \catcode‘\^^M\active%
1232 \def\verbatim@processline{\exf@exptwo\exf@verbatim@process%
1233 {\the\verbatim@line^^J}}%
1234 \verbatim@start}

\exf@endverbatim Stop reading the buffer:


1235 \newcommand{\exf@endverbatim}{\@esphack\endgroup}

\exf@scanblock Scan an optional argument from a verbatim environment; allow for an empty environment
and an empty first line; argument #1 is macro to be called eventually:
1236 \def\exf@scanblock#1{%

59
Check for empty first line:
1237 \@ifnextchar\par{\exf@scanblock@par{#1}}{\exf@scanblock@sel{#1}}}

Handle empty first line, implies no optional argument:


1238 \long\def\exf@scanblock@par#1\par{\exf@scanblock@sel{#1}[]}

Check for optional argument ([) and for environment ending (\end):
1239 \def\exf@scanblock@sel#1{\@ifnextchar[{\exf@scanblock@opt{#1}}%
1240 {\@ifnextchar\end{\exf@scanblock@end{#1}}{\exf@scanblock@noopt{#1}}}}

Handle empty environment, hopefully environment matches (otherwise?!):


1241 \def\exf@scanblock@end#1\end#2{%
1242 \def\exf@tmp{#2}\ifx\exf@tmp\@currenvir%
1243 \def\exf@verbatim{}\def\exf@endverbatim{}%
1244 \fi%
1245 #1{}{\scantokens{\end{#2}}}}

Pass on without and with optional argument; pass on optional argument and any token
scanned prematurely:
1246 \def\exf@scanblock@noopt#1#2{#1{}{\scantokens#2}}
1247 \def\exf@scanblock@opt#1[#2]{#1{#2}{}}

C.8 Points
Points Arithmetic.

\exf@addtopoints Add points #2+#3 to macro #1 using metric register:


1248 \newcommand{\exf@addtopoints}[3]{%
1249 \ifdefined#1\else\def#1{{0}{0}}\fi%
1250 \setlength\exf@tmpdim{\expandafter\@firstoftwo#1pt}%
1251 \addtolength\exf@tmpdim{#2pt}%
1252 \edef\exf@tmp{\strip@pt\exf@tmpdim}%
1253 \setlength\exf@tmpdim{\expandafter\@secondoftwo#1pt}%
1254 \addtolength\exf@tmpdim{#3pt}%
1255 \xdef#1{{\exf@tmp}{\strip@pt\exf@tmpdim}}}

\exf@pointsmismatch Execute #3 if points disagree:


1256 \newcommand{\exf@pointsmismatch}[3]{%
1257 \let\exf@tmp\@undefined%
1258 \ifdim\expandafter\@firstoftwo#1pt=\expandafter\@firstoftwo#2pt\else%
1259 \def\exf@tmp{}\fi%
1260 \ifdim\expandafter\@secondoftwo#1pt=\expandafter\@secondoftwo#2pt\else%
1261 \def\exf@tmp{}\fi%
1262 \ifdefined\exf@tmp#3\fi}

Points Expansion.

\exf@outpoints If points macro #3 is set, expand #3, pass on as #1{\protect#2}#3 and clear #3 globally:
1263 \def\exf@outpoints#1#2#3{\ifdefined#3%
1264 \exf@exptwo\exf@outpoints@switch{#3}{#1}{#2}%
1265 \global\let#3\@undefined\fi}
1266 \def\exf@outpoints@switch#1#2#3{#2{\protect#3#1}}

60
\exf@scanpoints Call as \exf@scanpoints#1[regular ][+bonus]++@ to write {regular }{bonus} into #1; fill with
0 if empty:
1267 \def\exf@scanpoints#1#2+#3+#4@{%
1268 \edef#1{\if @#2@0\else#2\fi}%
1269 \edef#1{{#1}{\if @#3@0\else#3\fi}}}

\exf@formatpoints Format as [#1][+#2]; remove 0 components:


1270 \def\exf@formatpoints#1#2{\ifdim#2pt=0pt#1\else%
1271 \ifdim#1pt=0pt+#2\else#1+#2\fi\fi}

\extractpoints Extract main (plain) or bonus (starred) part from saved points register:
1272 \newcommand{\extractpoints}{\@ifstar{\exf@extractpoints\@secondoftwo}%
1273 {\exf@extractpoints\@firstoftwo}}
1274 \newcommand{\exf@extractpoints}[2]{\edef\exf@tmp{#2}%
1275 \exf@exptwo\exf@scanpoints\exf@tmp\exf@tmp++@%
1276 \expandafter#1\exf@tmp}

\switchpoints Extract main (plain) and bonus (starred) part from points, and execute one of three:
1277 \newcommand{\switchpoints}[5]{\edef\exf@tmp{#5}%
1278 \exf@exptwo\exf@scanpoints\exf@tmp\exf@tmp++@%
1279 \expandafter\exf@switchpoints\exf@tmp{#1}{#2}{#3}{#4}}
1280 \newcommand{\exf@switchpoints}[6]{%
1281 \ifdim#2pt=0pt\ifdim#1pt=0pt\def\exf@tmp##1##2{#6}%
1282 \else\def\exf@tmp##1##2{#3}\fi%
1283 \else\ifdim#1pt=0pt\def\exf@tmp##1##2{#4}%
1284 \else\def\exf@tmp##1##2{#5}\fi\fi\exf@tmp{#1}{#2}}

Tools.

exf@makepointsmargin Combination to typeset points in margin:


1285 \newcommand{\exf@makepointsmargin}[2]{%
1286 \exf@config@insertpointsmargin{\exf@config@composepointspairmargin{#1}{#2}}}

\exf@warnmismatch If points #3 and #4 are defined and disagree, issue a warning message:
1287 \newcommand{\exf@warnmismatch}[4]{%
1288 \ifdefined#4\ifdefined#3\exf@pointsmismatch#3#4{%
1289 \let\exf@tmp\PackageWarning%
1290 \ifx#1\exf@solutionname\let\exf@tmp\PackageWarningNoLine\fi%
1291 \exf@tmp{exframe}{points mismatch %
1292 (\expandafter\exf@formatpoints#3 determined %
1293 vs. \expandafter\exf@formatpoints#4 given) %
1294 for #1 \csname the#2\endcsname}%
1295 \ifexf@warntext\edef\exf@tmp{%
1296 {\expandafter\exf@formatpoints#3}{\expandafter\exf@formatpoints#4}}%
1297 \exf@exptwo\exf@config@insertwarnpoints#1\exf@tmp\fi}%
1298 \fi\fi}

\exf@warnrerun If points #3 and #4 are defined and disagree, issue advice to recompile:
1299 \newcommand{\exf@warnrerun}[4]{%
1300 \ifdefined#4\ifdefined#3\exf@pointsmismatch#3#4{%
1301 \PackageWarning{exframe}{points changed %
1302 for #1 \csname the#2\endcsname; rerun to fix}%

61
1303 \ifexf@warntext\exf@config@insertwarnpointsrerun#1\fi}%
1304 \fi\fi}

Binary Rational Numbers.

\exf@splitsign Split a decimal float number into sign, integer and fractional part:
\exf@splitdecimal
1305 \def\exf@splitsign#1-#2-#3&{\def\exf@splitnum{#1#2}\def\exf@splitminus{#3}}
1306 \def\exf@splitdecimal#1.#2.#3&{\def\exf@splitint{#1}\def\exf@splitdec{#2}}

\showfracpoints Display a float number as a fraction with denominators 2, 4 or 8 when possible; first split
number, complete missing zeros and handle cases:
1307 \newcommand{\showfracpoints}[1]{%
1308 \edef\exf@tmp{#1}%
1309 \expandafter\exf@splitsign\exf@tmp--&%
1310 \expandafter\exf@splitdecimal\exf@splitnum..&%
1311 \if @\exf@splitint @\def\exf@splitint{0}\fi%
1312 \if @\exf@splitdec @\def\exf@splitdec{0}\fi%
1313 \def\exf@tmp{\exf@splitint.\exf@splitdec}%
1314 \ifnum\exf@splitdec=0\def\exf@tmp{\exf@splitint}\fi%
1315 \ifnum\exf@splitdec=5\def\exf@tmp{\exf@config@frac{\exf@splitint}{1}{2}}\fi%
1316 \ifnum\exf@splitdec=25\def\exf@tmp{\exf@config@frac{\exf@splitint}{1}{4}}\fi%
1317 \ifnum\exf@splitdec=75\def\exf@tmp{\exf@config@frac{\exf@splitint}{3}{4}}\fi%
1318 \ifnum\exf@splitdec=125\def\exf@tmp{\exf@config@frac{\exf@splitint}{1}{8}}\fi%
1319 \ifnum\exf@splitdec=375\def\exf@tmp{\exf@config@frac{\exf@splitint}{3}{8}}\fi%
1320 \ifnum\exf@splitdec=625\def\exf@tmp{\exf@config@frac{\exf@splitint}{5}{8}}\fi%
1321 \ifnum\exf@splitdec=875\def\exf@tmp{\exf@config@frac{\exf@splitint}{7}{8}}\fi%
1322 \ifx\exf@splitminus\exf@empty\else$\exf@splitminus$\fi\exf@tmp%
1323 }

\exf@config@frac Display a vulgar fraction such as 123/4 :


1324 \newcommand{\exf@config@frac}[3]{%
1325 \ifnum#1=0\relax\else#1\fi%
1326 \ifnum#2=0\relax\else$%
1327 ^{\exf@text{#2}}%
1328 \mskip-4mu/\mskip-2mu%
1329 _{\exf@text{#3}}$\fi}

Sheet Points Code.

notedata@sheetpoints Store a sheet point number in a macro:


1330 \newcommand{\exf@notedata@sheetpoints}[2]{%
1331 \exf@csdo\gdef{exf@sheetpoints@#1}{#2}}

exf@writesheetpoints Write sheet points to the .aux file:


1332 \newcommand{\exf@writesheetpoints}[2]%
1333 {\exf@writedata{sheetpoints}{\sheettag}{\exf@formatpoints{#1}{#2}}}

\getsheetpoints Read points for current sheet or from .aux file:


1334 \newcommand{\getsheetpoints}[1]{\if @#1@%
1335 \ifdefined\exf@sheet@points%
1336 \expandafter\exf@formatpoints\exf@sheet@points\else 0\fi%
1337 \else\exf@csor{exf@sheetpoints@#1}{0}\fi}

62
Problem Points Code.

tedata@problempoints Store a problem point number in a macro:


1338 \newcommand{\exf@notedata@problempoints}[2]{%
1339 \exf@csdo\gdef{exf@problempoints@#1}{#2}}

f@writeproblempoints Write problem points to the .aux file:


1340 \newcommand{\exf@writeproblempoints}[2]%
1341 {\exf@writedata{problempoints}{\problemtag}{\exf@formatpoints{#1}{#2}}}

\getproblempoints Read points for current problem or from .aux file:


1342 \newcommand{\getproblempoints}[1]{\if @#1@%
1343 \ifdefined\exf@problem@points%
1344 \expandafter\exf@formatpoints\exf@problem@points\else 0\fi%
1345 \else\exf@csor{exf@problempoints@#1}{0}\fi}

\showpoints Show points within a problem or subproblem:


1346 \newcommand{\showpoints}{%
1347 \ifdefined\exf@in@solution\exf@outpoints{\exf@ensuretext}%
1348 {\exf@config@composepointspairbodysolution}{\exf@solution@points@show}%
1349 \else\ifdefined\exf@in@subproblem\exf@outpoints{\exf@ensuretext}%
1350 {\exf@config@composepointspairbodysubproblem}{\exf@subproblem@points@show}%
1351 \else\ifdefined\exf@in@problem\exf@outpoints{\exf@ensuretext}%
1352 {\exf@config@composepointspairbodyproblem}{\exf@problem@points@show}%
1353 \fi\fi\fi}

Subproblem Points Code.

ata@subproblempoints Store a subproblem point number in a macro:


1354 \newcommand{\exf@notedata@subproblempoints}[2]{%
1355 \exf@csdo\gdef{exf@subproblempoints@#1}{#2}}

ritesubproblempoints Write subproblem points to the .aux file:


1356 \newcommand{\exf@writesubproblempoints}[2]%
1357 {\exf@writedata{subproblempoints}%
1358 {\subproblemtag}{\exf@formatpoints{#1}{#2}}}

\getsubproblempoints Read points for current subproblem:


1359 \newcommand{\getsubproblempoints}[1]{\if @#1@%
1360 \ifdefined\exf@subproblem@points%
1361 \expandafter\exf@formatpoints\exf@subproblem@points\else 0\fi%
1362 \else\exf@csor{exf@subproblempoints@#1}{0}\fi}

Solution Points Code.

\exf@awardpointsalt Award points for alternative or optional solution; does not count towards solution total:
1363 \newcommand{\exf@awardpointsalt}[2][]{\exf@scanpoints\exf@tmp#2++@%
1364 \exf@exptwo\exf@ensuretext{%
1365 \expandafter\exf@config@composepointspairawardalt\exf@tmp{#1}}}

63
\exf@awardpointsreg Award points for regular solution; counts towards solution total:
1366 \newcommand{\exf@awardpointsreg}[2][]{\exf@scanpoints\exf@tmp#2++@%
1367 \exf@exptwo\exf@addtopoints\exf@solution@points@total\exf@tmp%
1368 \exf@scanpoints\exf@tmp#2++@%
1369 \exf@exptwo\exf@ensuretext{%
1370 \expandafter\exf@config@composepointspairaward\exf@tmp{#1}}}

\awardpoints Award points within solution with optional starred form:


1371 \newcommand{\awardpoints}{\@ifstar\exf@awardpointsalt\exf@awardpointsreg}

\getsolutionpoints Read points for current solution:


1372 \newcommand{\getsolutionpoints}[1]{\if @#1@%
1373 \ifdefined\exf@solution@points%
1374 \expandafter\exf@formatpoints\exf@solution@points\else 0\fi%
1375 \else 0\fi}

C.9 Tag Lists


Loop Lists.

exerciseloop Counters for item number within list and depth of loop nesting:
exf@loopdepth
1376 \newcounter{exerciseloop}
1377 \newcounter{exf@loopdepth}

exf@listwalk Step through a list; call the callback function #1 with current item #2:
1378 \def\exf@listwalk#1#2{\if @#2@\def\exf@tmp{}\else%
1379 \def\exf@tmp{#1{#2}\exf@listwalk#1}\fi\exf@tmp}

\exerciseloop Loop through a list of items in braces #1 which is expanded first; store code #2 to be executed
in a callback function (need to use different callback function for each loop depth, callback
function must be global to work within table cells); initialise item counter:
1380 \newcommand{\exerciseloop}[2]{\addtocounter{exf@loopdepth}{1}%
1381 \setcounter{exerciseloop}{0}%
1382 \exf@csdo\gdef{exf@listcallback@\roman{exf@loopdepth}}##1%
1383 {\stepcounter{exerciseloop}#2}%
1384 \edef\exf@tmp{#1}%
1385 \exf@csdotwo\exf@exptwo\exf@listwalk%
1386 {exf@listcallback@\roman{exf@loopdepth}}\exf@tmp{}%
1387 \addtocounter{exf@loopdepth}{-1}}

\exerciseloopstr Loop through list and save result to \exerciseloopret (or optional argument #1):
1388 \newcommand{\exerciseloopstr}[3][\exerciseloopret]{%
1389 \def#1{}\exerciseloop{#2}{\protected@edef#1{#1#3}}}

Lists Management.

\exf@notedata@sheet Store a sheet tag:


1390 \def\exf@sheetlist{}
1391 \newcommand{\exf@notedata@sheet}[2]{%
1392 \xdef\exf@sheetlist{\exf@sheetlist{#1}}}

64
exf@notedata@problem Store a problem tag:
1393 \def\exf@problemlist{}
1394 \newcommand{\exf@notedata@problem}[2]{%
1395 \xdef\exf@problemlist{\exf@problemlist{#1}}%
1396 \if @#2@\else%
1397 \ifcsname exf@problemlist@#2\endcsname\else%
1398 \exf@csdo\gdef{exf@problemlist@#2}{}\fi%
1399 \exf@csdo\xdef{exf@problemlist@#2}%
1400 {\csname exf@problemlist@#2\endcsname{#1}}%
1401 \fi}

@notedata@subproblem Store a subproblem tag:


1402 \newcommand{\exf@notedata@subproblem}[2]{%
1403 \ifcsname exf@subproblemlist@#2\endcsname\else%
1404 \exf@csdo\gdef{exf@subproblemlist@#2}{}\fi%
1405 \exf@csdo\xdef{exf@subproblemlist@#2}%
1406 {\csname exf@subproblemlist@#2\endcsname{#1}}}

\getsheetlist Get list of sheet tags, problem tags (all, within current or particular sheet), subproblem tags
\getproblemlist (within current or particular problem):
\getsubproblemlist
1407 \newcommand{\getsheetlist}[1]{\exf@sheetlist}
1408 \newcommand{\getproblemlist}[1]{\if @#1@%
1409 \ifdefined\sheettag\exf@csor{exf@problemlist@\sheettag}{}%
1410 \else\exf@problemlist\fi%
1411 \else%
1412 \if *#1\exf@problemlist\else\exf@csor{exf@problemlist@#1}{}\fi%
1413 \fi}
1414 \newcommand{\getsubproblemlist}[1]{\if @#1@%
1415 \exf@csor{exf@subproblemlist@\problemtag}{}\else%
1416 \exf@csor{exf@subproblemlist@#1}{}\fi}

C.10 Sheet Environment


exf@sheet Define options for sheet environment:
1417 \define@key{exf@sheet}{points}{\exf@scanpoints\exf@sheet@points#1++@}
1418 \define@key{exf@sheet}{number}{\setcounter{\exf@sheetcounter}{#1}%
1419 \addtocounter{\exf@sheetcounter}{-1}\refstepcounter{\exf@sheetcounter}}
1420 \define@key{exf@sheet}{label}{\def\exf@label{#1}}
1421 \define@key{exf@sheet}{tag}{\def\sheettag{#1}}

sheet Define sheet environment (potentially using custom name):


1422 \newenvironment{\exf@sheetname}[1][]{%

Insert hook code to clear page, step counter:


1423 \exf@config@insertsheetclearpage%
1424 \refstepcounter{\exf@sheetcounter}%

Use equation counter for sheets:


1425 \ifexf@style@sheetequation%
1426 \exf@eqsav\value{equation}\relax%
1427 \setcounter{equation}{\value{exf@sheetequation}}%
1428 \let\theequation\theexf@sheetequation%
1429 \let\theHequation\theHexf@sheetequation%
1430 \fi%

65
Reset optional arguments, process arguments:
1431 \let\exf@sheet@points\@undefined%
1432 \def\sheettag{\getexerciseconfig{tagsheet}}%
1433 \let\exf@sheet@points@total\@undefined%
1434 \let\exf@label\@undefined%
1435 \setkeys{exf@sheet}{#1}%

Process automatic and manual labels:


1436 \ifexf@autolabelsheet\label{\exf@config@labelsheet{\sheettag}}\fi%
1437 \ifdefined\exf@label\label{\exf@label}\fi%
1438 \exf@writedata{sheet}{\sheettag}{}%

Set points from explicit input or from .aux storage:


1439 \ifdefined\exf@sheet@points%
1440 \let\exf@sheet@points@given\exf@empty%
1441 \else%
1442 \let\exf@sheet@points@given\@undefined%
1443 \ifcsname exf@sheetpoints@\sheettag\endcsname%
1444 \exf@csdotwo\let\exf@tmp{exf@sheetpoints@\sheettag}%
1445 \exf@exptwo\exf@scanpoints\exf@sheet@points\exf@tmp++@%
1446 \fi\fi%

Process metadata:
1447 \exf@ifis\exf@metadata{sheet}{{%
1448 \ifx\exf@data@sheet@author\exf@empty\else%
1449 \let\exf@data@author\exf@data@sheet@author\fi%
1450 \def\exf@data@title{\exf@config@composemetasheet%
1451 {\csname the\exf@sheetcounter\endcsname}{\exf@data@sheet@rawtitle}}%
1452 \exf@writemetadata}\gdef\exf@metadata{off}}%

Insert hook code:


1453 \exf@config@insertsheetbefore%

Add table of contents line:


1454 \ifx\exf@config@toclevelsheet\exf@empty\else%
1455 \ifdefined\phantomsection\phantomsection\fi\fi%
1456 \exf@addcontentsline{\exf@config@toclevelsheet}%
1457 {\exf@config@composetocsheet{\csname the\exf@sheetcounter\endcsname}%
1458 {\exf@data@sheet@rawtitle}}%

Write sheet title:


1459 \exf@config@insertsheettitle}%

End of environment; perform sanity check on total points if given explicitly:


1460 {\ifdefined\exf@sheet@points@given%
1461 \exf@warnmismatch{\exf@sheetname}{\exf@sheetcounter}%
1462 {\exf@sheet@points@total}{\exf@sheet@points}%

Test whether points have changed since last compile:


1463 \else%
1464 \exf@warnrerun{\exf@sheetname}{\exf@sheetcounter}%
1465 {\exf@sheet@points@total}{\exf@sheet@points}%

Store points:

66
1466 \let\exf@sheet@points\exf@sheet@points@total%
1467 \fi%

Write sheet points to .aux file:


1468 \ifdefined\exf@sheet@points%
1469 \expandafter\exf@writesheetpoints\exf@sheet@points%
1470 \fi%

Insert solutions:
1471 \exf@ifis\exf@solutionbelow{sheet}{\insertsolutions}%

Insert hook code:


1472 \exf@config@insertsheetafter%
1473 \exf@config@insertsheetclearpage%

Restore original equation counter:


1474 \ifexf@style@sheetequation%
1475 \setcounter{exf@sheetequation}{\value{equation}}%
1476 \setcounter{equation}{\exf@eqsav}%
1477 \fi%

Done:
1478 \ignorespacesafterend}

rcisecleardoublepage Clear the current page, clear even page with a totally empty page:
1479 \newcommand{\exercisecleardoublepage}{%
1480 \clearpage\ifexf@twoside\ifodd\value{page}\else%
1481 \thispagestyle{empty}\hbox{}\newpage\fi\fi}

C.11 Problem Environment


Print Problems.

exf@problem Define options for problem environment:


1482 \define@key{exf@problem}{points}{\exf@scanpoints\exf@problem@points#1++@}
1483 \define@key{exf@problem}{label}{\def\exf@label{#1}}
1484 \define@key{exf@problem}{tag}{\def\problemtag{#1}}
1485 \define@key{exf@problem}{sollabel}{\xdef\exf@sollabel{#1}}

printproblem Define printproblem environment:


1486 \newenvironment{printproblem}[1]{%

Start with new paragraph, set text style, add vspace:


1487 \par\exf@config@styletext\addvspace{\exf@config@skipproblemabove}%

Step problem counter:


1488 \refstepcounter{\exf@problemcounter}%

Insert hook code:


1489 \exf@config@insertproblembefore%

67
Begin inner group, mark in problem:
1490 \begingroup%
1491 \def\exf@in@problem{}%

Use equation counter for problems:


1492 \ifexf@style@problemequation%
1493 \exf@eqsav\value{equation}\relax%
1494 \setcounter{equation}{\value{exf@problemequation}}%
1495 \let\theequation\theexf@problemequation%
1496 \let\theHequation\theHexf@problemequation%
1497 \fi%

Initialise variables, process arguments:


1498 \exf@init@block{\exf@config@skipprobleminfo}%
1499 \def\problemtag{\getexerciseconfig{tagproblem}}%
1500 \let\exf@problem@points\@undefined%
1501 \let\exf@label\@undefined%
1502 \global\let\exf@sollabel\@undefined%
1503 \let\exf@problem@points@total\@undefined%
1504 \setkeys{exf@problem,exf@probleminfo,exf@scanproblem}{#1}%

Process automatic and manual labels:


1505 \ifexf@autolabelproblem\label{\exf@config@labelproblem{\problemtag}}\fi%
1506 \ifdefined\exf@label\label{\exf@label}\fi%
1507 \exf@writedata{problem}{\problemtag}{\ifdefined\sheettag\sheettag\fi}%

Mark for new solution section; remember problem counter, title:


1508 \gdef\exf@problem@solnewsec{}%
1509 \xdef\exf@prevprob{\csname the\exf@problemcounter\endcsname}%
1510 \ifcsname theH\exf@problemcounter\endcsname%
1511 \xdef\exf@prevprobhref{\exf@problemcounter.%
1512 \csname theH\exf@problemcounter\endcsname}%
1513 \fi%
1514 \ifx\exf@data@problem@rawtitle\exf@empty%
1515 \global\let\exf@prevprobtitle\@undefined%
1516 \else%
1517 \protected@xdef\exf@prevprobtitle{\exf@data@problem@rawtitle}%
1518 \fi%
1519 \global\let\exf@prevsubprob\@undefined%
1520 \global\let\exf@prevsubprobhref\@undefined%

Set points from explicit input or from .aux storage:


1521 \ifdefined\exf@problem@points%
1522 \let\exf@problem@points@given\exf@empty%
1523 \else%
1524 \let\exf@problem@points@given\@undefined%
1525 \ifcsname exf@problempoints@\problemtag\endcsname%
1526 \exf@csdotwo\let\exf@tmp{exf@problempoints@\problemtag}%
1527 \exf@exptwo\exf@scanpoints\exf@problem@points\exf@tmp++@%
1528 \fi\fi%
1529 \global\let\exf@prevpoints\exf@problem@points%
1530 \let\exf@problem@points@show\@undefined%
1531 \ifdefined\exf@problem@points%
1532 \let\exf@problem@points@show\exf@problem@points%
1533 \fi%

68
Disable points display if desired:
1534 \exf@ifis\exf@pointsat{off}{\let\exf@problem@points@show\@undefined}%

Display points in opening line if desired; expand points into argument and remove points:
1535 \exf@ifis\exf@pointsat{start}{\exf@outpoints{\exf@append@intro}%
1536 {\exf@config@composepointspairstartproblem}{\exf@problem@points@show}}%
1537 \exf@ifis\exf@pointsat{start*}{\exf@outpoints{\exf@prepend@intro}%
1538 {\exf@config@composepointspairstartproblem}{\exf@problem@points@show}}%

Insert hook code, set problem body style:


1539 \exf@config@insertprobleminfo%
1540 \exf@config@styletextproblem%

Write title without item:


1541 \ifdim\exf@config@skipproblemitem=0pt%
1542 \exf@prepend@intro{{%
1543 \exf@config@styletitle\exf@config@styletitleproblem%
1544 \exf@config@composetitleproblem{\csname the\exf@problemcounter\endcsname}%
1545 {\exf@data@problem@rawtitle}}}%

Write item with fixed total width or item width plus space:
1546 \else%
1547 \ifdim\exf@config@skipproblemitem>0pt%
1548 \setlength\exf@addmargin{\exf@config@skipproblemitem}%
1549 \else%
1550 \settowidth\exf@addmargin{%
1551 \exf@config@styletitle\exf@config@styletitleproblem%
1552 \exf@config@composeitemproblem{\exf@config@counterproblemmax}%
1553 \exf@config@composeitemproblemsep}%
1554 \fi%

Define item label:


1555 \def\exf@introitem{\makebox[0cm][r]{%
1556 \exf@config@styletitle\exf@config@styletitleproblem%
1557 \exf@config@composeitemproblem{\csname the\exf@problemcounter\endcsname}%
1558 \exf@config@composeitemproblemsep}}%

Compose title:
1559 \ifx\exf@data@problem@rawtitle\exf@empty\else%
1560 \exf@prepend@intro{{%
1561 \exf@config@styletitle\exf@config@styletitleproblem%
1562 \exf@config@composetitleproblem{\exf@empty}{\exf@data@problem@rawtitle}}}%
1563 \fi%
1564 \fi%

Write points into margin if desired; expand points into argument and remove points:
1565 \exf@ifis\exf@pointsat{margin}{%
1566 \exf@outpoints{\exf@prepend@def\exf@introitem}%
1567 {\exf@makepointsmargin}{\exf@problem@points@show}}%

Write out opening line:


1568 \exf@open@block{\exf@config@skipproblemtitle}%

Add table of contents line:

69
1569 \exf@addcontentsline{\exf@config@toclevelproblem}%
1570 {\exf@config@composetocproblem{\csname the\exf@problemcounter\endcsname}%
1571 {\exf@data@problem@rawtitle}}%

Done:
1572 \@afterindentfalse}%

End environment, show points if desired:


1573 {\exf@ifis\exf@pointsat{end}{\showpoints}%

Perform sanity checks on total points if given explicitly:


1574 \ifdefined\exf@problem@points@given%
1575 \exf@warnmismatch{\exf@problemname}{\exf@problemcounter}%
1576 {\exf@problem@points@total}{\exf@problem@points}%

Warn if calculated total points have changed:


1577 \else%
1578 \exf@warnrerun{\exf@problemname}{\exf@problemcounter}%
1579 {\exf@problem@points@total}{\exf@problem@points}%

Read computed total points:


1580 \let\exf@problem@points\exf@problem@points@total%
1581 \fi%

Write points to .aux file; add to sheet total:


1582 \ifdefined\exf@problem@points%
1583 \expandafter\exf@writeproblempoints\exf@problem@points%
1584 \exf@exptwo\exf@addtopoints\exf@sheet@points@total\exf@problem@points%

Warn if no points given for present problem but previously:


1585 \else\ifdefined\exf@sheet@points@total%
1586 \PackageWarning{exframe}{no points defined for \exf@problemname}%
1587 \fi\fi%

Solutions to subproblems must be declared within problem environment:


1588 \global\let\exf@prevsubprob\@undefined%
1589 \global\let\exf@prevsubprobhref\@undefined%

End paragraph and environment:


1590 \par\exf@close@block%

Display solution if desired:


1591 \exf@ifis\exf@solutionbelow{problem}{%
1592 \exf@config@insertproblemsolution%
1593 \exf@showsolutions{\exf@config@composetitlesolutionmulti}{}}%

Restore original equation counter:


1594 \ifexf@style@problemequation%
1595 \setcounter{exf@problemequation}{\value{equation}}%
1596 \setcounter{equation}{\exf@eqsav}%
1597 \fi%

End inner group:


1598 \endgroup%

70
Insert hook code, vertical skip:
1599 \exf@config@insertproblemafter%
1600 \addvspace{\exf@config@skipproblembelow}%

Display solution if desired:


1601 \exf@ifis\exf@solutionbelow{problem*}{%
1602 \exf@showsolutions{\exf@config@composetitlesolutionmulti}{}}%

Done:
1603 \ignorespacesafterend}

Read Problem Environment.

exf@scanproblem Define options for problem environment:


1604 \define@boolkey{exf@scanproblem}[exf@scanproblem@]{disable}[true]{}

exf@problem@direct Define direct output version of problem environment; pass on to printproblem environment:
1605 \newenvironment{exf@problem@direct}[1][]%
1606 {\printproblem{#1}}{\endprintproblem\ignorespacesafterend}

exf@problem@scan Define scan version of problem environment; use \exf@scanblock to properly parse optional
exf@scanproblem argument and pass on to exf@scanproblem:
1607 \newenvironment{exf@problem@scan}%
1608 {\exf@scanblock{\exf@scanproblem}}{\endexf@scanproblem}%
1609 \newenvironment{exf@scanproblem}[2]{%

Determine problem display:


1610 \exf@scanproblem@disablefalse%
1611 \setkeys*{exf@scanproblem}{#1}%
1612 \exf@config@insertproblemselect{#1}%

Write separator and printproblem environment to buffer:


1613 \ifexf@scanproblem@disable%
1614 \def\exf@verbatim@process{\@gobble}%
1615 \else%
1616 \ifexf@lineno\exf@addline\exf@probbuf{\exf@linesep}%
1617 \exf@addline\exf@probbuf{\exf@lineno}\fi%
1618 \exf@addline\exf@probbuf%
1619 {\@backslashchar begin{printproblem}{#1}}%
1620 \def\exf@verbatim@process{\exf@append@buf\exf@probbuf}%
1621 \fi%

Start verbatim processing:


1622 \exf@verbatim#2}%

End verbatim processing; close printproblem environment:


1623 {\exf@endverbatim%
1624 \ifexf@scanproblem@disable\else%
1625 \exf@addline\exf@probbuf{\@backslashchar end{printproblem}}%
1626 \global\exf@probbuf@cleanfalse%
1627 \fi%

71
Write buffer to file if output file open:
1628 \ifexf@probfile@open%
1629 \exf@write@buf\exf@probfile\exf@probbuf%
1630 \exf@clear@probbuf%
1631 \fi%

Output buffer immediately:


1632 \ifexf@problemmanual\else%
1633 \exf@source@buf\exf@probbuf%
1634 \exf@clear@probbuf%
1635 \fi%

Done:
1636 \ignorespacesafterend}

problem Define problem environment (potentially using custom name) to choose between direct and
buffered version:
1637 \newenvironment{\exf@problemname}%
1638 {\ifexf@problembuf\let\exf@tmp\exf@problem@scan%
1639 \else\let\exf@tmp\exf@problem@direct\fi%
1640 \exf@tmp}%
1641 {\ifexf@problembuf\let\exf@tmp\endexf@problem@scan%
1642 \else\let\exf@tmp\endexf@problem@direct\fi%
1643 \exf@tmp}

C.12 Problem Blocks


Problem Block Handling.

\exf@problemstitle Compose the title for a problem block section:


1644 \newcommand{\exf@problemstitle}{%

Check whether title is empty:


1645 \protected@edef\exf@problemstitleexp{\exf@config@composetitleproblems}%
1646 \ifx\exf@problemstitleexp\exf@empty\else%

Output section line:


1647 \exf@section{\exf@config@skipproblemstitle}%
1648 {\exf@config@styletitle\exf@config@styletitleproblems%
1649 \exf@problemstitleexp}%
1650 \exf@addcontentsline{\exf@config@toclevelproblems}%
1651 {\exf@config@composetocproblems}%
1652 \fi}

\exf@showproblemsin Output problem block intro:


1653 \newcommand{\exf@showproblemsin}{%

Set problem body style; add vertical space; insert hook code:
1654 \par\exf@config@styletext\addvspace{\exf@config@skipproblemsabove}%
1655 \exf@config@insertproblemsbefore}

\exf@showproblemsout Output problem block outro:


1656 \newcommand{\exf@showproblemsout}{%

72
Insert hook code; close paragraph; add vertical space:
1657 \exf@config@insertproblemsafter%
1658 \par\exf@config@styletext\addvspace{\exf@config@skipproblemsbelow}}

\exf@showproblems Output problem block in buffer:


1659 \newcommand{\exf@showproblems}{%

Do nothing if buffer is empty (avoid titles):


1660 \ifexf@probbuf@clean\else\begingroup%

Execute output problem block intro:


1661 \exf@showproblemsin%
1662 \exf@problemstitle%

Source and clear buffer:


1663 \exf@source@buf\exf@probbuf%
1664 \exf@clear@probbuf%

Execute output problem block outro:


1665 \exf@showproblemsout%
1666 \endgroup\fi}

Problems Buffer Interface.

\writeproblems Open a file #1.prb for writing problems; default is present main file name:
1667 \newcommand{\writeproblems}[1][\jobname]{%
1668 \exf@close@probfile\exf@start@probfile{#1}}

\closeproblems Close problems output file (if open):


1669 \newcommand{\closeproblems}{\exf@close@probfile}

\readproblems Read problems from file #1.prb; default is present main file name; switch layout and add
heading:
1670 \newcommand{\readproblems}[1][\jobname]{\exf@close@probfile%
1671 \begingroup%
1672 \exf@config@styletext\exf@config@styletextproblem%
1673 \exf@problemstitle%
1674 \input{#1\exf@config@extproblems}%
1675 \endgroup}

\insertproblems Show problems buffer:


1676 \newcommand{\insertproblems}{\exf@showproblems}

C.13 Subproblem Environment


exf@subproblem Define options for subproblem environment:
1677 \define@key{exf@subproblem}{points}{\exf@scanpoints\exf@subproblem@points#1++@}
1678 \define@key{exf@subproblem}{label}{\def\exf@label{#1}}
1679 \define@key{exf@subproblem}{tag}{\def\subproblemtag{#1}}

73
subproblem Define subproblem environment (potentially using custom name):
1680 \newenvironment{\exf@subproblemname}[1][]{%

Start with new paragraph, set text style, add vspace and step counter:
1681 \par{\exf@config@styletext\addvspace{\exf@config@skipsubproblemabove}}%
1682 \refstepcounter{\exf@subproblemcounter}%

Insert hook code:


1683 \exf@config@insertsubproblembefore%

Start inner group, mark in subproblem:


1684 \begingroup%
1685 \def\exf@in@subproblem{}%

Initialise variables, process arguments:


1686 \exf@init@block{\exf@config@skipsubprobleminfo}%
1687 \def\subproblemtag{\getexerciseconfig{tagsubproblem}}%
1688 \let\exf@subproblem@points\@undefined%
1689 \let\exf@label\@undefined%
1690 \setkeys{exf@subproblem,exf@probleminfo}{#1}%

Process automatic and manual labels:


1691 \ifexf@autolabelproblem\label{\exf@config@labelsubproblem%
1692 {\subproblemtag}}\fi%
1693 \ifdefined\exf@label\label{\exf@label}\fi%
1694 \exf@writedata{subproblem}{\subproblemtag}{\problemtag}%

Remember subproblem counter for solution:


1695 \xdef\exf@prevsubprob{\csname the\exf@subproblemcounter\endcsname}%
1696 \ifcsname theH\exf@subproblemcounter\endcsname%
1697 \xdef\exf@prevsubprobhref{\exf@subproblemcounter.%
1698 \csname theH\exf@subproblemcounter\endcsname}%
1699 \fi%

Remember points for display; disable points display if desired:


1700 \let\exf@subproblem@points@show\@undefined%
1701 \ifdefined\exf@subproblem@points%
1702 \let\exf@subproblem@points@show\exf@subproblem@points\fi%
1703 \exf@ifis\exf@subpointsat{off}{\let\exf@subproblem@points@show\@undefined}%

Write points to .aux file; add to problem total:


1704 \ifdefined\exf@subproblem@points%
1705 \global\let\exf@prevpoints\exf@subproblem@points%
1706 \expandafter\exf@writesubproblempoints\exf@subproblem@points%
1707 \exf@exptwo\exf@addtopoints\exf@problem@points@total\exf@subproblem@points%

Warn if no points given for present subproblem but previously:


1708 \else\ifdefined\exf@problem@points@total%
1709 \PackageWarning{exframe}{no points defined for \exf@subproblemname}%
1710 \fi\fi%

Display points in opening line if desired; expand points into argument and remove points:
1711 \exf@ifis\exf@subpointsat{start}{\exf@outpoints{\exf@append@intro}%
1712 {\exf@config@composepointspairstartsubproblem}{\exf@subproblem@points@show}}%

74
1713 \exf@ifis\exf@subpointsat{start*}{\exf@outpoints{\exf@prepend@intro}%
1714 {\exf@config@composepointspairstartsubproblem}{\exf@subproblem@points@show}}%

Insert hook code:


1715 \exf@config@insertsubprobleminfo%

Write opening line without item:


1716 \ifdim\exf@config@skipsubproblemitem=0pt%
1717 \exf@prepend@intro{{%
1718 \exf@config@styletitle\exf@config@styletitlesubproblem%
1719 \exf@config@composetitlesubproblem{%
1720 \csname the\exf@subproblemcounter\endcsname}}}%

Write item with fixed total width or item width plus space:
1721 \else%
1722 \ifdim\exf@config@skipsubproblemitem>0pt%
1723 \setlength\exf@addmargin{\exf@config@skipsubproblemitem}%
1724 \else%
1725 \settowidth\exf@addmargin{%
1726 \exf@config@styletitle\exf@config@styletitlesubproblem%
1727 \exf@config@composeitemsubproblem{\exf@config@countersubproblemmax}%
1728 \exf@config@composeitemsubproblemsep}%
1729 \fi%

Define item label:


1730 \def\exf@introitem{\makebox[0cm][r]{%
1731 \exf@config@styletitle\exf@config@styletitlesubproblem%
1732 \exf@config@composeitemsubproblem%
1733 {\csname the\exf@subproblemcounter\endcsname}%
1734 \exf@config@composeitemsubproblemsep}}%
1735 \fi%

Write points into margin if desired; expand points into argument and remove points:
1736 \exf@ifis\exf@subpointsat{margin}{%
1737 \exf@outpoints{\exf@prepend@def\exf@introitem}%
1738 {\exf@makepointsmargin}{\exf@subproblem@points@show}}%

Write out opening line:


1739 \exf@open@block{\exf@config@skipsubproblemtitle}%

Done:
1740 \@afterindentfalse}%

End environment, show points if desired:


1741 {\exf@ifis\exf@subpointsat{end}{\showpoints}%

End paragraph and environment:


1742 \par\exf@close@block%

Display solution if desired:


1743 \exf@ifis\exf@solutionbelow{subproblem*}{%
1744 \exf@config@insertsubproblemsolution%
1745 \exf@showsolutions{\exf@config@composetitlesolutionsingle}{}}%

75
End inner group:
1746 \endgroup%

Insert hook code, vertical skip:


1747 \exf@config@insertsubproblemafter%
1748 {\exf@config@styletext\addvspace{\exf@config@skipsubproblembelow}}%

Display solution if desired:


1749 \exf@ifis\exf@solutionbelow{subproblem}{%
1750 \exf@showsolutions{\exf@config@composetitlesolutionsingle}{}}%

Done:
1751 \ignorespacesafterend}

C.14 Solution Environment


Print Solutions.

exf@solution Define options for solution environment:


1752 \define@key{exf@solution}{prob}{\def\exf@solprob{#1}}
1753 \define@key{exf@solution}{subprob}{\def\exf@solsubprob{#1}}
1754 \define@key{exf@solution}{problemtag}{\def\problemtag{#1}}
1755 \define@key{exf@solution}{sheettag}{\def\sheettag{#1}}
1756 \define@key{exf@solution}{href}{\def\exf@solhref{#1}}
1757 \define@key{exf@solution}{label}{\def\exf@label{#1}}
1758 \define@key{exf@solution}{points}{\exf@scanpoints\exf@solution@points#1++@}
1759 \define@key{exf@solution}{probtitle}{\def\exf@solprobtitle{#1}}

printsolution Define printsolution environment to display a previously read solution environment; this
works analogously to problem and subproblem:
1760 \newenvironment{printsolution}[1]{%

Start new paragraph, add vertical space:


1761 \par{\exf@config@styletext\addvspace{\exf@config@skipsolutionabove}}%

Insert hook code:


1762 \exf@config@insertsolutionbefore%

Use equation counter for solutions:


1763 \ifexf@style@solutionequation%
1764 \exf@eqsav\value{equation}\relax%
1765 \setcounter{equation}{\value{exf@solutionequation}}%
1766 \let\theequation\theexf@solutionequation%
1767 \let\theHequation\theHexf@solutionequation%
1768 \fi%

Start a group, initialise variables, process arguments:


1769 \begingroup%
1770 \def\exf@in@solution{}%
1771 \def\exf@solprob{}%
1772 \def\exf@solsubprob{}%
1773 \let\exf@label\@undefined%

76
1774 \let\exf@solution@points\@undefined%
1775 \let\exf@solution@points@total\@undefined%
1776 \def\exf@solhref{}%
1777 \exf@init@block{\exf@config@skipsolutioninfo}%
1778 \setkeys{exf@solution,exf@probleminfo}{#1}%

Set solution counter to reflect associated problem:


1779 \exf@csdo\def{the\exf@solutioncounter}%
1780 {\exf@config@composeitemsolutionlabel{\exf@solprob}{\exf@solsubprob}}%
1781 \refstepcounter{\exf@solutioncounter}%

Set label:
1782 \ifdefined\exf@label\label{\exf@label}\fi%

Remember points for display; disable points display if desired:


1783 \let\exf@solution@points@show\@undefined%
1784 \ifdefined\exf@solution@points%
1785 \let\exf@solution@points@show\exf@solution@points\fi%
1786 \exf@ifis\exf@solpointsat{off}{\let\exf@solution@points@show\@undefined}%

Display points in opening line if desired; expand points into argument and remove points:
1787 \exf@ifis\exf@solpointsat{start}{\exf@outpoints{\exf@append@intro}%
1788 {\exf@config@composepointspairstartsolution}{\exf@solution@points@show}}%
1789 \exf@ifis\exf@solpointsat{start*}{\exf@outpoints{\exf@prepend@intro}%
1790 {\exf@config@composepointspairstartsolution}{\exf@solution@points@show}}%

Insert hook code, set solution body style:


1791 \exf@config@insertsolutioninfo%
1792 \exf@config@styletext\exf@config@styletextsolution%

Determine solution for problem or subproblem:


1793 \ifx\exf@solsubprob\exf@empty%
1794 \let\exf@tmp\exf@config@skipsolutionitem%
1795 \else%
1796 \let\exf@tmp\exf@config@skipsolutionitemsub%
1797 \fi%

Write title without item:


1798 \ifdim\exf@tmp=0pt%
1799 \protected@edef\exf@solution@title{%
1800 \exf@composetitle{\exf@solprob}{\exf@solsubprob}}%
1801 \ifx\exf@solution@title\exf@empty\else%
1802 \exf@prepend@intro{{%
1803 \exf@config@styletitle\exf@config@styletitlesolution%
1804 \ifexf@solutionhref\exf@href{\exf@solhref}%
1805 {\exf@solution@title}\else\exf@solution@title\fi}}%
1806 \fi%

Write item with fixed total width or item width plus space:
1807 \else%
1808 \ifdim\exf@tmp>0pt%
1809 \setlength\exf@addmargin{\exf@tmp}%
1810 \else%
1811 \settowidth\exf@addmargin{%
1812 \exf@config@styletitle\exf@config@styletitlesolution%

77
1813 \ifx\exf@solsubprob\exf@empty%
1814 \exf@config@composeitemsolution{\exf@config@counterproblemmax}%
1815 {\exf@config@countersubproblemmax}%
1816 \else%
1817 \exf@config@composeitemsolutionsub{\exf@config@counterproblemmax}%
1818 {\exf@config@countersubproblemmax}%
1819 \fi\exf@config@composeitemsolutionsep}%
1820 \fi%

Set item label depending on problem or subproblem:


1821 \ifx\exf@solsubprob\exf@empty%
1822 \protected@edef\exf@solution@item%
1823 {\exf@config@composeitemsolution{\exf@solprob}{\exf@empty}}%
1824 \else%
1825 \protected@edef\exf@solution@item%
1826 {\exf@config@composeitemsolutionsub{\exf@solprob}{\exf@solsubprob}}%
1827 \fi%

Define item label:


1828 \def\exf@introitem{\makebox[0cm][r]{%
1829 \exf@config@styletitle\exf@config@styletitlesubproblem%
1830 \ifexf@solutionhref\exf@href{\exf@solhref}{\exf@solution@item}%
1831 \else\exf@solution@item\fi%
1832 \exf@config@composeitemproblemsep}}%
1833 \fi%

Write points into margin if desired; expand points into argument and remove points:
1834 \exf@ifis\exf@solpointsat{margin}{%
1835 \exf@outpoints{\exf@prepend@def\exf@introitem}%
1836 {\exf@makepointsmargin}{\exf@solution@points@show}}%

Write out opening line:


1837 \exf@open@block{\exf@config@skipsolutiontitle}%

Done:
1838 \@afterindentfalse}%

End environment, show points if desired, perform sanity check:


1839 {\exf@ifis\exf@solpointsat{end}{\showpoints}%
1840 \exf@warnmismatch{\exf@solutionname}{\exf@solutioncounter}%
1841 {\exf@solution@points@total}{\exf@solution@points}%

End paragraph and envionment:


1842 \par\exf@close@block%

Restore original equation counter:


1843 \ifexf@style@solutionequation%
1844 \setcounter{exf@solutionequation}{\value{equation}}%
1845 \setcounter{equation}{\exf@eqsav}%
1846 \fi%

End inner group:


1847 \endgroup%

Vertical skip, insert hook code:

78
1848 {\exf@config@styletext\addvspace{\exf@config@skipsolutionbelow}}%
1849 \exf@config@insertsolutionafter%

Done:
1850 \ignorespacesafterend}

\solutionssection Define a section for a problem within a solution block:


1851 \newcommand{\solutionssection}[1]{\begingroup%

Initialise variables, process arguments:


1852 \def\exf@solprob{}%
1853 \def\exf@solsubprob{}%
1854 \def\exf@solprobtitle{}%
1855 \let\exf@label\@undefined%
1856 \let\exf@solhref\@undefined%
1857 \setkeys{exf@solution}{#1}%

Select title (and table of contents entry) corresponding to multiple problems vs. single prob-
lem:
1858 \let\exf@composetitle\exf@config@composetitlesolutionsproblemmulti%
1859 \exf@ifis\exf@solutionbelow{problem}{\let\exf@composetitle%
1860 \exf@config@composetitlesolutionsproblemsingle}%
1861 \exf@ifis\exf@solutionbelow{problem*}{\let\exf@composetitle%
1862 \exf@config@composetitlesolutionsproblemsingle}%
1863 \def\exf@solutionstoc{\exf@addcontentsline{\exf@config@toclevelsolution}%
1864 {\exf@config@composetocsolution{\exf@solprob}{\exf@solprobtitle}}}%

Write section line:


1865 \addvspace{\exf@config@skipsolutionsproblemabove}%
1866 \exf@solutionssection{\exf@config@styletitlesolutionsproblem}%
1867 {\exf@composetitle{\exf@solprob}{\exf@solprobtitle}}%
1868 {\exf@config@skipsolutionsproblemtitle}%
1869 {\exf@solutionstoc}{\exf@label}{\exf@solhref}%
1870 \endgroup}

Read Solution Environment.

xf@process@solnewsec If this is the first solution within a new section, write section heading to buffer:
1871 \newcommand{\exf@process@solnewsec}{%
1872 \ifdefined\exf@problem@solnewsec%
1873 \def\exf@probarg{\ifdefined\exf@prevprob prob={\exf@prevprob}\fi%
1874 \ifdefined\exf@prevprobtitle,probtitle={\exf@prevprobtitle}\fi%
1875 \ifdefined\exf@prevprobhref,href={\exf@prevprobhref}\fi%
1876 \ifdefined\exf@sollabel,label={\exf@sollabel}\fi}%
1877 \exf@ifis\exf@solutionbelow{here}{\let\exf@probarg\@undefined}%
1878 \exf@ifis\exf@solutionbelow{subproblem}{\let\exf@probarg\@undefined}%
1879 \exf@ifis\exf@solutionbelow{subproblem*}{\let\exf@probarg\@undefined}%
1880 \ifdefined\exf@probarg%
1881 \ifexf@lineno\exf@addline\exf@solbuf{\exf@linesep}%
1882 \exf@addline\exf@solbuf{\exf@lineno}\fi%
1883 \exf@addline\exf@solbuf{\@backslashchar solutionssection{\exf@probarg}}%
1884 \exf@addline\exf@solbuf{}%
1885 \fi%
1886 \global\let\exf@problem@solnewsec\@undefined%
1887 \fi}%

79
xf@process@solnewsec Declare additional arguments to printsolution to describe corresponding problem and
tags:
1888 \newcommand{\exf@generate@solprobarg}{%
1889 \edef\exf@solprobarg{%
1890 \ifdefined\exf@prevprob prob={\exf@prevprob},\fi%
1891 \ifdefined\exf@prevsubprob subprob={\exf@prevsubprob},%
1892 \ifdefined\exf@prevsubprobhref href={\exf@prevsubprobhref},\fi%
1893 \else%
1894 \ifdefined\exf@prevprobhref href={\exf@prevprobhref},\fi%
1895 \fi%
1896 \ifdefined\exf@prevpoints points=%
1897 {\expandafter\exf@formatpoints\exf@prevpoints},\fi%
1898 \ifdefined\sheettag sheettag={\sheettag},\fi%
1899 \ifdefined\problemtag problemtag={\problemtag},\fi}%

Clean up:
1900 \global\let\exf@prevsubprob\@undefined%
1901 \global\let\exf@prevsubprobhref\@undefined%
1902 \global\let\exf@prevpoints\@undefined}%

exf@solution@direct Define direct output version of solution environment; pass on to printsolution environ-
ment:
1903 \newenvironment{exf@solution@direct}[1][]%
1904 {\showpoints%
1905 \global\let\exf@problem@solnewsec\@undefined%
1906 \exf@generate@solprobarg%
1907 \exf@showsolutionsin%
1908 \let\exf@composetitle\exf@config@composetitlesolutionsingle%
1909 \exf@exptwo\printsolution{\exf@solprobarg#1}}%
1910 {\endprintsolution%
1911 \exf@showsolutionsout%
1912 \ignorespacesafterend}%

exf@solution@scan Define scan version of solution environment; use \exf@scanblock to properly parse op-
exf@scansolution tional argument and pass on to exf@scansolution:
1913 \newenvironment{exf@solution@scan}%
1914 {\exf@scanblock{\exf@scansolution}}{\endexf@scansolution}%
1915 \newenvironment{exf@scansolution}[2]{%

If solution is to be displayed immediately, make sure to display points first; insert solution
section heading in buffer; compose additional arguments to printsolution:
1916 \exf@ifis\exf@solutionbelow{here}{\showpoints}%
1917 \exf@process@solnewsec%
1918 \exf@generate@solprobarg%

Write separator and printsolution environment to buffer:


1919 \ifexf@lineno\exf@addline\exf@solbuf{\exf@linesep}%
1920 \exf@addline\exf@solbuf{\exf@lineno}\fi%
1921 \exf@addline\exf@solbuf%
1922 {\@backslashchar begin{printsolution}{\exf@solprobarg#1}}%

Start verbatim processing:


1923 \def\exf@verbatim@process{\exf@append@buf\exf@solbuf}%
1924 \exf@verbatim#2}%

80
End verbatim processing; close printsolution environment:
1925 {\exf@endverbatim%
1926 \exf@addline\exf@solbuf{\@backslashchar end{printsolution}}%
1927 \global\exf@solbuf@cleanfalse%

Write buffer to file if output file open:


1928 \ifexf@solfile@open%
1929 \exf@write@buf\exf@solfile\exf@solbuf%
1930 \exf@clear@solbuf%
1931 \fi%

Drop buffer if solutions not to be displayed:


1932 \ifsolutions\else\exf@clear@solbuf\fi%

Display solution immediately in various cases:


1933 \exf@ifis\exf@solutionbelow{here}{\exf@showsolutions%
1934 {\exf@config@composetitlesolutionsingle}{}}%
1935 \ifdefined\exf@in@subproblem\else%
1936 \exf@ifis\exf@solutionbelow{subproblem}{%
1937 \exf@showsolutions{\exf@config@composetitlesolutionsingle}{}}%
1938 \exf@ifis\exf@solutionbelow{subproblem*}{%
1939 \exf@showsolutions{\exf@config@composetitlesolutionsingle}{}}\fi%
1940 \ifdefined\exf@in@problem\else%
1941 \exf@ifis\exf@solutionbelow{problem}{%
1942 \exf@showsolutions{\exf@config@composetitlesolutionmulti}{}}%
1943 \exf@ifis\exf@solutionbelow{problem*}{%
1944 \exf@showsolutions{\exf@config@composetitlesolutionmulti}{}}\fi%

Done:
1945 \ignorespacesafterend}

solution Define solution environment (potentially using custom name) to choose between direct and
buffered version:
1946 \newenvironment{\exf@solutionname}%
1947 {\ifexf@solutionbuf\let\exf@tmp\exf@solution@scan%
1948 \else\let\exf@tmp\exf@solution@direct\fi%
1949 \exf@tmp}%
1950 {\ifexf@solutionbuf\let\exf@tmp\endexf@solution@scan%
1951 \else\let\exf@tmp\endexf@solution@direct\fi%
1952 \exf@tmp}

C.15 Solution Blocks


Solution Block Handling.

exf@solutionssection Output solution block section:


1953 \newcommand{\exf@solutionssection}[6]{%

Check whether title is empty:


1954 \protected@edef\exf@solutionstitleexp{#2}%
1955 \ifx\exf@solutionstitleexp\exf@empty\else%

Define a label:

81
1956 \ifdefined#5%
1957 \exf@csdo\def{the\exf@solutioncounter}%
1958 {\exf@config@composeitemsolutionlabel{\exf@solprob}{\exf@solsubprob}}%
1959 \refstepcounter{\exf@solutioncounter}\label{#5}%
1960 \fi%

Output section line:


1961 \exf@section{#3}{\exf@config@styletitle\exf@config@styletitlesolution#1%
1962 \ifexf@solutionhref\exf@href{#6}{\exf@solutionstitleexp}%
1963 \else\exf@solutionstitleexp\fi}#4%
1964 \fi}

\exf@solutionstitle Compose the title for a solution block:


1965 \newcommand{\exf@solutionstitle}{\exf@solutionssection%
1966 {\exf@config@styletitlesolutions}{%
1967 \exf@config@composetitlesolutions}{\exf@config@skipsolutionstitle}%
1968 {\exf@addcontentsline{\exf@config@toclevelsolutions}%
1969 {\exf@config@composetocsolutions}}{\@undefined}{\@undefined}}

\exf@showsolutionsin Output solution block intro:


1970 \newcommand{\exf@showsolutionsin}{%

Set solution body style; add vertical space; insert hook code:
1971 \par\exf@config@styletext\addvspace{\exf@config@skipsolutionsabove}%
1972 \exf@config@styletextsolution%
1973 \exf@config@insertsolutionsbefore}

exf@showsolutionsout Output solution block outro:


1974 \newcommand{\exf@showsolutionsout}{%

Insert hook code; close paragraph; add vertical space:


1975 \exf@config@insertsolutionsafter%
1976 \par\exf@config@styletext\addvspace{\exf@config@skipsolutionsbelow}}

\exf@showsolutions Output solution block in buffer:


1977 \newcommand{\exf@showsolutions}[2]{%

Do nothing if buffer is empty (avoid titles):


1978 \ifexf@solbuf@clean\else\begingroup%

Execute output solution block intro:


1979 \exf@showsolutionsin%
1980 \let\exf@composetitle#1%
1981 #2%

Source and clear buffer:


1982 \exf@source@buf\exf@solbuf%
1983 \exf@clear@solbuf%

Execute output solution block outro:


1984 \exf@showsolutionsout%
1985 \endgroup\fi}

82
Solutions Buffer Interface.

\writesolutions Open a file #1.sol for writing solutions; default is present main file name:
1986 \newcommand{\writesolutions}[1][\jobname]{%
1987 \exf@close@solfile\exf@start@solfile{#1}}

\closesolutions Close solutions output file (if open):


1988 \newcommand{\closesolutions}{\exf@close@solfile}

\readsolutions Read solutions from file #1.sol; default is present main file name; switch layout and add
heading:
1989 \newcommand{\readsolutions}[1][\jobname]{\exf@close@solfile%
1990 \ifsolutions\begingroup%
1991 \exf@config@styletext\exf@config@styletextsolution%
1992 \let\exf@composetitle\exf@config@composetitlesolutionmulti%
1993 \exf@solutionstitle%
1994 \input{#1\exf@config@extsolutions}%
1995 \endgroup\fi}

\insertsolutions Show solutions buffer:


1996 \newcommand{\insertsolutions}{\exf@showsolutions%
1997 {\exf@config@composetitlesolutionmulti}{\exf@solutionstitle}}

C.16 Interaction with metastr


This package transfers some functionality to the package metastr when loaded previously
(preferably with package option course) by the package option metastr. The following
changes apply:

• The terms specified by the configuration options term..., see section C.3, are trans-
ferred to the corresponding term registers \metaterm{...} in metastr. This can facili-
tate internationalisation, and suitable words for English, German, French and Spanish
are provided.
• Metadata as described in section 2.3 should be filled via \metaset rather than
\exercisedata. The present package will read it from the metastr registers.
• Basic PDF metadata is written automatically or manually as described in section 2.3.
This is done via \metawritepdfinfo, consequently, automatic writing of these basic
metadata is disabled in metastr.
• Sheet-specific metadata (package option pdfdata=sheet) is handled via the metastr
registers sheettitle and sheetdata rather than composemetasheet.

Apply modifications only when package metastr is loaded:


1998 \ifdefined\metaset

Transfer Metadata. Import basic data from metastr:


1999 \exercisedata{author={\metapick[]{author}}}
2000 \exercisedata{title={\metapick[]{title}}}
2001 \exercisedata{subject={\metapick[]{subject}}}
2002 \exercisedata{keyword={\metapick[]{keyword}}}
2003 \exercisedata{date={\metapick[]{date}}}

83
Import course data from metastr:
2004 \ifdefined\mstr@def@course
2005 \exercisedata{course={\metapick[]{course}}}
2006 \exercisedata{instructor={\metapick[]{instructor}}}
2007 \exercisedata{institution={\metapick[]{institution}}}
2008 \exercisedata{period={\metapick[]{period}}}
2009 \exercisedata{material={\metapick[]{material}}}
2010 \fi

Sheet Data.

sheettitle Registers for sheet title and author:


sheetauthor
2011 \metadef{sheettitle}
2012 \metadef{sheetauthor}

\exf@writemetadata Write PDF metadata via metastr package, let exframe initiate process (especially for sheet):
2013 \metaunset[info]{writepdf}
2014 \def\exf@writemetadata{%
2015 \exf@ifis\exf@metadata{sheet}{\metaset[use]{sheettitle}{}}%
2016 \metawritepdfinfo%
2017 \exf@ifis\exf@metadata{sheet}{\metaunset[use]{sheettitle}}}

Fill registers:
2018 \metaset{sheetauthor}{\exerciseifempty{\getsheetdata{author}}%
2019 {\metapick[#1]{instructor}}{\getsheetdata{author}}}
2020 \metaset{sheettitle}{\exerciseifempty{\getsheetdata{rawtitle}}%
2021 {\metatranslate[#1]{sheet} \thesheet}%
2022 {\getsheetdata{rawtitle}}}
2023 \metaset{author}{\exerciseifempty{\getsheetdata{author}}%
2024 {\metapick[#1]{instructor}}{\metapick[#1]{sheetauthor}}}
2025 \metaset{subtitle}{%
2026 \metaif[use]{sheettitle}
2027 {\metapick[#1]{sheettitle}}
2028 {\metapick[#1]{material}}}

Terms.

term... Transfer term definitions to metastr:


2029 \exerciseconfig{termsheet}{\metaterm{sheet}}
2030 \exerciseconfig{termsheets}{\metaterm{sheets}}
2031 \exerciseconfig{termproblem}{\metaterm{problem}}
2032 \exerciseconfig{termproblems}{\metaterm{problems}}
2033 \exerciseconfig{termsolution}{\metaterm{solution}}
2034 \exerciseconfig{termsolutions}{\metaterm{solutions}}
2035 \exerciseconfig{termpoint}{\metaterm{point}}
2036 \exerciseconfig{termpoints}{\metaterm{points}}

Translations. English:
2037 \ifdefined\mstr@lang@en
2038 \metasetterm[en]{sheet}{Sheet}
2039 \metasetterm[en]{sheets}{Sheets}
2040 \metasetterm[en]{problem}{Problem}

84
2041 \metasetterm[en]{problems}{Problems}
2042 \metasetterm[en]{solution}{Solution}
2043 \metasetterm[en]{solutions}{Solutions}
2044 \metasetterm[en]{point}{point}
2045 \metasetterm[en]{points}{points}
2046 \fi

German:
2047 \ifdefined\mstr@lang@de
2048 \metasetterm[de]{sheet}{Blatt}
2049 \metasetterm[de]{sheets}{Blätter}
2050 \metasetterm[de]{problem}{Aufgabe}
2051 \metasetterm[de]{problems}{Aufgaben}
2052 \metasetterm[de]{solution}{L\"osung}
2053 \metasetterm[de]{solutions}{L\"osungen}
2054 \metasetterm[de]{point}{Punkt}
2055 \metasetterm[de]{points}{Punkte}
2056 \fi

French:
2057 \ifdefined\mstr@lang@fr
2058 \metasetterm[fr]{sheet}{Feuille}
2059 \metasetterm[fr]{sheets}{Feuilles}
2060 \metasetterm[fr]{problem}{Probl\‘eme}
2061 \metasetterm[fr]{problems}{Probl\‘emes}
2062 \metasetterm[fr]{solution}{Solution}
2063 \metasetterm[fr]{solutions}{Solutions}
2064 \metasetterm[fr]{point}{point}
2065 \metasetterm[fr]{points}{points}
2066 \fi

Spanish:
2067 \ifdefined\mstr@lang@es
2068 \metasetterm[es]{sheet}{Hoja}
2069 \metasetterm[es]{sheets}{Hojas}
2070 \metasetterm[es]{problem}{Problema}
2071 \metasetterm[es]{problems}{Problemas}
2072 \metasetterm[es]{solution}{Solucion}
2073 \metasetterm[es]{solutions}{Soluciones}
2074 \metasetterm[es]{point}{punto}
2075 \metasetterm[es]{points}{puntos}
2076 \fi

Close metastr conditional:


2077 \fi

85

You might also like