Ex Frame
Ex Frame
Niklas Beisert
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:
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}
\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}
\begin{solution}[opts]
solution text
\end{solution}
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.
\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:
\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]
\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}
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}
• 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:
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:
• 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]
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}
\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}
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}
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:
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.
\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\else#3\fi and \if&\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).
\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:
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{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}
• 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:
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&...\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.
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
• 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.
18
• interaction with package metastr
• minor fixes
v3.31: 2020/01/11
v3.3: 2019/06/15
v3.2: 2019/05/01
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
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
• renamed to nbprob.sty
• added metadata
• added points
• added layout configuration
• removed specific macros
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
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}
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}
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{}}}
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}
Show solutions below each problem (may try alternatives subproblem or sheet):
47 \exercisestyle{solutionbelow=problem}
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
Body.
85 \begin{document}
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}
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}
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}
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}
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}
26
246 \\\hline
247 \exerciseloop{\getsubproblemlist{#1}}{&}
248 &\\\hline
249 \end{tabular}\quad
250 \fi
251 }
252 \fi
End sheet:
253 \end{sheet}
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.
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
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}{}
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
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
28
299 \metasetterm[en]{sheets}{sample sheets}
300 \metasetterm[en]{solution}{Solution}
301 \metasetterm[en]{solutions}{solutions}
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}
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
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}}
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 sheet to collect unused problems (only process for individual sheets, i.e. itself):
410 \def\jobnameunused{exfseraa}
411 \ifx\childdocname\jobnameunused\include{\jobnameunused}\fi
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.
Adjust due date for each sheet. For sheet containing unused problems exfseraa.tex, declare
a sheet title={unused problems} instead of due date.
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
33
Start new page:
472 \turnover
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}
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.
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
35
530 if [[ "$num" == "$v" ]]; then secokay="okay"; fi
531 done
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
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-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.
General Definitions.
\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@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}
Make sure the macros in code written to the .aux file exist:
657 \AtBeginDocument{\immediate\write\@auxout{%
658 \string\providecommand{\string\exf@notedata}[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]{}
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]{}
40
Write warning message to document for better detection of inconsistencies:
690 \define@boolkey{exf@setup}[exf@]{warntext}[true]{}
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}}
\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}
42
Style for problem titles:
736 \exerciseconfig{styletitleproblem}{\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 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}
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}
43
753 \exerciseconfig{skipsolutionbelow}{1.5ex plus 0.5ex minus 1ex}
754 \exerciseconfig{skipsolutiontitle}{-0.5em}
755 \exerciseconfig{skipsolutioninfo}{0.25em}
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}
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}
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}
44
Code to insert before a problem block is displayed:
773 \exerciseconfig{insertproblemsbefore}{}
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}{}
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.}
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 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}}
46
Compose title for problem block:
819 \exerciseconfig{composetitleproblems}%
820 {\getexerciseconfig{termproblems}}
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}
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}
48
888 \exerciseconfig{insertwarnpointsrerun}[1]
889 {\textbf{points changed for #1 (please recompile)}}
Further Definitions.
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}{}
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.
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}}
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
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}}
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}}}}
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}}}
52
Declare additional general purpose fields:
1016 \defexercisedata{date}
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}}}
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}}}
\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}}
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}}}
\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}}
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
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}
56
1138 \def\theexf@solutionequation{\exf@config@countersolutionequation}
1139 \def\theHexf@solutionequation{sol.\arabic{equation}}
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.
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
Verbatim Processing.
\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}}}
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}}}}
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.
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}}}
\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@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}
\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 }
62
Problem 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}}}
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.
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}
\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}
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 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}}%
Store points:
66
1466 \let\exf@sheet@points\exf@sheet@points@total%
1467 \fi%
Insert solutions:
1471 \exf@ifis\exf@solutionbelow{sheet}{\insertsolutions}%
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}
67
Begin inner group, mark in problem:
1490 \begingroup%
1491 \def\exf@in@problem{}%
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}}%
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%
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}}%
69
1569 \exf@addcontentsline{\exf@config@toclevelproblem}%
1570 {\exf@config@composetocproblem{\csname the\exf@problemcounter\endcsname}%
1571 {\exf@data@problem@rawtitle}}%
Done:
1572 \@afterindentfalse}%
70
Insert hook code, vertical skip:
1599 \exf@config@insertproblemafter%
1600 \addvspace{\exf@config@skipproblembelow}%
Done:
1603 \ignorespacesafterend}
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]{%
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%
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}
Set problem body style; add vertical space; insert hook code:
1654 \par\exf@config@styletext\addvspace{\exf@config@skipproblemsabove}%
1655 \exf@config@insertproblemsbefore}
72
Insert hook code; close paragraph; add vertical space:
1657 \exf@config@insertproblemsafter%
1658 \par\exf@config@styletext\addvspace{\exf@config@skipproblemsbelow}}
\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}}
\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}
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}%
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}}%
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%
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}}%
Done:
1740 \@afterindentfalse}%
75
End inner group:
1746 \endgroup%
Done:
1751 \ignorespacesafterend}
printsolution Define printsolution environment to display a previously read solution environment; this
works analogously to problem and subproblem:
1760 \newenvironment{printsolution}[1]{%
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 label:
1782 \ifdefined\exf@label\label{\exf@label}\fi%
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}}%
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%
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}}%
Done:
1838 \@afterindentfalse}%
78
1848 {\exf@config@styletext\addvspace{\exf@config@skipsolutionbelow}}%
1849 \exf@config@insertsolutionafter%
Done:
1850 \ignorespacesafterend}
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}}}%
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%
80
End verbatim processing; close printsolution environment:
1925 {\exf@endverbatim%
1926 \exf@addline\exf@solbuf{\@backslashchar end{printsolution}}%
1927 \global\exf@solbuf@cleanfalse%
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}
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%
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}
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}}
\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}
• 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.
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.
\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.
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
85