]> git.donarmstrong.com Git - lib.git/commitdiff
added a new version of exam.cls
authorDon Armstrong <don@donarmstrong.com>
Mon, 17 Oct 2005 04:24:37 +0000 (04:24 +0000)
committerDon Armstrong <don@donarmstrong.com>
Mon, 17 Oct 2005 04:24:37 +0000 (04:24 +0000)
texmf/ls-R
texmf/tex/latex/exam.cls [new file with mode: 0644]

index bae79a091ed2923387b3d450b665b7c076c0255b..01d97913aa1e8b5d14cf6a034d620cb076cf45b7 100644 (file)
@@ -8,14 +8,52 @@ invoice.sty
 ls-R
 metafont
 realcalc.tex
+.svn
+tex
 
 ./bibtex:
+.svn
 unsrtdon.bst
 unsrtdon.bst~
 
+./bibtex/.svn:
+empty-file
+entries
+format
+prop-base
+props
+README.txt
+text-base
+tmp
+wcprops
+
+./bibtex/.svn/prop-base:
+
+./bibtex/.svn/props:
+
+./bibtex/.svn/text-base:
+unsrtdon.bst.svn-base
+
+./bibtex/.svn/tmp:
+prop-base
+props
+text-base
+wcprops
+
+./bibtex/.svn/tmp/prop-base:
+
+./bibtex/.svn/tmp/props:
+
+./bibtex/.svn/tmp/text-base:
+
+./bibtex/.svn/tmp/wcprops:
+
+./bibtex/.svn/wcprops:
+
 ./metafont:
 kelly
 ls-R
+.svn
 
 ./metafont/kelly:
 cmg10.600pk
@@ -37,3 +75,154 @@ greek.pdf
 greek.sty
 greek.tex
 grktxt.mf
+.svn
+
+./metafont/kelly/.svn:
+empty-file
+entries
+format
+prop-base
+props
+README.txt
+text-base
+tmp
+wcprops
+
+./metafont/kelly/.svn/prop-base:
+cmg10.600pk.svn-base
+cmg10.tfm.svn-base
+cmgb10.600pk.svn-base
+cmgb10.tfm.svn-base
+cmgi10.600pk.svn-base
+cmgi10.tfm.svn-base
+cmgtt10.600pk.svn-base
+cmgtt10.tfm.svn-base
+greek.dvi.svn-base
+greek.pdf.svn-base
+
+./metafont/kelly/.svn/props:
+cmg10.600pk.svn-work
+cmg10.tfm.svn-work
+cmgb10.600pk.svn-work
+cmgb10.tfm.svn-work
+cmgi10.600pk.svn-work
+cmgi10.tfm.svn-work
+cmgtt10.600pk.svn-work
+cmgtt10.tfm.svn-work
+greek.dvi.svn-work
+greek.pdf.svn-work
+
+./metafont/kelly/.svn/text-base:
+cmg10.600pk.svn-base
+cmg10.mf.svn-base
+cmg10.tfm.svn-base
+cmgb10.600pk.svn-base
+cmgb10.mf.svn-base
+cmgb10.tfm.svn-base
+cmgi10.600pk.svn-base
+cmgi10.mf.svn-base
+cmgi10.tfm.svn-base
+cmgtt10.600pk.svn-base
+cmgtt10.mf.svn-base
+cmgtt10.tfm.svn-base
+greek.aux.svn-base
+greek.dvi.svn-base
+greek.log.svn-base
+greek.pdf.svn-base
+greek.sty.svn-base
+greek.tex.svn-base
+grktxt.mf.svn-base
+
+./metafont/kelly/.svn/tmp:
+prop-base
+props
+text-base
+wcprops
+
+./metafont/kelly/.svn/tmp/prop-base:
+
+./metafont/kelly/.svn/tmp/props:
+
+./metafont/kelly/.svn/tmp/text-base:
+
+./metafont/kelly/.svn/tmp/wcprops:
+
+./metafont/kelly/.svn/wcprops:
+
+./metafont/.svn:
+empty-file
+entries
+format
+prop-base
+props
+README.txt
+text-base
+tmp
+wcprops
+
+./metafont/.svn/prop-base:
+
+./metafont/.svn/props:
+
+./metafont/.svn/text-base:
+ls-R.svn-base
+
+./metafont/.svn/tmp:
+prop-base
+props
+text-base
+wcprops
+
+./metafont/.svn/tmp/prop-base:
+
+./metafont/.svn/tmp/props:
+
+./metafont/.svn/tmp/text-base:
+
+./metafont/.svn/tmp/wcprops:
+
+./metafont/.svn/wcprops:
+
+./.svn:
+empty-file
+entries
+format
+prop-base
+props
+README.txt
+text-base
+tmp
+wcprops
+
+./.svn/prop-base:
+
+./.svn/props:
+
+./.svn/text-base:
+aliases.svn-base
+invoice.def.svn-base
+invoice.sty.svn-base
+ls-R.svn-base
+realcalc.tex.svn-base
+
+./.svn/tmp:
+prop-base
+props
+text-base
+wcprops
+
+./.svn/tmp/prop-base:
+
+./.svn/tmp/props:
+
+./.svn/tmp/text-base:
+
+./.svn/tmp/wcprops:
+
+./.svn/wcprops:
+
+./tex:
+latex
+
+./tex/latex:
+exam.cls
diff --git a/texmf/tex/latex/exam.cls b/texmf/tex/latex/exam.cls
new file mode 100644 (file)
index 0000000..d6165bf
--- /dev/null
@@ -0,0 +1,4668 @@
+% exam.cls
+%
+% A LaTeX2e document class for preparing exams.
+
+%% exam.cls
+%% Copyright (c) 1994, 1997, 2000, 2004 Philip S. Hirschhorn
+%
+% 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 2003/12/01 or later.
+%
+% This work has the LPPL maintenance status "author-maintained".
+% 
+% This work consists of the files exam.cls and examdoc.tex.
+
+
+% The user documentation for exam.cls is in the file examdoc.tex.
+
+
+%%% Philip Hirschhorn
+%%% Department of Mathematics
+%%% Wellesley College
+%%% Wellesley, MA 02481
+%%% psh@math.mit.edu
+
+% The newest version of this documentclass should always be available
+% from my web page: http://www-math.mit.edu/~psh/
+
+
+\def\fileversion{2.2}
+\def\filedate{2004/08/14}
+%---------------------------------------------------------------------
+%---------------------------------------------------------------------
+% PLEASE DO NOT MAKE ANY CHANGES TO THIS FILE!
+% 
+% If you wish to make changes to this file, rename this file
+% to something other than exam.cls BEFORE YOU MAKE THE CHANGES!
+% 
+% If there's some feature that you'd like that this file doesn't
+% provide, tell me about it.
+% 
+%
+%
+%
+%
+% Thanks to:
+%
+% Piet van Oostrum, from whose excellent ``fancyheadings.sty'' we
+% shamelessly stole most of the code for setting the headers and
+% footers.
+%
+% Mate Wierdl <mw@wierdlmpc.msci.memphis.edu>, who contributed the
+% code so that if the number of points is ``1'', then the default
+% value of \pointname will print ``1 point'' instead of ``1 points''.
+%
+% Tom Brikowski <brikowi@utdallas.edu>, who contributed the code for
+% making the number of points and number of questions available as
+% macros (as well as the idea of putting the number of points in a 
+% box, instead of in parentheses).  (I changed his code to make this
+% all optional, so if there are errors there, it's my fault and not
+% his.)
+%
+% Ottmar Beucher <beucher@fh-karlsruhe.de>, Dan Drake
+% <drake@math.umn.edu>, and Justus Piater <Justus.Piater@ULg.ac.be> who
+% contributed ideas and code for the \pointsofquestion and \gradetable
+% commands for printing a Grading Table.  (I changed all the code to
+% make this compatible with hyperref.sty, so if there are errors there,
+% it's my fault and not theirs.)
+%
+% Justus Piater <Justus.Piater@ULg.ac.be>, who contributed the code for
+% the solution environment.  (I changed his code to allow page breaks
+% inside solutions so, once again, if it's buggy, it's my fault.) 
+%
+% Donald Arseneau <asnd@triumf.ca>, who created the excellent
+% ``framed.sty'' and generously allowed me to include basically the
+% whole thing in exam.cls, making the few changes needed for it to
+% work well with question environments:
+% framed.sty   v 0.8a   21-Jul-2003
+% Copyright (C) 1992-2003 by Donald Arseneau
+% These macros may be freely transmitted, reproduced, or modified
+% provided that this notice is left intact.
+%
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%                             Changelog:
+
+
+% Version 2.2:
+%
+% Enough already with betatest.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.116$\beta$:
+%
+% We futzed with the oneparchoices environment so that a bit more
+% space will be left before the first choice when the list of choices
+% continues the paragraph of the question.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.115$\beta$:
+%
+% New environment: oneparchoices
+%
+% Intended for multiple choice questions (just like the choices
+% environment), except that the oneparchoices prints all the choices in
+% a single paragraph.  This environment does *not* create a paragraph
+% break at its beginning, so if you begin the environment without
+% skipping a line before it, the choices will be printed as a
+% continuation of the paragraph preceding the environment.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.114$\beta$:
+%
+% We fixed up the code for \uplevel and \fullwidth so that they work
+% correctly if a solution environment is inside the argument.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.113$\beta$:
+%
+% Added code to warn if point totals have changed since the last run of
+% LaTeX (which requires running LaTeX again to make sure that
+% gradetables, pointsofquestion, and pointsonpage values are correct).
+%
+%
+% We also added code to create a label for every question, part,
+% subpart, and subsubpart.  We make no use of these labels, but we put
+% them there so that if a question (or part, etc.) is, e.g., moved from
+% one page to another, LaTeX will notice this and warn the user that
+% LaTeX must be run one more time to be sure everything is correct.
+%
+% We need to do this even though we've already included code to check
+% when point totals change because questions (and parts, etc.) know what
+% page they're on from reading the info written to the .aux file on the
+% previous run.  Thus, if a question (or part, etc.) is moved to a
+% different page, then the pointsonpage totals won't notice until the
+% *second* subsequent run of LaTeX, and so there'll be no warning to the
+% user on the *first* run.  Including these labels gives the user a
+% warning on that first run.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.112$\beta$:
+%
+% New environment: coverpages
+%
+% This is for use only *before* any questions (or parts, or subparts, or
+% subsubparts).  It allows you to print one or more cover pages,
+% numbered in a different sequence of page numbers from the main pages.
+% That is, the page number is reset to 1 at the end of a coverpages
+% environment.
+%
+% The default is that headers and footers are empty on the coverpages,
+% but if you print the page number (using \thepage in the header or
+% footer) then the page number will be printed in roman numerals.  When
+% the coverpages environment ends, the page number is reset to 1 and the
+% page numbers revert to the (standard) arabic numbers.
+%
+% Headers and footers on coverpages are determined by commands
+% completely analogous to the relevant commands for the main pages,
+% except that the names of the commands begin with the word ``cover''.
+% That is, the following commands are available to define headers and
+% footers, and to leave additional space for the headers and footers as
+% needed: 
+%
+%
+% New commands:
+%
+% \coverheader
+% \coverrunningheader
+% \coverfirstpageheader
+%
+% \coverlhead
+% \coverchead
+% \coverrhead
+%
+% \coverfooter
+% \coverrunningfooter
+% \coverfirstpagefooter
+%
+% \coverlfoot
+% \covercfoot
+% \coverrfoot
+%
+% \coverextraheadheight
+% \coverextrafootheight
+%
+%--------------------------------------------------------------------
+%
+% Version 2.111$\beta$:
+%
+% Bugfix: There was an incompatibility with spanish.ldf (loaded when the
+% user loads the babel package with the spanish option) (and possibly
+% with other language packages as well).  That file redefines \@roman,
+% which is used by \roman, which I had used to define some internally
+% used command names.  I replaced
+%
+%   \roman{countername}
+%
+% with
+%
+%   \romannumeral \csname c@countername\endcsname
+%
+% for all of those command names, and now all at least seems to be
+% well.
+%
+%
+% The following stuff isn't really complete yet:
+% New environment: coverpages
+%
+% New commands:
+%
+% \coverheader
+% \coverrunningheader
+% \coverfirstpageheader
+%
+% \coverlhead
+% \coverchead
+% \coverrhead
+%
+% \coverfooter
+% \coverrunningfooter
+% \coverfirstpagefooter
+%
+% \coverlfoot
+% \covercfoot
+% \coverrfoot
+%
+% \coverextraheadheight
+% \coverextrafootheight
+%
+%--------------------------------------------------------------------
+%
+% Version 2.110$\beta$:
+%
+% We change the definition of \half to print a fraction one half that
+% uses a slanted fraction bar.  We also created two new commands:
+%
+%   \newcommand*\usehorizontalhalf
+%   \newcommand*\useslantedhalf
+%
+% The first one changes the definition of \half so that it produces a
+% fraction with a horizontal fraction bar (via $\frac{1}{2}$), and the
+% second one returns the definition of \half to its default.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.109$\beta$:
+%
+% Point values for questions (and parts, etc.) can now include half
+% points.  To specify a half point, you include ``\half'' immediately
+% following the integer part (or just with ``\half'' if the integer part
+% is zero).  For example, the following are all valid point values:
+%
+% 0
+% \half
+% 1
+% 1\half
+% 2
+% 2\half
+% Etc.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.108$\beta$:
+%
+% New environment: solutionorlines
+%
+% This is almost identical to the solution environment, except that when
+% solutions are not being printed and an optional argument appears
+% specifying an amount of space to be left for answers, that space is
+% filled with ruled lines (created by \fillwithlines), rather than being
+% left blank (as it is by the solution environment).
+%
+% Also: Changed the shade of gray used as the default color for
+%       \shadedsolutions.
+%
+%       Changed the default thickness of lines used by \fillwithlines.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.107$\beta$:
+%
+% We added an option to have solution environments use a \colorbox (from
+% the color package) instead of an \fbox.  Instead of surrounding the
+% solution with a printed box, it prints the solution on a colored
+% background.  The default color is a light gray (so that it can be
+% printed on any printer that can do grayscale), but the color can be
+% changed.
+%
+% To use this option, the user must load the color package with the
+% command
+%
+%   \usepackage{color}
+%
+% in the preamble.  (If appropriate, optional arguments can be used in
+% that command.)  The user can then give the command
+%
+%   \shadedsolutions
+%
+% to have all solutions printed using a \colorbox.  After giving that
+% command, the user can change the color of the backgrounds of solutions
+% by defining the color ``SolutionColor''.  The default SolutionColor is
+% set via the command
+%
+%   \definecolor{SolutionColor}{gray}{0.9}
+%
+% and the user can change that by giving a \definecolor command *after*
+% giving the command \shadedsolutions.  For example, the command
+%
+%   \definecolor{SolutionColor}{rgb}{0.8,0.9,1}
+%
+% sets the background color to a light blue.
+%
+% You can return to the default situation of having solutions printed
+% inside an \fbox by giving the command
+%
+%   \framedsolutions
+%
+% Note added later: The default shade of gray was changed in version
+% 2.108$\beta$.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.106$\beta$:
+%
+%
+% We redid the solution environment to use Donald Arseneau's framed.sty
+% macros, so that the solution can be broken across pages with each
+% piece enclosed in a frame.
+%
+% We also changed the default definition of \solutiontitle; it's now
+% defined by:
+%
+%  \newcommand{\solutiontitle}{\noindent\textbf{Solution:}\enspace}
+%
+%
+%--------------------------------------------------------------------
+%
+% Version 2.105$\beta$:
+%
+% We're making the thickness of the lines used by \fillwithlines
+% changeable, and changing the default thickness.
+%
+% We're doing this by defining a new command:
+%
+%   \linefill,
+%
+% which is similar to \hrulefill, except that \linefill uses a line of
+% height \linefillthickness, whose default value is 0.2pt.
+% (\fillwithlines used to use \hrulefill, which uses a line of height
+% 0.4pt.)
+%
+% The default value of \linefillthickness is set by the command
+%
+%   \setlength\linefillthickness{0.2pt}
+%
+% and this can be changed by giving a new \setlength command.
+%
+% Note added later: The default thickness was changed in version
+% 2.108$\beta$.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.104$\beta$:
+%
+% We added a new command: \fillwithlines
+%
+% \fillwithlines takes one argument, which is either a length or \fill,
+% and it fills that much vertical space with horizontal lines that run
+% the length of the current line.  That is, they extend from the current
+% left margin (which depends on whether we're in a question, part,
+% subpart, or subsubpart) to the right margin.
+%
+% The distance between the lines is \linefillheight, whose default value
+% is set with the command
+%
+%   \setlength\linefillheight{.25in}
+%
+% This value can be changed by giving a new \setlength command.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.103$\beta$:
+%
+% We added a new command: \answerline
+%
+% This is intended for short answer questions.  It inserts a \vskip of
+% length \answerskip and then inserts a horizontal line of length
+% \answerlinelength at the right margin, preceded by the number of the
+% current question, part, subpart, or subsubpart.
+%
+% The default values are set by the commands
+%
+%   \setlength\answerlinelength{1in}
+%   \setlength\answerskip{2ex}
+%
+% and these can be changed by giving new \setlength commands.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.101$\beta$:
+%
+% We eliminated the command \marks, since it conflicts with a definition
+% of that name in some package or other.  We changed the definition of
+% \marksnotpoints so that it still accomplishes the same thing, but now
+% it works through the \pointpoints command.
+%
+% We changed the default format for the \droptotalpoints command, so
+% that it now prints
+%
+%   Total for Question 1: 25
+%
+% where the ``25'' is followed by \marginpointname, whose default value
+% is empty.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.098$\beta$:
+%
+% We moved the definitions of \thepartno, \thesubpart, and
+% \thesubsubpart outside of the associated list environments, so that
+% the user can redefine them once at the beginning of the LaTeX file and
+% not have their redefinition overridden in every such list.
+%
+% We also replaced most occurrences of \thequestion with
+% \arabic{question}, so that the user can safely redefine \thequestion
+% to something like \Alph{question}, etc.
+%
+% We rewrote the components of the \gradetable[v][questions] and
+% \gradetable[h][questions] to use the question counter in place of
+% @iterator, and to insert \thequestion instead of \the@iterator as the
+% question number in the table (so that if the user redefines
+% \thequestion, then the table will print the question ``numbers'' (or
+% letters, etc.) in whatever format \thequestion prints the question
+% numbers on the exam).
+%
+% We also created a new command:
+%
+%   \totalpoints
+%
+% for use in the argument of a \totalformat command.  \totalpoints is
+% just an abbreviation for \pointsofquestion{\arabic{question}}.  That
+% is, it's a macro that prints the total number of points for the
+% current question.
+%
+% We changed the longsolution environment to make it easy to change the
+% amount by which the left and right margins are increased.  The default
+% amount is set by the command
+%
+%   \setlength{\longsolutionindent}{2em}
+%
+% and the user can change this by giving a new \setlength command.
+%
+% Note added later: longsolution was eliminated in version
+% 2.106$\beta$.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.097$\beta$:
+%
+% We've changed the default format for the total points for a question
+% printed by the \droptotalpoints command.  This command still prints
+% the total points for the question right justified a distance of
+% \rightpointsmargin from the right edge of the paper, but now the
+% number of points will, by default, be surrounded by either
+%
+%   a double box, if \boxedpoints is in effect,
+%   double brackets, if \bracketedpoints is in effect, or
+%   double parentheses, otherwise.
+%
+% It's still true that if you use a \totalformat command, then the
+% format of the printed total points is completely controlled by the
+% argument of the \totalformat command and the default doesn't matter at
+% all.
+%
+%
+% Note added later: We changed the default format again in version
+% 2.101$\beta$; see the notes above.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.096$\beta$:
+%
+% The labels for questions, parts, subparts, and subsubparts can now be
+% customized.  The format now depends on the commands
+%
+%   \questionlabel
+%   \partlabel
+%   \subpartlabel
+%   \subsubpartlabel
+%
+% the default definitions of which are:
+%
+%   \newcommand\questionlabel{\thequestion.}
+%   \newcommand\partlabel{(\thepartno)}
+%   \newcommand\subpartlabel{\thesubpart.}
+%   \newcommand\subsubpartlabel{\thesubsubpart)}
+%
+% These definions can be changed by using a \renewcommand command.
+% Note that the definition of \partlabel used `\thepartno', and *not*
+% `\thepart'.  This is because `\thepart' refers to the counter for the
+% standard sectioning command \part, and not the counter used in the
+% parts environment.  The counter used by the parts environment is
+% inserted with the command `\thepartno'.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.095$\beta$:
+%
+% Added solution and longsolution environments.
+%
+% The command \printanswers causes both of these environments print the
+% solution, and the command \noprintanswers causes both of these
+% environments not to print the solution.  The default is
+% \noprintanswers.
+%
+% The commands \printanswers and \noprintanswers can be given as many
+% times as desired to switch back and forth between the two.
+%
+% The documentclass option ``answers'' is equivalent to giving a
+% \printanswers command at the beginning of the file.
+%
+%
+% Both of these environments take an optional argument which is an
+% amount of blank vertical space to be left when \noprintanswers is in
+% effect.  (The default value of this blank vertical space is 0pt.)
+%
+%
+% The solution environment prints the solution inside of a box, which
+% cannot be broken across pages.  Thus, it is only appropriate for
+% solutions that are short enough to fit on a page.
+%
+% The longsolution environment prints the solution with left and right
+% margins slightly increased, and it can be broken across pages.
+%
+% When printing the solution, both environments begin with
+% \solutiontitle, the default value of which is created by the command
+%
+% \newcommand{\solutiontitle}{\textbf{Solution:}\enspace}
+%
+% This can be changed with the \renewcommand command.
+%
+% Note added later: solution was changed and longsolution was
+% eliminated in version 2.106$\beta$.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.094$\beta$:
+%
+% We've expanded the options of the \gradetable command, so that you
+% can now get a grading table indexed by either question numbers or by
+% page numbers, and in either case you can have either a horizontally
+% oriented table or a vertically oriented table.
+%
+% \gradetable now takes two optional arguments: The first can be either
+% `[v]' or `[h]', and the second can be either `[questions]' or
+% `[pages]'.  The defaults are `[v]' and `[questions]', and you must
+% specify a first option if you want to specify a second option.
+%
+% Thus: \gradetable is equivalent to \gradetable[v][questions]
+%
+% `[v]' and `[h]' are as before: Vertically oriented or horizontally
+% oriented.
+%
+% `[questions]' is the same as the earlier version: A table that lists
+% the question numbers, the possible total points for each question the
+% total for the entire exam, and spaces are left for the score on each
+% question.
+%
+% `[pages]' prints a table indexed by page numbers instead of by
+% question numbers.  It lists only the numbers of pages that have points
+% on them, and for each such page it lists the number of points possible
+% on that page.  It also lists the total possible points on the exam,
+% and spaces are left for the score on each page.
+%
+% For both tables indexed by questions and tables indexed by points,
+% there are commands that allow you to change the column and row
+% headings (the following are shown setting the default values:)
+%
+%    \hpword{Points:}
+%    \hsword{Score:}
+%    \htword{Total}
+%    \vpword{Points}
+%    \vsword{Score}
+%    \vtword{Total:}
+%
+% For tables indexed by questions, the appropriate row and column titles
+% are set by the following commands:
+%
+%    \hqword{Question:}
+%    \vqword{Question}
+%
+% For tables indexed by pages, the appropriate row and column titles are
+% set by the following commands:
+%
+%    \hpgword{Page:}
+%    \vpgword{Page}
+%
+%
+% For both \gradetable[h] and \gradetable [v], the width of the blank
+% cells created for filling in the grades can be changed with the
+% command \cellwidth, and the arraystretch applied to the table can be
+% changed with the command \gradetablestretch.  The default values are
+% created by the commands:
+%
+%   \cellwidth{2em}
+%   \gradetablestretch{1.5}
+%
+%--------------------------------------------------------------------
+%
+% Version 2.093$\beta$:
+%
+% If the user gives the comman \addpoints, then
+% \pointsonpage{n} expands to the number of points on page n.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.092$\beta$:
+%
+% Increased the \leftmargin in the choices environment.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.091$\beta$:
+%
+% New commands:
+% \pointsdroppedatright
+% \droppoints
+% \droptotalpoints
+% \totalformat
+%
+% \pointsdroppedatright: The command \pointsdroppedatright causes points
+% not to be printed until you give the command \droppoints, except that
+% a \qformat command still works as expected (i.e., if you include
+% ``\thepoints'' in the argument of the \qformat, it will print the
+% points as usual).
+%
+%
+% \droppoints: The command \droppoints should be given only at the end
+% of a paragraph or between paragraphs; if you give it within a
+% paragraph, it causes the paragraph to end.  \droppoints prints the
+% most recent point value in the right margin, formatted as it is when
+% you give the command \pointsinrightmargin, except that the points
+% appear opposite the last line of the paragraph (or, if the command
+% \droppoints is given between paragraphs, then additional vertical
+% space is left between the paragraphs and the points are printed
+% opposite the blank space).  Thus, the formatting can be changed by
+% using giving the commands \bracketedpoints, \boxedpoints, or
+% \marginpointname.
+%
+% The command \droppoints actually works this way even if one of the
+% commands \pointsdroppedatright, \pointsinmargin, or
+% \pointsinrightmargin, is in effect, but if you use it that way the
+% points will appear twice on the page.
+%
+%
+% \droptotalpoints: To use the command \droptotalpoints, you must first
+% give the command \addpoints.  The command \droptotalpoints should be
+% given only at the end of a paragraph or between paragraphs; if you
+% give it within a paragraph, it causes the paragraph to end.
+% \droptotalpoints prints the total points for the current question
+% (i.e., the sum of the points assigned to the question and to all of
+% its parts, subparts, and subsubparts) in the right margin, formatted
+% formatted by default inside either double brackets, double box, or
+% double parentheses, depending on whether \bracketedpoints,
+% \boxedpoints, or neither is in effect.
+%
+% \totalformat: The \totalformat command allows you to change the format
+% used by the \droptotalpoints command.  It takes one argument, and that
+% argument becomes the command to print the total points, right
+% justified a distance of \rightpointsmargin from the right edge of the
+% paper.  The argument should contain the expression
+% ``\pointsofquestion{\arabic{question}}'' at the point at which the number
+% of points should appear.  For example, the command
+%
+%   \totalformat{[\pointsofquestion{\arabic{question}}]}
+%
+% will produce the same appearance as the default does when the command
+% \bracketedpoints is in effect and \marginpointname is empty, and the
+% command
+%
+%   \totalformat{\fbox{Total: \pointsofquestion{\arabic{question}}}}
+%
+% produces a box surrounding ``Total: 25''.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.087$\beta$:
+%
+% We changed ``\point@toks={}'' into ``\global \point@toks={}'' when
+% \point@toks is set, so that if the user somehow arranges for us to be
+% inside of a group when we enter horizontal mode, the \point@toks will
+% be properly set equal to null, and so the points won't accidentally be
+% placed a second time at the second paragraph of the question.
+%
+% Similarly, we changed ``\pageinfo@commands={}'' to 
+% ``\global \pageinfo@commands={}''.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.080$\beta$:
+%
+% We added a new command \gradetable that produces a grading table,
+% oriented either vertically or horizontally, that lists the questions,
+% their point values, and the total points, and leaves spaces for
+% entering the grade for each question and the total grade.  We also
+% added a new command \pointsofquestion that takes one argument that is
+% assumed to be the number of a question and returns the total number of
+% points for that question.  \pointsofquestion is used by the
+% \gradetable command, but the user can choose to use it separately.
+
+% To use either \gradetable or \pointsofquestion, the user must give the
+% command \addpoints.  \pointsofquestion{n} will then return the total
+% number of points for question n and all of its parts, subparts, and
+% subsubparts.  Since all this information is stored in the .aux file
+% and then read back on the next run of LaTeX, the user must run LaTeX
+% twice after any changes to the questions or points.
+
+% \gradetable[h] produces a horizonatlly oriented grade table, and
+% \gradetable[v] produces a vertically oriented grade table.  The
+% command \gradetable is equivalent to \gradetable[v].
+
+% \gradetable[h] produces a table with three rows, titled (by default)
+% ``Question:'', ``Points:'', and ``Score:'' (the titles are in the
+% first column of the table).  There is then one column for each
+% question (with the question number and point value in the first two
+% rows), plus a final column labelled ``Total'' with the total points in
+% the second row.
+
+% \gradetable[v] produces a table with three columns, titled (by
+% default) ``Question'', ``Points'', and ``Score'' (the titles are in
+% the first row of the table).  There is then one row for each question
+% (with the question number and point value in the first two columns),
+% plus a final row labelled ``Total:'' with the total points in the
+% second column.
+
+% Note that \gradetable[h] produces row titles whose default values
+% contains colons, while \gradetable[v] produces column titles whose
+% default values do not contain colons.
+
+% The row and column titles and the word ``Total'' can be changed using
+% the commands \hqword, \hpword, \hsword, \htword, \vqword,
+% \vpword, \vsword, and \vtword, where the first four affect
+% \gradetable[h] and the second four affect \gradetable[v].  The default
+% values are created by the commands:
+
+%   \hqword{Question:}
+%   \hpword{Points:}
+%   \hsword{Score:}
+%   \htword{Total}
+%   \vqword{Question}
+%   \vpword{Points}
+%   \vsword{Score}
+%   \vtword{Total:}
+
+% For both \gradetable[h] and \gradetable [v], the width of the blank
+% cells created for filling in the grades can be changed with the
+% command \cellwidth, and the arraystretch applied to the table can be
+% changed with the command \gradetablestretch.  The default values are
+% created by the commands:
+
+%   \cellwidth{2em}
+%   \gradetablestretch{1.5}
+
+
+
+% Changing the definition of \points:
+
+% The default definition of \points is that it expands to ``point'' if
+% the number of points is 1 and to ``points'' otherwise.  There is now a
+% command ``\pointpoints'' that takes two arguments, after which
+% \points will expand to the first argument when the number of points is
+% 1 and to the second argument otherwise.  For example, the default is
+% the result of the command \pointpoints{point}{points}.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.070$\beta$:
+%
+% We made this compatible with hyperref.sty.
+% We did this by eliminating all use of LaTeX's 
+% \label, \newlabel, \ref, and \pageref commands.
+% We now put information into the .aux file using the
+% \PgInfo@write command, and get that info out of the aux file
+% using \PgInfo and \PgInfo@get, along with a few \gdef commands
+% written straight to the .aux file.
+%
+%--------------------------------------------------------------------
+%
+% Version 2.067$\beta$:
+%
+% We're adding code to enable headers and footers
+% to know whether the current page continues a question started on an
+% earlier page, and whether the page ends with a question still
+% incomplete.
+
+%--------------------------------------------------------------------
+% For use in headers and footers:
+%
+% \ifcontinuation{Text 1}{Text 2}
+% Expands to ``Text 1'' if this page begins with a part or subpart or
+% subsubpart that continues a question begun on an earlier page, and
+% expands to ``Text 2'' if this page begins with a new question.
+%
+% \ContinuedQuestion expands to the number of the question that is
+% being continued from an earlier page.
+%
+% \ifincomplete{Text 1}{Text 2}
+% Expands to ``Text 1'' if the last question begun on or before this
+% page has a part, subpart, or subsubpart that begins on a later page,
+% and if we have not yet encountered a \nomorequestions command.
+%
+% \IncompleteQuestion expands to the number of the question that is
+% continued on the next page.
+%
+% \nomorequestions is a command that you can give after the last
+% question if you intend to include extra material (e.g., tables for
+% use on the exam) but you don't want the pages containing the extra
+% material to be labelled as continuing the last question on the exam.
+%
+%--------------------------------------------------------------------
+%
+%
+% Also: 
+% Changed the code for headers and footers to
+% use the command \normalfont instead of \rm so that the main
+% document font will appear in headers and footers even when the
+% main document font is *not* a roman font.
+%
+% \def\marksnotpoints
+%
+% Changes \pointname so that it is identical to the default \pointname
+% except that the work ``mark'' is used instead of the word
+% ``point''.  That is, if the number of points is 1, then you'll get
+% ``1 mark'', and if the number of points is other than 1 then you'll
+% get ``n marks'' (where n is the number of points).
+%
+%
+% \bracketedpoints
+% \nobracketedpoints
+%
+% The default remains to put the points inside of parentheses.
+% \bracketedpoints switches to points inside of square brackets and
+% \boxedpoints switches to points in side of a box.  Both
+% \nobracketedpoints and \noboxedpoints return to the default of
+% points inside of parentheses no matter how many \boxedpoints and
+% \bracketedpoints commands have been given in any order.
+%
+%
+% \pointsinrightmargin
+% \nopointsinrightmargin
+%
+% The default remains to put the points right after the question
+% number, before the text of the question. \pointsinrightmargin
+% switches to points in the right margin and \pointsinleftmargin
+% switches to points in the left margin.  Both \nopointsinrightmargin
+% and \nopointsinleftmargin return to the default of points right
+% after the question number, before the text of the question, no
+% matter how many \pointsinrightmargin and \pointsinleftmargin
+% commands have been given in any order. 
+%
+% if \pointsinrightmargin is used, then the points are printed
+% right justified in the right margin, with the right edge a distance
+% of \rightpointsmargin from the right edge of the paper.
+% The default value of \rightpointsmargin is 1 cm, but it can be set
+% to any other length with the usual \setlength command
+% (as in \setlength{\rightpointsmargin}{0.5cm}).
+%
+%
+% subsubparts environment
+% Numbered using lower case greek letters.
+%
+%
+% choices environment, for multiple choice answers
+%
+%
+% \qformat{Format line}
+% 
+% Format line must have some stretch (e.g., at least one \hfil or
+% \dotfill or something similar).
+% \thequestion inserts the question number,
+% \thepoints inserts the number of points followed by pointname if
+%   a number of points has been specified for this question, and it
+%   inserts nothing at all if no points have been specified.
+%
+% \noqformat returns to the standard question number formatting.
+%
+%
+%
+% The standard options
+%   a4paper
+%   a5paper
+%   b5paper
+%   letterpaper
+%   legalpaper
+%   executivepaper
+%   landscape
+% now all work.
+%
+%
+%
+% Two new commands for use in \pointname, \marginpointname, and
+% \qformat: 
+%
+% \points expands to either ``point'' or ``points'', depending on
+% whether the number of points is 1 or other than 1.
+%
+% \marks expands to either ``mark'' or ``marks'', depending on
+% whether the number of points is 1 or other than 1.
+%
+%
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%
+% The only change from version 2.0 to version 2.01 is that this
+% documentclass (and its accompanying documentation) is now
+% explicitly distributed under the LaTeX Project Public License.
+%
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+
+\NeedsTeXFormat{LaTeX2e}
+
+\ProvidesClass{exam}[\filedate\space Version \fileversion\space by
+  Philip Hirschhorn]
+
+\RequirePackage{ifthen}
+
+\newif\if@printanswers
+\@printanswersfalse
+\DeclareOption{answers}{\@printanswerstrue}
+\DeclareOption{noanswers}{\@printanswersfalse}
+
+\DeclareOption*{%
+  \PassOptionsToClass{\CurrentOption}{article}%
+}
+\ProcessOptions\relax
+\LoadClass{article}
+
+
+
+
+%                         *****************
+%                         ** PAGE LAYOUT **
+%                         *****************
+
+
+% We set the parameters in terms of \paperwidth and \paperheight
+% so that the options
+
+% a4paper
+% a5paper
+% b5paper
+% letterpaper
+% legalpaper
+% executivepaper
+% landscape
+
+% will all work:
+
+\setlength{\textwidth}{\paperwidth}
+\addtolength{\textwidth}{-2in}
+\setlength{\oddsidemargin}{0pt}
+\setlength{\evensidemargin}{0pt}
+
+\setlength{\headheight}{15pt}
+\setlength{\headsep}{15pt}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\footskip}{29pt}
+\setlength{\textheight}{\paperheight}
+\addtolength{\textheight}{-2.2in}
+
+\setlength{\marginparwidth}{.5in}
+\setlength{\marginparsep}{5pt}
+
+
+
+
+
+%--------------------------------------------------------------------
+
+%                          ****************
+%                          ** EXTRAWIDTH **
+%                          ****************
+
+\newlength\@extrawidth
+
+% \@rightmargin is needed for \pointsinrightmargin and
+% \pointsdroppedatright, so that we can right justify the points:
+\newlength\@rightmargin
+\setlength{\@rightmargin}{1in}
+
+% We put the argument of \extrawidth into a length so that it will
+% work correctly even if it's negative:
+
+\def\extrawidth#1{%
+  \@extrawidth=#1
+  \advance \textwidth by \@extrawidth
+  \divide\@extrawidth by 2
+  \advance\oddsidemargin by -\@extrawidth
+  \advance\evensidemargin by -\@extrawidth
+  % Bug fix, 13 April 2004: 
+  %\advance\@rightmargin by \@extrawidth
+  \advance\@rightmargin by -\@extrawidth
+}
+
+
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%             Making room for large headers and footers
+
+% The following are used to save the effect of any changes to 
+% \topmargin and \textheight caused by \extraheadheight or
+% \extrafootheight commands.  They hold the values currently in effect.
+% We put them into lengths so that it will work correctly even if the
+% argument is negative:
+
+\newlength\@extrahead
+\newlength\@extrafoot
+\setlength{\@extrahead}{0in}
+\setlength{\@extrafoot}{0in}
+
+% The following are used to hold the requested values for extrahead and
+% extrafoot, first page and all pages after the first, and then the
+% similar things requested for the cover pages:
+\newlength\run@exhd
+\newlength\fp@exhd
+\newlength\run@exft
+\newlength\fp@exft
+\newlength\covrun@exhd
+\newlength\covfp@exhd
+\newlength\covrun@exft
+\newlength\covfp@exft
+
+\setlength{\run@exhd}{0in}
+\setlength{\fp@exhd}{0in}
+\setlength{\run@exft}{0in}
+\setlength{\fp@exft}{0in}
+\setlength{\covrun@exhd}{0in}
+\setlength{\covfp@exhd}{0in}
+\setlength{\covrun@exft}{0in}
+\setlength{\covfp@exft}{0in}
+
+
+\newcommand*\adj@hdht@ftht{%
+  \if@coverpages
+    \ifnum\value{page}=1
+      \@setheadheight{\covfp@exhd}%
+      \@setfootheight{\covfp@exft}%
+    \else
+      \@setheadheight{\covrun@exhd}%
+      \@setfootheight{\covrun@exft}%
+    \fi
+  \else
+    \ifnum\value{page}=1
+      \@setheadheight{\fp@exhd}%
+      \@setfootheight{\fp@exft}%
+    \else
+      \@setheadheight{\run@exhd}%
+      \@setfootheight{\run@exft}%
+    \fi
+  \fi
+}
+
+
+\newcommand*\extraheadheight{%
+  \@ifnextchar[{\@xtrahd}{\@ytrahd}%
+}
+
+\def\@xtrahd[#1]#2{%
+  \setlength{\fp@exhd}{#1}%
+  \setlength{\run@exhd}{#2}%
+  \adj@hdht@ftht
+}
+
+\def\@ytrahd#1{%
+  \setlength{\fp@exhd}{#1}%
+  \setlength{\run@exhd}{#1}%
+  \adj@hdht@ftht
+}
+
+\newcommand*\extrafootheight{%
+  \@ifnextchar[{\@xtraft}{\@ytraft}%
+}
+
+\def\@xtraft[#1]#2{%
+  \setlength{\fp@exft}{#1}%
+  \setlength{\run@exft}{#2}%
+  \adj@hdht@ftht
+}
+
+\def\@ytraft#1{%
+  \setlength{\fp@exft}{#1}%
+  \setlength{\run@exft}{#1}%
+  \adj@hdht@ftht
+}
+
+
+\newcommand*\coverextraheadheight{%
+  \@ifnextchar[{\cov@xtrahd}{\cov@ytrahd}%
+}
+
+\def\cov@xtrahd[#1]#2{%
+  \setlength{\covfp@exhd}{#1}%
+  \setlength{\covrun@exhd}{#2}%
+  \adj@hdht@ftht
+}
+
+\def\cov@ytrahd#1{%
+  \setlength{\covfp@exhd}{#1}%
+  \setlength{\covrun@exhd}{#1}%
+  \adj@hdht@ftht
+}
+
+\newcommand*\coverextrafootheight{%
+  \@ifnextchar[{\cov@xtraft}{\cov@ytraft}%
+}
+
+\def\cov@xtraft[#1]#2{%
+  \setlength{\covfp@exft}{#1}%
+  \setlength{\covrun@exft}{#2}%
+  \adj@hdht@ftht
+}
+
+\def\cov@ytraft#1{%
+  \setlength{\covfp@exft}{#1}%
+  \setlength{\covrun@exft}{#1}%
+  \adj@hdht@ftht
+}
+
+\def\@appendoutput#1{%
+  \output=\expandafter{\the\output #1}%
+}
+
+\@appendoutput{\adj@hdht@ftht}
+
+%--------------------------------------------------------------------
+%                 \setheadheight and \setfootheight:
+
+\def\@setheadheight#1{%
+  \begingroup % Avoid trouble from using \@temp and \@spaces
+    % Reset the effect of the most recent change:
+    \global\advance\topmargin by -\@extrahead
+    \global\advance\textheight by \@extrahead
+    % Save the newly set value:
+    \def\@temp{#1}
+    \def\@spaces{ }
+    \ifx\@temp\@empty
+      \global\@extrahead=0in
+    \else
+      \ifx\@temp\@spaces
+        \global\@extrahead=0in
+      \else
+        \global\@extrahead=#1
+      \fi
+    \fi
+    % Set the new values:
+    \global\advance\topmargin by \@extrahead
+    \global\advance\textheight by -\@extrahead
+    % Make it take effect RIGHT NOW!:
+    % (The following stuff isn't necessary if \@setheadheight is
+    % executed only in the preamble or as we return from the output
+    % routine, but we're leaving it in so that this will still work if
+    % we use this at some random point in the middle of composing a
+    % page). 
+    \global\@colht=\textheight
+    \global\@colroom=\textheight
+    \global\vsize=\textheight
+    \global\pagegoal=\textheight
+  \endgroup
+}
+
+\def\@setfootheight#1{%
+  \begingroup % Avoid trouble from using \@temp and \@spaces
+    % Reset the effect of the most recent change:
+    \global\advance\textheight by \@extrafoot
+    % Save the newly set value:
+    \def\@temp{#1}
+    \def\@spaces{ }
+    \ifx\@temp\@empty
+      \global\@extrafoot=0in
+    \else
+      \ifx\@temp\@spaces
+        \global\@extrafoot=0in
+      \else
+        \global\@extrafoot=#1
+      \fi
+    \fi
+    % Set the new values:
+    \global\advance\textheight by -\@extrafoot
+    % Make it take effect RIGHT NOW!:
+    % (The following stuff isn't necessary if \@setfootheight is
+    % executed only in the preamble or as we return from the output
+    % routine, but we're leaving it in so that this will still work if
+    % we use this at some random point in the middle of composing a
+    % page). 
+    \global\@colht=\textheight
+    \global\@colroom=\textheight
+    \global\vsize=\textheight
+    \global\pagegoal=\textheight
+  \endgroup
+}
+
+
+
+
+%---------------------------------------------------------------------
+%
+%                      *************************
+%                      ** HEADERS AND FOOTERS **
+%                      *************************
+% 
+% The pagestyles available are head, foot, headandfoot, and empty.
+% \pagestyle{head} prints the head, and gives an empty foot.
+% \pagestyle{foot} prints the foot, and gives an empty head.
+% \pagestyle{headandfoot} prints both the head and the foot.
+% \pagestyle{empty} gives an empty head and an empty foot.
+% 
+
+%                            Pagestyles:
+
+\newcommand*\ps@head{%
+  \@dohead
+  \@nofoot
+}
+
+\newcommand*\ps@headandfoot{%
+  \@dohead
+  \@dofoot
+}
+
+\newcommand*\ps@foot{%
+  \@nohead
+  \@dofoot
+}
+
+% \ps@empty is already defined by article.cls, so we'll
+% say \def instead of \newcommand*:
+\def\ps@empty{%
+  \@nohead
+  \@nofoot
+}
+
+\newif\if@coverpages
+\@coverpagesfalse
+
+\newenvironment{coverpages}{%
+    \ifnum \value{numquestions}>0
+      \ClassError{exam}{%
+        Coverpages cannot be used after questions have begun.\MessageBreak
+      }{%
+        All question, part, subpart, and subsubpart environments
+        \MessageBreak
+        must begin after the cover pages are complete.\MessageBreak
+      }%
+    \fi
+    \@coverpagestrue
+    \pagenumbering{roman}%
+    \adj@hdht@ftht
+  }{%
+    \clearpage
+    \pagenumbering{arabic}%
+    \adj@hdht@ftht
+}
+
+\newcommand*\cover@question@error{%
+  \ClassError{exam}{%
+    No questions are allowed in the cover pages.\MessageBreak
+  }{%
+    All question, part, subpart, and subsubpart environments
+    \MessageBreak
+    must begin after the cover pages are complete.\MessageBreak
+  }%
+}
+
+
+
+\newcommand*\@dohead{%
+  \def\@oddhead{%
+    \if@coverpages
+      \ifnum\value{page}=1
+        \cov@fullhead
+      \else
+        \covrun@fullhead
+      \fi
+    \else
+      \ifnum\value{page}=1
+        \@fullhead
+      \else
+        \run@fullhead
+      \fi
+    \fi
+  }% @oddhead
+  \let\@evenhead=\@oddhead
+}
+
+\newcommand*\@dofoot{%
+  \def\@oddfoot{%
+    \if@coverpages
+      \ifnum\value{page}=1
+        \cov@fullfoot
+      \else
+        \covrun@fullfoot
+      \fi
+    \else
+      \ifnum\value{page}=1
+        \@fullfoot
+      \else
+        \run@fullfoot
+      \fi
+    \fi
+  }% @oddfoot
+  \let\@evenfoot=\@oddfoot
+}
+
+\newcommand*\@nohead{%
+  \def\@oddhead{}%
+  \let\@evenhead=\@oddhead
+}
+
+\newcommand*\@nofoot{%
+  \def\@oddfoot{}%
+  \let\@evenfoot=\@oddfoot
+}
+
+
+
+
+%--------------------------------------------------------------------
+%       \@fullhead, \run@fullhead, \@fullfoot, and \run@fullfoot:
+
+\newcommand*\@fullhead{%
+  \vbox to \headheight{%
+    \vss
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\@lhead\strut}}%
+        \hss\parbox[b]{\textwidth}{\centering\@chead\strut}\hss
+        \llap{\parbox[b]{\textwidth}{\raggedleft\@rhead\strut}}%
+    }% hbox
+    \if@headrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+  }% vbox
+}
+
+
+\newcommand*\run@fullhead{%
+  \vbox to \headheight{%
+    \vss
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\run@lhead\strut}}%
+        \hss\parbox[b]{\textwidth}{\centering\run@chead\strut}\hss
+        \llap{\parbox[b]{\textwidth}{\raggedleft\run@rhead\strut}}%
+    }% hbox
+    \ifrun@headrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+  }% vbox
+}
+
+
+
+% We arrange it so that the very top of first line of text in the
+% foot is at a fixed position on the page, whether or not there's
+% a footrule:
+
+\newcommand*\@fullfoot{%
+  \vbox to 0pt{%
+    \if@footrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+    \vskip 3pt
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\@lfoot}}%
+        \hss\parbox[t]{\textwidth}{\centering\@cfoot}\hss
+        \llap{\parbox[t]{\textwidth}{\raggedleft\@rfoot}}%
+    }% hbox
+    \vss
+  }% vbox
+}
+
+
+\newcommand*\run@fullfoot{%
+  \vbox to 0pt{%
+    \ifrun@footrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+    \vskip 3pt
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\run@lfoot}}%
+        \hss\parbox[t]{\textwidth}{\centering\run@cfoot}\hss
+        \llap{\parbox[t]{\textwidth}{\raggedleft\run@rfoot}}%
+    }% hbox
+    \vss
+  }% vbox
+}
+
+%--------------------------------------------------------------------
+%       \cov@fullhead, \covrun@fullhead, \cov@fullfoot, and
+%       \covrun@fullfoot: 
+
+\newcommand*\cov@fullhead{%
+  \vbox to \headheight{%
+    \vss
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\cov@lhead\strut}}%
+        \hss\parbox[b]{\textwidth}{\centering\cov@chead\strut}\hss
+        \llap{\parbox[b]{\textwidth}{\raggedleft\cov@rhead\strut}}%
+    }% hbox
+    \ifcov@headrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+  }% vbox
+}
+
+
+\newcommand*\covrun@fullhead{%
+  \vbox to \headheight{%
+    \vss
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\covrun@lhead\strut}}%
+        \hss\parbox[b]{\textwidth}{\centering\covrun@chead\strut}\hss
+        \llap{\parbox[b]{\textwidth}{\raggedleft\covrun@rhead\strut}}%
+    }% hbox
+    \ifcovrun@headrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+  }% vbox
+}
+
+
+
+% We arrange it so that the very top of first line of text in the
+% foot is at a fixed position on the page, whether or not there's
+% a footrule:
+
+\newcommand*\cov@fullfoot{%
+  \vbox to 0pt{%
+    \ifcov@footrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+    \vskip 3pt
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\cov@lfoot}}%
+        \hss\parbox[t]{\textwidth}{\centering\cov@cfoot}\hss
+        \llap{\parbox[t]{\textwidth}{\raggedleft\cov@rfoot}}%
+    }% hbox
+    \vss
+  }% vbox
+}
+
+
+\newcommand*\covrun@fullfoot{%
+  \vbox to 0pt{%
+    \ifcovrun@footrule
+      \hrule
+    \else
+      % an invisible hrule, to keep positioning constant:
+      \hrule width 0pt
+    \fi
+    \vskip 3pt
+    \hbox to \textwidth{%
+      \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\covrun@lfoot}}%
+        \hss\parbox[t]{\textwidth}{\centering\covrun@cfoot}\hss
+        \llap{\parbox[t]{\textwidth}{\raggedleft\covrun@rfoot}}%
+    }% hbox
+    \vss
+  }% vbox
+}
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%
+%            ********************************************
+%            ** COMMANDS TO DEFINE HEADERS AND FOOTERS **
+%            ********************************************
+%
+% \lhead[#1]{#2} sets the first page left head to #1, and the
+%   running left head to #2
+% 
+% \lhead{#1} sets both the first page left head and the running
+%   left head to #1
+% 
+% \chead, \rhead, \lfoot, \cfoot, and \rfoot work similarly.
+% 
+% 
+% \@lhead is the left head for Page 1
+% \run@lhead is the running left head
+% (i.e., for all pages other than the first)
+% 
+% \@chead is the center head for Page 1
+% \run@chead is the running center head
+% (i.e., for all pages other than the first)
+% 
+% etc.
+% 
+% Alternative commands are:
+% \firstpageheader{LEFT}{CENTER}{RIGHT}
+% \runningheader{LEFT}{CENTER}{RIGHT}
+% or
+% \header{LEFT}{CENTER}{RIGHT}
+% which is equivalent to the two commands
+%          \firstpageheader{LEFT}{CENTER}{RIGHT}
+%          \runningheader{LEFT}{CENTER}{RIGHT}
+% 
+% Alternative commands are:
+% \firstpagefooter{LEFT}{CENTER}{RIGHT}
+% \runningfoother{LEFT}{CENTER}{RIGHT}
+% or
+% \footer{LEFT}{CENTER}{RIGHT}
+% which is equivalent to the two commands
+%          \firstpagefooter{LEFT}{CENTER}{RIGHT}
+%          \runningfoother{LEFT}{CENTER}{RIGHT}
+
+\def\firstpageheader#1#2#3{%
+  \def\@lhead{#1}%
+  \def\@chead{#2}%
+  \def\@rhead{#3}%
+}
+
+\def\runningheader#1#2#3{%
+  \def\run@lhead{#1}%
+  \def\run@chead{#2}%
+  \def\run@rhead{#3}%
+}
+
+\def\header#1#2#3{%
+  \firstpageheader{#1}{#2}{#3}%
+  \runningheader{#1}{#2}{#3}%
+}
+
+
+\def\firstpagefooter#1#2#3{%
+  \def\@lfoot{#1}%
+  \def\@cfoot{#2}%
+  \def\@rfoot{#3}%
+}
+
+\def\runningfooter#1#2#3{%
+  \def\run@lfoot{#1}%
+  \def\run@cfoot{#2}%
+  \def\run@rfoot{#3}%
+}
+
+\def\footer#1#2#3{%
+  \firstpagefooter{#1}{#2}{#3}%
+  \runningfooter{#1}{#2}{#3}%
+}
+
+
+
+\def\lhead{\@ifnextchar[{\@xlhead}{\@ylhead}}
+\def\@xlhead[#1]#2{\def\@lhead{#1}\def\run@lhead{#2}}
+\def\@ylhead#1{\def\run@lhead{#1}\def\@lhead{#1}}
+
+\def\chead{\@ifnextchar[{\@xchead}{\@ychead}}
+\def\@xchead[#1]#2{\def\@chead{#1}\def\run@chead{#2}}
+\def\@ychead#1{\def\run@chead{#1}\def\@chead{#1}}
+
+\def\rhead{\@ifnextchar[{\@xrhead}{\@yrhead}}
+\def\@xrhead[#1]#2{\def\@rhead{#1}\def\run@rhead{#2}}
+\def\@yrhead#1{\def\run@rhead{#1}\def\@rhead{#1}}
+
+\def\lfoot{\@ifnextchar[{\@xlfoot}{\@ylfoot}}
+\def\@xlfoot[#1]#2{\def\@lfoot{#1}\def\run@lfoot{#2}}
+\def\@ylfoot#1{\def\run@lfoot{#1}\def\@lfoot{#1}}
+
+\def\cfoot{\@ifnextchar[{\@xcfoot}{\@ycfoot}}
+\def\@xcfoot[#1]#2{\def\@cfoot{#1}\def\run@cfoot{#2}}
+\def\@ycfoot#1{\def\run@cfoot{#1}\def\@cfoot{#1}}
+
+\def\rfoot{\@ifnextchar[{\@xrfoot}{\@yrfoot}}
+\def\@xrfoot[#1]#2{\def\@rfoot{#1}\def\run@rfoot{#2}}
+\def\@yrfoot#1{\def\run@rfoot{#1}\def\@rfoot{#1}}
+
+
+%                    Initialize head and foot:
+
+
+
+\pagestyle{headandfoot}
+
+\lhead{}
+\chead{}
+\rhead{}
+\lfoot{}
+\cfoot[]{Page \thepage}
+\rfoot{}
+
+%--------------------------------------------------------------------
+%                    Coverpage headers and footers
+%
+% \coverlhead[#1]{#2} sets the first cover page left head to #1, and the
+%   running cover left head to #2
+% 
+% \coverlhead{#1} sets both the first cover page left head and the running
+%   cover left head to #1
+% 
+% \coverchead, \coverrhead, \coverlfoot, \covercfoot, and \coverrfoot
+% work similarly.
+% 
+% 
+% \cov@lhead is the left head for Page 1
+% \covrun@lhead is the running left head
+% (i.e., for all pages other than the first)
+% 
+% \cov@chead is the center head for Page 1
+% \covrun@chead is the running center head
+% (i.e., for all pages other than the first)
+% 
+% etc.
+% 
+% Alternative commands are:
+% \coverfirstpageheader{LEFT}{CENTER}{RIGHT}
+% \coverrunningheader{LEFT}{CENTER}{RIGHT}
+% or
+% \coverheader{LEFT}{CENTER}{RIGHT}
+% which is equivalent to the two commands
+%          \coverfirstpageheader{LEFT}{CENTER}{RIGHT}
+%          \coverrunningheader{LEFT}{CENTER}{RIGHT}
+% 
+% Alternative commands are:
+% \coverfirstpagefooter{LEFT}{CENTER}{RIGHT}
+% \coverrunningfoother{LEFT}{CENTER}{RIGHT}
+% or
+% \coverfooter{LEFT}{CENTER}{RIGHT}
+% which is equivalent to the two commands
+%          \coverfirstpagefooter{LEFT}{CENTER}{RIGHT}
+%          \coverrunningfoother{LEFT}{CENTER}{RIGHT}
+
+\def\coverfirstpageheader#1#2#3{%
+  \def\cov@lhead{#1}%
+  \def\cov@chead{#2}%
+  \def\cov@rhead{#3}%
+}
+
+\def\coverrunningheader#1#2#3{%
+  \def\covrun@lhead{#1}%
+  \def\covrun@chead{#2}%
+  \def\covrun@rhead{#3}%
+}
+
+\def\coverheader#1#2#3{%
+  \coverfirstpageheader{#1}{#2}{#3}%
+  \coverrunningheader{#1}{#2}{#3}%
+}
+
+
+\def\coverfirstpagefooter#1#2#3{%
+  \def\cov@lfoot{#1}%
+  \def\cov@cfoot{#2}%
+  \def\cov@rfoot{#3}%
+}
+
+\def\coverrunningfooter#1#2#3{%
+  \def\covrun@lfoot{#1}%
+  \def\covrun@cfoot{#2}%
+  \def\covrun@rfoot{#3}%
+}
+
+\def\coverfooter#1#2#3{%
+  \coverfirstpagefooter{#1}{#2}{#3}%
+  \coverrunningfooter{#1}{#2}{#3}%
+}
+
+
+
+\def\coverlhead{\@ifnextchar[{\cov@xlhead}{\cov@ylhead}}
+\def\cov@xlhead[#1]#2{\def\cov@lhead{#1}\def\covrun@lhead{#2}}
+\def\cov@ylhead#1{\def\covrun@lhead{#1}\def\cov@lhead{#1}}
+
+\def\coverchead{\@ifnextchar[{\cov@xchead}{\cov@ychead}}
+\def\cov@xchead[#1]#2{\def\cov@chead{#1}\def\covrun@chead{#2}}
+\def\cov@ychead#1{\def\covrun@chead{#1}\def\cov@chead{#1}}
+
+\def\coverrhead{\@ifnextchar[{\cov@xrhead}{\cov@yrhead}}
+\def\cov@xrhead[#1]#2{\def\cov@rhead{#1}\def\covrun@rhead{#2}}
+\def\cov@yrhead#1{\def\covrun@rhead{#1}\def\cov@rhead{#1}}
+
+\def\coverlfoot{\@ifnextchar[{\cov@xlfoot}{\cov@ylfoot}}
+\def\cov@xlfoot[#1]#2{\def\cov@lfoot{#1}\def\covrun@lfoot{#2}}
+\def\cov@ylfoot#1{\def\covrun@lfoot{#1}\def\cov@lfoot{#1}}
+
+\def\covercfoot{\@ifnextchar[{\cov@xcfoot}{\cov@ycfoot}}
+\def\cov@xcfoot[#1]#2{\def\cov@cfoot{#1}\def\covrun@cfoot{#2}}
+\def\cov@ycfoot#1{\def\covrun@cfoot{#1}\def\cov@cfoot{#1}}
+
+\def\coverrfoot{\@ifnextchar[{\cov@xrfoot}{\cov@yrfoot}}
+\def\cov@xrfoot[#1]#2{\def\cov@rfoot{#1}\def\covrun@rfoot{#2}}
+\def\cov@yrfoot#1{\def\covrun@rfoot{#1}\def\cov@rfoot{#1}}
+
+
+%                 Initialize coverpage head and foot:
+
+
+\coverlhead{}
+\coverchead{}
+\coverrhead{}
+\coverlfoot{}
+\covercfoot{}
+\coverrfoot{}
+
+
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+
+%                      Headrules and footrules:
+
+\newif\if@headrule
+\newif\ifrun@headrule
+
+\def\firstpageheadrule{\@headruletrue}
+\def\nofirstpageheadrule{\@headrulefalse}
+
+\def\runningheadrule{\run@headruletrue}
+\def\norunningheadrule{\run@headrulefalse}
+
+\def\headrule{\@headruletrue\run@headruletrue}
+\def\noheadrule{\@headrulefalse\run@headrulefalse}
+
+
+
+\newif\if@footrule
+\newif\ifrun@footrule
+
+\def\firstpagefootrule{\@footruletrue}
+\def\nofirstpagefootrule{\@footrulefalse}
+
+\def\runningfootrule{\run@footruletrue}
+\def\norunningfootrule{\run@footrulefalse}
+
+\def\footrule{\@footruletrue\run@footruletrue}
+\def\nofootrule{\@footrulefalse\run@footrulefalse}
+
+
+
+%                             Initialize:
+
+\noheadrule
+\nofootrule
+
+
+%                 Cover page headrules and footrules:
+
+\newif\ifcov@headrule
+\newif\ifcovrun@headrule
+
+\def\coverfirstpageheadrule{\cov@headruletrue}
+\def\nocoverfirstpageheadrule{\cov@headrulefalse}
+
+\def\coverrunningheadrule{\covrun@headruletrue}
+\def\nocoverrunningheadrule{\covrun@headrulefalse}
+
+\def\coverheadrule{\cov@headruletrue\covrun@headruletrue}
+\def\nocoverheadrule{\cov@headrulefalse\covrun@headrulefalse}
+
+
+
+\newif\ifcov@footrule
+\newif\ifcovrun@footrule
+
+\def\coverfirstpagefootrule{\cov@footruletrue}
+\def\nocoverfirstpagefootrule{\cov@footrulefalse}
+
+\def\coverrunningfootrule{\covrun@footruletrue}
+\def\nocoverrunningfootrule{\covrun@footrulefalse}
+
+\def\coverfootrule{\cov@footruletrue\covrun@footruletrue}
+\def\nocoverfootrule{\cov@footrulefalse\covrun@footrulefalse}
+
+
+
+%                             Initialize:
+
+\nocoverheadrule
+\nocoverfootrule
+
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+
+%                \numpages, \iflastpage, and \oddeven
+%     Also: \numpoints, \numquestions, \numparts, and \numsubparts
+%                    Also also: \pointsofquestion
+
+% Make the number of pages available as the macro \numpages,
+% the number of points as \numpoints,
+% the number of questions as \numquestions,
+% the number of parts as \numparts, and
+% the number of subparts as \numsubparts
+%\def\numpages{\pageref{@lastpage}}
+%\def\numpoints{\pageref{@numpoints}}
+%\def\numquestions{\pageref{@numquestions}}
+%\def\numparts{\pageref{@numparts}}
+%\def\numsubparts{\pageref{@numsubparts}}
+%\def\numsubsubparts{\pageref{@numsubsubparts}}
+
+% This was previously done with \pageref commands.  When I eliminated
+% all \label, \ref, and \pageref commands in order to make this
+% compatible with hyperref.sty, this stuff was created:
+
+% \gdef commands for exam@lastpage, exam@numpoints, exam@numquestions,
+% exam@numparts, exam@numsubparts and exam@numsubsubparts are written to
+% the .aux file via \AtEndDocument.
+
+% \gdef commands for pointsofq@i, pointsofq@ii, etc. are written to the
+% .aux file as each question is completed (see the definition of the
+% questions environment).
+
+% \gdef commands for pointsonpage@i, pointsonpage@ii, etc. are written
+% to the .aux file as we encounter points defined for a later page, and
+% for the last such page with AtEndDocument.
+
+\def\numpages{\@ifundefined{exam@lastpage}%
+  {\mbox{\normalfont\bf ??}}%
+  \exam@lastpage
+}
+
+\def\numpoints{\@ifundefined{exam@numpoints}%
+  {\mbox{\normalfont\bf ??}}%
+  \exam@numpoints
+}
+
+\def\numquestions{\@ifundefined{exam@numquestions}%
+  {\mbox{\normalfont\bf ??}}%
+  \exam@numquestions
+}
+
+\def\numparts{\@ifundefined{exam@numparts}%
+  {\mbox{\normalfont\bf ??}}%
+  \exam@numparts
+}
+
+\def\numsubparts{\@ifundefined{exam@numsubparts}%
+  {\mbox{\normalfont\bf ??}}%
+  \exam@numsubparts
+}
+
+\def\numsubsubparts{\@ifundefined{exam@numsubsubparts}%
+  {\mbox{\normalfont\bf ??}}%
+  \exam@numsubsubparts
+}
+
+\def\pointsofquestion#1{\@ifundefined{pointsofq@\romannumeral #1}%
+  {\mbox{\normalfont\bf ??}}%
+  {\csname pointsofq@\romannumeral #1\endcsname}%
+}
+
+\def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}%
+  {\mbox{\normalfont\bf ??}}%
+  {\csname pointsonpage@\romannumeral #1\endcsname}%
+}
+
+
+\newif\if@pointschanged
+\@pointschangedfalse
+
+
+
+%%%\let\@realenddocument=\enddocument
+%%%\def\enddocument{\clearpage
+%%%   \if@filesw 
+%%%     {\advance\c@page-1 \immediate\write\@mainaux
+%%%       {\string\newlabel{@lastpage}{{}{\arabic{page}}}}%
+%%%     }
+%%%   \fi
+%%%   \@realenddocument
+%%%}
+
+
+\AtEndDocument{%
+  \clearpage
+  \if@filesw
+    \advance\c@page-1
+    \immediate\write\@mainaux
+      {\string\gdef\string\exam@lastpage{\arabic{page}}}%
+    \advance\c@page+1 % In case some other package looks at \c@page
+    \immediate\write\@mainaux
+        {\string\gdef\string\exam@numpoints{\prtaux@hlfcntr{numpoints}}}%
+    % See if this has changed from the last run of LaTeX:
+    \@ifundefined{exam@numpoints}%
+      {\global\@pointschangedtrue}%
+      {%
+      % OK; it's defined.  See if it's changed:
+      \begingroup
+        \set@hlfcntr{tmp@hlfcntr}{\exam@numpoints}%
+        \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
+        \edef\pt@check{\prtaux@hlfcntr{numpoints}}%
+        \ifx \pt@check \othpt@check
+          % Do nothing
+        \else
+          \global\@pointschangedtrue
+        \fi
+      \endgroup
+      }%
+    \immediate\write\@mainaux
+      {\string\gdef\string\exam@numquestions{\thenumquestions}}%
+    \immediate\write\@mainaux
+      {\string\gdef\string\exam@numparts{\thenumparts}}%
+    \immediate\write\@mainaux
+      {\string\gdef\string\exam@numsubparts{\thenumsubparts}}%
+    \immediate\write\@mainaux
+      {\string\gdef\string\exam@numsubsubparts{\thenumsubsubparts}}%
+    \ifnum \thepageof@pagepoints > 0\relax
+      \immediate\write\@mainaux
+          {\string\gdef\string\pointsonpage@\romannumeral
+                          \csname c@pageof@pagepoints\endcsname
+             {\prtaux@hlfcntr{@pagepoints}}}%
+      % See if this has changed from the last run of LaTeX:
+      \@ifundefined{pointsonpage@\romannumeral
+                          \csname c@pageof@pagepoints\endcsname}%
+        {\global\@pointschangedtrue}%
+        {%
+        % OK; it's defined.  See if it's changed:
+        \begingroup
+          \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral 
+                    \csname c@pageof@pagepoints\endcsname\endcsname}%
+          \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
+          \edef\pt@check{\prtaux@hlfcntr{@pagepoints}}%
+          \ifx \pt@check \othpt@check
+            % Do nothing
+          \else
+            \global\@pointschangedtrue
+          \fi
+        \endgroup
+        }%
+    \fi
+    \immediate\write\@mainaux
+      {\string\gdef\string\lastpage@withpoints{\page@withpoints}}%
+    % See if this has changed from the last run of LaTeX:
+    \@ifundefined{lastpage@withpoints}%
+      {\global\@pointschangedtrue}%
+      {%
+      % OK; it's defined.  See if it's changed:
+      \begingroup
+        \edef\othpt@check{\page@withpoints}%
+        \edef\pt@check{\lastpage@withpoints}%
+        \ifx \pt@check \othpt@check
+          % Do nothing
+        \else
+          \global\@pointschangedtrue
+        \fi
+      \endgroup
+      }%
+  \fi
+  % Echo numbers of questions, parts, and subparts:
+  \typeout{This exam contains \thenumquestions\space questions
+    with \thenumparts\space parts, \thenumsubparts\space subparts,
+    and \thenumsubsubparts\space subsubparts.}
+  % If counting points, echo total points:
+  \if@printtotalpoints
+    \begingroup
+      \def\typ@expnd{%
+        \thenumpoints
+        \ifnumpoints@half
+          \space and a half%
+        \fi
+      }
+      \typeout{This exam has a total of \typ@expnd\space points.}
+    \endgroup
+  \fi
+  \if@pointschanged
+    \ClassWarningNoLine{exam}{Point totals have changed.
+               Rerun to get point totals right}%
+  \fi
+}
+
+
+% We define \iflastpage so that it can safely be used
+% in headers and footers:
+\def\iflastpage#1#2{%
+  \@ifundefined{exam@lastpage}{\def\@@lastpage{-1}}%
+          {\edef\@@lastpage{\exam@lastpage}}%
+  \ifnum\value{page}=\@@lastpage
+    #1%
+  \else
+    #2%
+  \fi
+}
+
+
+% The macro \oddeven takes two arguments.  If the page number is odd,
+% then you get the first argument; otherwise, you get the second
+% argument.
+\def\oddeven#1#2{%
+  \ifodd\value{page}%
+    #1
+  \else
+    #2
+  \fi
+}
+
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%                 \ifcontinuation, \ContinuedQuestion,
+%                \ifincomplete, and \IncompleteQuestion
+
+% The commands \ifcontinuation, \ContinuedQuestion, \ifincomplete, and
+% \IncompleteQuestion assume that there is only one questions
+% environment in the entire document.  (Actually, \ContinuedQuestion
+% should work even if there are multiple questions environments, but
+% none of the other three will work in general.)
+
+
+
+% \PgInfo@write, \PgInfo and \PgInfo@get are our replacements
+% for \label, \newlabel, and \pageref.  (We're avoiding using
+% \label, \newlabel, and \pageref so that we will be compatible
+% with hyperref.sty, which redefines those commands.)
+
+% We use \PgInfo, \PgInfo@write, and \PgInfo@get to know on which page
+% each question, part, subpart, and subsubpart appears.
+
+% We use \PgInfo@write to write \PgInfo commands to the .aux file.  The
+% \PgInfo command takes two arguments: A question (or part, or subpart,
+% or subsubpart) label, and the number of the page on which it appears.
+
+% The label for a question is of the form `question@2' (if it's question
+% 2).
+
+% The label for a part is of the form `part@2@1' (if it's part a of
+% question 2).
+
+% The label for a subpart is of the form `subpart@2@1@3' (if it's
+% subpart iii of part a of question 2).
+
+% The label for a subsubpart is of the form `subsubpart@2@1@3@4' (if
+% it's subsubpart $\delta$ of subpart iii of part a of question 2).
+
+% The \PgInfo command defines a control sequence of the form `Pg@label'
+% that expands to the page number for the corresponding question.  For
+% example, \PgInfo{subsubpart@2@1@3@4}{7} defines 
+%   \csname Pg@subsubpart@2@1@3@4\endcsname 
+% to expand to 7.
+
+% The \PgInfo@get{label} command returns the value of the macro Pg@label,
+% but it *doesn't* check whether that macro is defined.  Thus, it's
+% important to check that the macro Pg@label is defined before giving the
+% command \PgInfo@get{label}.
+
+
+
+% The token list to a \write command isn't expanded until
+% it's shipped out.  Since the argument to PgInfo@write
+% generally contains macros, we want to expand those macros
+% now, rather than waiting until this is shipped out, at which
+% point the macros may have different values.  Thus, we use
+% \edef to force expansion of the argument, and we put
+% a \noexpand in front of \thepage so that the \thepage
+% will not be expanded now.  (This may not get shipped out
+% until a later page, and so we want the \thepage to be expanded
+% only when it's shipped out.)
+% We use the \begingroup \endgroup pair so that our use
+% of \reserved@a won't affect its use anywhere else.
+\def\PgInfo@write#1{%
+  \begingroup
+    \edef\reserved@a{\write\@mainaux
+      {\string\PgInfo{#1}{\noexpand\thepage}}}%
+    \reserved@a
+  \endgroup
+}
+
+%\PgInfo commands are written to the .aux file by the \PgInfo@write
+%command; that's the only place that \PgInfo commands appear.
+\def\PgInfo#1#2{\expandafter\gdef\csname Pg@#1\endcsname{#2}}
+
+% Note: PgInfo@get assumes that the control sequence being
+% constructed is already defined; you have to make sure of this
+% *before* calling \Pginfo@get
+\def\PgInfo@get#1{\csname Pg@#1\endcsname}
+
+% \set@counter@to@pageof takes two arguments: The first is the name
+% of a counter, and the second (expands to) the label of a question,
+% part, subpart, or subsubpart.  If that label exists, then we set
+% the counter equal to the page on which the question (or part, etc.)
+% appears.  If that label doesn't exist, we set the counter equal
+% to -1.  (No labels exist on the first run of LaTeX on the file,
+% and if a new question (or part, etc.) was created by editing the
+% file, then the label will not exist until the second run of LaTeX
+% after that.
+\def\set@counter@to@pageof#1#2{%
+  \@ifundefined{Pg@#2}%
+  {\setcounter{#1}{-1}}%
+  {\setcounter{#1}{\csname Pg@#2\endcsname}}%
+}
+
+
+%--------------------------------------------------------------------
+
+% \ifcontinuation#1#2 expands to #2 if either: (1) The current page is
+% before the page containing question number 1, or (2) A question begins
+% on this page before any part, subpart, or subsubpart begins, or (3)
+% The current page is later than a page with the \nomorequestions
+% command.  Otherwise, it expands to #1.
+
+
+\def\ifcontinuation#1#2{%
+  % We need to first check whether we're on a page *before* the page on
+  % which the first question appears.  If we don't yet know which page
+  % has question number 1, then we must be doing an early run of LaTeX,
+  % and we'll assume we're not a continuation.
+  \expandafter\ifx\csname Pg@question@1\endcsname\relax
+    % No page info yet; assume not a continuation
+    #2%
+  \else
+    % Note: The ``\relax'' at the end of the following \ifnum
+    % serves an entirely different purpose from the one at the
+    % end of the above \expandafter\ifx.  That one (above)
+    % is one of the things being compared, whereas the
+    % one we're about to use is just to clearly mark the
+    % end of the second number being compared by the \ifnum
+    % (since it's conceivable that the ``#2'' would begin
+    % with a digit).
+    \ifnum \thepage < \csname Pg@question@1\endcsname\relax
+      % We're before the page with question 1:
+      #2%
+    \else
+      % The current page begins a new question if Contin@\thepage
+      % has been defined as a macro that expands to \relax
+      % (Note that this is different from if Contin@\thepage
+      % has never been defined at all, in which case it will
+      % be let equal to \relax (temporarily) by the \csname command.)
+      \expandafter\ifx\csname Contin@\thepage\endcsname\ref@relax
+        #2%
+      \else
+        % See if we're after a \nomorequestions command:
+        \@ifundefined{Pg@@endquestions}%
+        {#1}%
+        {\ifnum \thepage > \PgInfo@get{@endquestions}\relax
+          % We're after a \nomorequestions:
+          #2
+         \else
+           % We actually are incomplete:
+           #1
+         \fi
+        }%
+      \fi
+    \fi 
+  \fi
+}
+
+\def\nomorequestions{
+  \PgInfo@write{@endquestions}%
+}
+
+
+
+%--------------------------------------------------------------------
+% \ContinuedQuestion is for use in headers and footers, where we can
+% assume that \thepage is the number of the page on which we'll
+% actually appear.
+
+% \ContinuedQuestion expands to the number of the question that
+% continues onto this page, or to -1 if this page begins with a new
+% question.
+
+% ACTUALLY: \ContinuedQuestion expands to a positive number if either
+% (1) this page doesn't contain the beginning of any question, part,
+% subpart, or subsubpart, or (2) this page has a part, subpart, or
+% subsubpart that appears before any question.  That means that if the
+% current page actually begins with space for a continuation of the
+% previous question (but doesn't begin any part, subpart, or subsubpart
+% of that question) and then has a question, then we'll be asserting
+% that this page begins with a new question, but the actual top of the
+% page will begin with some blank space that's intended for the previous
+% question.
+
+% \ContinuedQuestion works by examining the value of the macro
+% Contin@\thepage.  If this page starts with a question (i.e., if no
+% question continues onto this page), then the macro Contin@\thepage
+% will be defined, and will expand to `\relax' (and so an \ifx between
+% \csname Contin@\thepage\endcsname and \ref@relax will be true).
+
+% If Contin@\thepage is undefined, then when it is used in an \ifx
+% command it will be temporarily set equal to \relax (which is
+% *different* from being a macro that expands to \relax); in this case,
+% there is no question, part, subpart, or subsubpart that begins on this
+% page, and so \ContinuedQuestion will be set equal to the last question
+% that was begun on a page before this one.
+
+% The last possibility is that this page begins with either a part,
+% subpart, or subsubpart.  In this case, Contin@\thepage is defined, and
+% it expands to the number of the question that is continues onto this
+% page.
+
+
+\def\ref@relax{\relax}
+
+\def\ContinuedQuestion{%
+  \expandafter\ifx\csname Contin@\thepage\endcsname\relax
+    % We get here if there's no question, part, subpart, or
+    % subsubpart on this page, and so Contin@\thepage has
+    % never been defined at all.  In that case, this page
+    % continues whichever question was last begun on or 
+    % before this page.
+    \find@latestques
+    \thelatest@ques
+  \else
+    \expandafter\ifx\csname Contin@\thepage\endcsname\ref@relax
+      % We get here if this page begins with a new question,
+      % which is why Contin@\thepage has been defined to be
+      % a macro that expands to \relax.
+      % ACTUALLY: We get here if this page has a question that
+      % appears before any part, subpart, or subsubpart.  That
+      % means that if the current page actually begins with space
+      % for a continuation of the previous question but doesn't begin
+      % any part, subpart, or subsubpart of that question, then
+      % we'll be asserting that this page begins with a new question,
+      % but the actual top of the page will begin with some space
+      % that's intended for the previous question.
+      -1\relax
+    \else
+      % We get here if we didn't get anywhere above.  This happens
+      % if Contin@\thepage has been defined to be a macro that expands
+      % to something other than \relax, in which case it has been
+      % defined to be a macro that expands to the number of the
+      % question that continues onto this page.
+      \csname Contin@\thepage\endcsname
+    \fi
+  \fi
+}
+
+%--------------------------------------------------------------------
+% \find@latestques is for use in headers and footers, where we can
+% assume that \thepage actually equals the page on which we'll appear.
+% We find the last question that was started on or before the current
+% page.
+
+\newcounter{latest@ques}
+
+\newcommand\find@latestques{%
+  % \find@latestques is for use in headers and footers.
+  % \find@latestques will set the counter latest@ques
+  % to the number of the last question
+  % that was begun on the exam from page 1 through the current
+  % page.  This may well be the value of the question counter,
+  % but it may be less than that if the page following this one
+  % begins a new question and that question beginning was
+  % typeset before the present page was shipped out.
+  % Note: This macro is called both by \ContinuedQuestion and by
+  % \find@quesend, which is why it has to find the last question
+  % begun on or before the current page, rather than just before
+  % the current page.
+  \ifnum 1 > \arabic{question}\relax
+    % Oops; probably because we're before the first question
+    % Just set latest@ques to -1:
+    \setcounter{latest@ques}{-1}%
+  \else
+    % If question latest@ques actually begins on this page (rather
+    % than on the next page, but early enough on the next page
+    % that the counter was advanced before we ran off into the
+    % output routine to output the page and set the header and 
+    % footer), then that's the correct question number.
+    \expandafter\ifx\csname Pg@question@\arabic{question}\endcsname\relax
+      % We don't know what page that question is on;
+      % this must be an early run, before the aux file
+      % is helpful.  Just set it equal to -1 and wait until the next
+      % run to get it right.
+      \setcounter{latest@ques}{-1}%
+    \else
+      % We now know that \PgInfo@get can tell us the page number
+      % of \arabic{question} and of all earlier questions.
+      % Set latest@ques equal to the current question number, and
+      % then call \decr@latest@ques to recursively decrement
+      % latest@ques as needed to find a question that begins on
+      % or before the current page:
+      \setcounter{latest@ques}{\arabic{question}}%
+      \decr@latest@ques
+    \fi
+  \fi
+}
+
+\def\decr@latest@ques{%
+  % If we get here, then we've already checked that the reference
+  % Pg@question@\thelatest@ques is defined at least for a value of
+  % \thelatest@ques greater than or equal to it's present value,
+  % so we assume it's defined for all lesser values as well:
+  \ifnum \thepage < \PgInfo@get{question@\thelatest@ques}\relax
+    % Nope; latest@ques starts on a later page
+    % Decrement latest@ques and see if that one's right:
+    \addtocounter{latest@ques}{-1}%
+    \ifnum \thelatest@ques < 1\relax
+      \setcounter{latest@ques}{-1}%
+      \let\next@dlq=\relax
+    \else
+      \let\next@dlq=\decr@latest@ques
+    \fi
+  \else
+    % latest@ques starts on this page or earlier, so
+    % that's the correct question number!  Exit:
+    \let\next@dlq=\relax
+  \fi
+  \next@dlq
+}
+         
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+\newcounter{ques@end}
+\def\find@quesend{%
+  % We find the last question started on or before the current page
+  % and then find the page containing the last part (or subpart, or
+  % subsubpart) of that question, and set the counter ques@end to that
+  % page number.
+  % Set latest@ques equal to the correct question number:
+  \find@latestques
+  \ifnum \value{latest@ques} < 0\relax
+    % This must be an early run of LaTeX, before we have
+    % \PgInfo commands in the .aux file:
+    \setcounter{ques@end}{-1}%
+  \else
+    % See if this question has any parts.  (It has one or more parts
+    % if and only if it has a part number 1.)
+    \@ifundefined{Pg@part@\thelatest@ques @1}%
+      {%
+        % Nope; no parts.
+        \setcounter{ques@end}{\PgInfo@get{question@\thelatest@ques}}%
+      }%
+      {\find@part}%
+  \fi
+}
+
+\newcounter{last@part}
+\def\find@part{%
+  % We now know that this question has at least one part.
+  % We'll find its highest numbered part by setting last@part
+  % equal to 2 and then calling \find@lastpart to recursively
+  % test whether that part number exists and, if so, incrementing
+  % last@part to test for a higher numbered one:
+  \setcounter{last@part}{2}%
+  \find@lastpart
+  % Now: See if this part has any subparts.  (It has one or more
+  % subparts if and only if it has a subpart numbered 1.)
+  \@ifundefined{Pg@subpart@\thelatest@ques @\thelast@part @1}%
+    {%
+      % Nope; no subparts.
+      \setcounter{ques@end}{\PgInfo@get{part@\thelatest@ques
+                                          @\thelast@part}}%
+    }%
+    {\find@subpart}%
+}
+
+\def\find@lastpart{%
+  % We check whether this question has a part numbered last@part
+  % and recursively increment last@part to find the highest
+  % numbered value for which the part exists:
+  \@ifundefined{Pg@part@\thelatest@ques @\thelast@part}%
+    {\addtocounter{last@part}{-1}%
+      \let\nextfind@lastpart=\relax
+    }%
+    {\addtocounter{last@part}{1}%
+      \let\nextfind@lastpart=\find@lastpart
+    }%
+  \nextfind@lastpart
+}
+
+\newcounter{last@subpart}
+\def\find@subpart{%
+  % We now know that this part has at least one subpart.
+  % We'll find its highest numbered subpart by setting last@subpart
+  % equal to 2 and then calling \find@lastsubpart to recursively
+  % test whether that subpart number exists and, if so, incrementing
+  % last@subpart to test for a higher numbered one:
+  \setcounter{last@subpart}{2}%
+  \find@lastsubpart
+  % Now: See if this subpart has any subsubparts.  (It has one or more
+  % subsubparts if and only if it has a subsubpart numbered 1.)
+  \@ifundefined{Pg@subsubpart@\thelatest@ques 
+                         @\thelast@part @\thelast@subpart @1}%
+    {%
+      % Nope; no subsubparts
+      \setcounter{ques@end}{\PgInfo@get{subpart@\thelatest@ques
+                                  @\thelast@part @\thelast@subpart}}%
+    }%
+    {\find@subsubpart}%
+}
+
+\def\find@lastsubpart{%
+  % We check whether this part has a subpart numbered last@subpart
+  % and recursively increment last@subpart to find the highest
+  % numbered value for which the subpart exists:
+  \@ifundefined{Pg@subpart@\thelatest@ques 
+                         @\thelast@part @\thelast@subpart}%
+    {\addtocounter{last@subpart}{-1}%
+      \let\nextfind@lastsubpart=\relax
+    }%
+    {\addtocounter{last@subpart}{1}%
+      \let\nextfind@lastsubpart=\find@lastsubpart
+    }%
+  \nextfind@lastsubpart
+}
+
+\newcounter{last@subsubpart}
+\def\find@subsubpart{%
+  % We now know that this subpart has at least one subsubpart.
+  % We'll find its highest numbered subsubpart by setting last@subsubpart
+  % equal to 2 and then calling \find@lastsubsubpart to recursively
+  % test whether that subsubpart number exists and, if so, incrementing
+  % last@subsubpart to test for a higher numbered one:
+  \setcounter{last@subsubpart}{2}%
+  \find@lastsubsubpart
+  \setcounter{ques@end}{\PgInfo@get{subsubpart@\thelatest@ques
+               @\thelast@part @\thelast@subpart @\thelast@subsubpart}}%
+}
+
+\def\find@lastsubsubpart{%
+  % We check whether this subpart has a subsubpart numbered last@subsubpart
+  % and recursively increment last@subsubpart to find the highest
+  % numbered value for which the subsubpart exists:
+  \@ifundefined{Pg@subsubpart@\thelatest@ques 
+              @\thelast@part @\thelast@subpart @\thelast@subsubpart}%
+    {\addtocounter{last@subsubpart}{-1}%
+      \let\nextfind@lastsubsubpart=\relax
+    }%
+    {\addtocounter{last@subsubpart}{1}%
+      \let\nextfind@lastsubsubpart=\find@lastsubsubpart
+    }%
+  \nextfind@lastsubsubpart
+}
+
+
+%--------------------------------------------------------------------
+\newcounter{incmp@ques}
+
+\def\IncompleteQuestion{%
+  \Find@Incmp@ques
+  \theincmp@ques
+}
+
+\def\Find@Incmp@ques{%
+  \iflastpage{\setcounter{incmp@ques}{-1}}{\chk@incomp}%
+}
+\newcounter{next@ques}
+\newcounter{nextq@page}
+\def\chk@incomp{%
+  \find@quesend
+  \ifnum \theques@end > \thepage\relax
+    % This question has a part (or sub...) starting on a later page
+    \setcounter{incmp@ques}{\value{latest@ques}}%
+  \else
+    \setcounter{next@ques}{\thelatest@ques}%
+    \addtocounter{next@ques}{1}%
+    \expandafter\ifx\csname Pg@question@\thenext@ques \endcsname\relax
+      % This isn't the last page but there is no next question:
+      \setcounter{incmp@ques}{\thelatest@ques}%
+    \else
+      % This isn't the last page and there is a next question:
+      \setcounter{nextq@page}{\PgInfo@get{question@\thenext@ques}}%
+      \addtocounter{nextq@page}{-1}%
+      \ifnum \thenextq@page > \thepage\relax
+        \setcounter{incmp@ques}{\thelatest@ques}%
+      \else
+        \setcounter{incmp@ques}{-1}%
+      \fi
+    \fi
+  \fi
+}
+
+
+\def\ifincomplete#1#2{%
+  \def\incomp@first{#1}%
+  \def\incomp@second{#2}%
+  \Find@Incmp@ques
+  \ifnum \theincmp@ques < 0\relax
+    \incomp@second
+  \else
+        \@ifundefined{Pg@@endquestions}%
+        {\incomp@first}%
+        {\ifnum \thepage < \PgInfo@get{@endquestions}%
+           \incomp@first
+         \else
+           \incomp@second
+         \fi
+        }%
+  \fi
+}
+
+
+
+
+%---------------------------------------------------------------------
+%
+%                    ***************************
+%                    ** QUESTION ENVIRONMENTS **
+%                    ***************************
+%
+%
+%
+
+% We define the command \part only inside of a parts environment, so
+% that we don't interfere with the meaning of the standard article
+% documentclass command \part if that is used inside of a questions
+% environment.  The commands \question, \subpart, and \subsubpart are
+% defined everywhere inside of a questions environment.  If the user
+% accidentally gives a \subpart command outside of a subparts
+% environment, then an error will be created.
+
+
+%--------------------------------------------------------------------
+% These are the commands for dealing with hlfcntr's, i.e., the things
+% used to count points.
+%
+% A point value is a nonnegative integer with an optional half integer.
+% A hlfcntr consists of a regular counter together with an \if: If the
+% regular counter is called ``counter'', then the \if is called
+% ``\ifcounter@half''; it's set true by ``\counter@halftrue'' and set
+% false by ``\counter@halffalse''.
+%
+% The commands:
+%
+% \set@hlfcntr{countername}{value}
+% \copy@hlfcntr{tocounter}{fromcounter}
+% \addto@hlfcntr{countername}{value}
+% \add@hlfcntrtohlfcntr
+% \ifhlfcntr@pos{countername}
+% \prtaux@hlfcntr{countername}
+%
+% ``value'' can be either a (nonnegative) integer, an integer followed by
+% ``\half'', or just plain ``\half''.  (Actually, ``value'' can be empty
+% (although the braces must be present), in which case it's interpreted
+% as ``0''.)
+%
+% Examples of valid values:
+%   0
+%   0\half
+%   1
+%   1\half
+%   2
+%   2\half
+% etc.
+
+% Note on using ``\global'': LaTeX's \setcounter and \addtocounter
+% commands are already \global (i.e., you don't have to say
+% ``\global''), but \somethingtrue and \somethingfalse (used to set
+% \ifsomething) aren't.  Thus, we need to say ``\global'' when setting
+% these things.
+
+% A scratch hlfcntr:
+\newcounter{tmp@hlfcntr}
+\newif\iftmp@hlfcntr@half
+
+\newcommand*\horiz@half{$\frac{1}{2}$}
+\newcommand*\slanted@half{%
+  $\raise0.6ex\hbox{$\scriptstyle 1$}\kern -.2em/\kern -.2em
+     \raise-0.5ex\hbox{$\scriptstyle 2$}$%
+}
+\newcommand*\useslantedhalf{\let\half\slanted@half}
+\newcommand*\usehorizontalhalf{\let\half\horiz@half}
+\newcommand*\half{\slanted@half}
+
+
+\newcommand*\set@hlfcntr[2]{%
+  \begingroup
+    \expandafter\global\csname #1@halffalse\endcsname
+    % If there as a `\half' present, it will be executed
+    % right after the assignment of the digit part of #2
+    % to the counter #1.
+    \def\half{%
+      \expandafter\global\csname #1@halftrue\endcsname
+    }%
+    % We insert a `0' in case there are no digits present:
+    \setcounter{#1}{0#2}\relax
+  \endgroup
+}
+
+\newcommand*\copy@hlfcntr[2]{%
+  % We set #1 to the value of #2
+  \setcounter{#1}{\value{#2}}%
+  \csname if#2@half\endcsname
+    \expandafter\global\csname #1@halftrue\endcsname
+  \else
+    \expandafter\global\csname #1@halffalse\endcsname
+  \fi
+}
+
+\newcommand*\addto@hlfcntr[2]{%
+  % We add the valueandhalf #2 to hlfcntr #1
+  \begingroup
+    \def\half{\add@half{#1}}%
+    % We insert a `0' in case there are no digits present:
+    \addtocounter{#1}{0#2}\relax
+  \endgroup
+}
+
+\newcommand*\add@hlfcntrtohlfcntr[2]{%
+  % We add the hlfcntr #2 to the hlfcntr #1
+  \addtocounter{#1}{\value{#2}}%
+  \csname if#2@half\endcsname
+    \add@half{#1}%
+  \fi
+}
+
+\newcommand*\add@half[1]{%
+  % We add one half to hlfcntr #1:
+  \csname if#1@half\endcsname
+    \addtocounter{#1}{1}%
+    \expandafter\global\csname #1@halffalse\endcsname
+  \else
+    \expandafter\global\csname #1@halftrue\endcsname
+  \fi
+}
+
+\newcounter{ifpos@cntr}
+\def\ifhlfcntr@pos#1{%
+  % The argument must be a hlfcntr (which, of course,
+  % can never be negative); we'll be true if and only if
+  % that halfcntr is positive:
+  \setcounter{ifpos@cntr}{\value{#1}}%
+  \csname if#1@half\endcsname
+    \addtocounter{ifpos@cntr}{1}%
+  \fi
+  \ifnum \value{ifpos@cntr} > 0
+}
+
+% \prtaux@hlfcntr is used inside the argument of a \write command for
+% writing to the .aux file:
+\newcommand*\prtaux@hlfcntr[1]{%
+  % We don't want a \relax after the 0 in the following
+  % line, because it would sometimes appear in the aux file:
+  \ifnum \value{#1} = 0 
+    % We have to make the following a macro, because if we
+    % don't do this part, the \fi will cause confusion, since
+    % there's no \if visible until the \csname is expanded:
+    \prtaux@halforzero{#1}%
+  \else
+    \arabic{#1}%
+    % We have to make the following a macro, because if we
+    % don't do this part, the \fi will cause confusion, since
+    % there's no \if visible until the \csname is expanded:
+    \prtaux@halforblank{#1}%
+  \fi
+}
+\newcommand*\prtaux@halforzero[1]{%
+  \csname if#1@half\endcsname
+    \string\half
+  \else
+    0%
+  \fi
+}
+\newcommand*\prtaux@halforblank[1]{%
+  \csname if#1@half\endcsname
+    \string\half
+  \fi
+}
+%--------------------------------------------------------------------
+
+
+
+
+% We use the counter name `partno' for the parts environment so that
+% we will not interfere with the counter `part' used by the article
+% document class.
+
+\newcounter{question}
+\newcounter{partno}
+\newcounter{subpart}
+\newcounter{subsubpart}
+\newcounter{choice}
+\newcounter{numpoints}
+\newif\ifnumpoints@half
+\set@hlfcntr{numpoints}{0}
+\newcounter{pointsof@thisquestion}
+\newif\ifpointsof@thisquestion@half
+\set@hlfcntr{pointsof@thisquestion}{0}
+\newcounter{numquestions}
+\newcounter{numparts}
+\newcounter{numsubparts}
+\newcounter{numsubsubparts}
+\newcounter{Curr@Page}
+
+% @pagepoints accumulates the points on a single page:
+\newcounter{@pagepoints}
+\newif\if@pagepoints@half
+%\setcounter{@pagepoints}{0}
+\set@hlfcntr{@pagepoints}{0}
+\newcounter{pageof@pagepoints}
+\setcounter{pageof@pagepoints}{0}
+
+% latest@points is a holding area for points until we know
+% whether they'll land on the same page as the points
+% currently counted in @pagepoints:
+\newcounter{latest@points}
+\newif\iflatest@points@half
+\set@hlfcntr{latest@points}{0}
+
+% Whenever we meet a new page on which points are defined, we'll
+% redefine \page@withpoints to expand to that page.  At the end of the
+% document, it will hold the last page that has points, and we'll write
+% a \gdef\lastpage@withpoints command to the .aux file.
+% We initialize \page@withpoints here:
+\def\page@withpoints{0}%
+
+% \pageinfo@commands is used by each question, part, subpart, and
+% subsubpart to insert into everypar the \PgInfo@write command to put
+% its page number inot the .aux file, the \PgInfo@get command to read
+% the page number into the counter Curr@Page, and to test and set
+% \Contin@\theCurr@Page.  \temp@toks is used by part, subpart, and
+% subsubpart to append all that to \pageinfo@commands, rather than
+% deleting whatever may have been put into \pageinfo@commands by the
+% current question and/or part and/or subpart.
+\newtoks\pageinfo@commands
+\newtoks\temp@toks
+
+% \pagepoint@commands holds the commands to manage the counting of the
+% number of points defined on each page.
+\newtoks\pagepoint@commands
+
+% \point@toks holds the commands to print the points at the proper
+% location on the page (except that it's not used by the \qformat
+% option).
+\newtoks\point@toks
+
+% We'll use \greeknum to number subsubparts
+\def\greeknum#1{\expandafter\lc@greek\csname c@#1\endcsname}
+\def\lc@greek#1{%
+  \ifcase #1\or $\alpha$\or $\beta$\or $\gamma$\or $\delta$\or
+  $\epsilon$\or $\zeta$\or $\eta$\or $\theta$\or $\iota$\or
+  $\kappa$\or $\lambda$\or $\mu$\or $\nu$\or $\xi$\or o\or $\pi$\or
+  $\rho$\or $\sigma$\or $\tau$\or $\upsilon$\or $\phi$\or $\chi$\or
+  $\psi$\or $\omega$\else \@ctrerr
+  \fi
+}%
+
+
+% The following macros are a variation on a trick from Victor
+% Eijkhout's ``TeX by Topic'', page 142:
+% Both \prepend@toklist and \append@toklist take two arguments,
+% both of which should be token lists.
+% \prepend@toklist prepends #2 to #1
+% \append@toklist appends #2 to #1
+
+\def\prepend@toklist#1#2{%
+  \edef\do@it{\noexpand#1={\the#2\the#1}}%
+  \do@it
+}%
+
+\def\append@toklist#1#2{%
+  \edef\do@it{\noexpand#1={\the#1\the#2}}%
+  \do@it
+}%
+
+
+% The command \qformat is provided for the user who wants to
+% design a nonstandard question line.  If this command is used,
+% then the usual line containing the question numbers will be
+% replaced by the line specified by the \qformat command.
+% Within the argument of the \qformat command:
+% \thequestion will be replaced by the question number, and
+% \thepoints will be replaced by ``\@points \@pointname'' if the
+% number of points has been specified for this question, and otherwise
+% it inserts nothing at all.  (The conditional @placepoints is used to
+% determine if the number of points is nonzero.)
+% The argument to the \qformat command *must* contain some
+% stretch, i.e., at least one \hfil or \dotfill or ...
+\newif\if@qformat
+\@qformatfalse
+
+\def\qformat#1{%
+  \global\@qformattrue
+  \gdef\@questionformat{#1}%
+}
+
+\newcommand\noqformat{%
+  \global\@qformatfalse
+}
+
+\newcommand\thepoints{%
+  \if@placepoints
+    \@points \@pointname
+  \fi
+}
+
+% We define the \subpart and \subsubpart commands when we enter a
+% questions environment (rather than waiting until we enter a subparts
+% of subsubparts environment) so that we can signal an error if a
+% \subpart or \subsubpart command appears outside of the corresponding
+% environment.  (We don't do this for the \part command so that the user
+% can use the standard sectioning \part command outside of a parts
+% environment.)
+
+\newenvironment{questions}{%
+  % \@queslevel is used for two purposes:
+  % (1) We check that every \question, \part, \subpart, and 
+  % \subsubpart command appears inside the appropriate environment,
+  % and generate an error if one appears in the wrong place.
+  % (2) If a \qformat is being used and if \@queslevel tells us
+  % that we're currently processing a question, then we set
+  % \global \point@toks={} to avoid setting the points for a 
+  % question other than via the qformat command.
+  \def\@queslevel{question}%
+  \def\question{%
+    \if@coverpages
+      \cover@question@error
+    \fi
+    \@checkqueslevel{question}%
+    \addtocounter{numquestions}{1}%
+    % Write the sum of points of the previous question (if any)
+    % to the .aux file.  (At this point, the question counter
+    % has not yet been incremented, so \arabic{question} has the
+    % number of the question that was just completed.)
+    \if@filesw
+      \ifnum \arabic{question} > 0\relax
+        \immediate\write\@mainaux
+          {\string\gdef\string\pointsofq@
+            \romannumeral \csname c@question\endcsname
+              {\prtaux@hlfcntr{pointsof@thisquestion}}}%
+        % See if this has changed from the last run of LaTeX:
+        \@ifundefined{pointsofq@\romannumeral
+                            \csname c@question\endcsname}%
+          {\global\@pointschangedtrue}%
+          {%
+          % OK; it's defined.  See if it's changed:
+          \begingroup
+            \set@hlfcntr{tmp@hlfcntr}{\csname pointsofq@\romannumeral 
+                         \csname c@question\endcsname\endcsname}%
+            \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
+            \edef\pt@check{\prtaux@hlfcntr{pointsof@thisquestion}}%
+            \ifx \pt@check \othpt@check
+              % Do nothing
+            \else
+              \global\@pointschangedtrue
+            \fi
+          \endgroup
+          }%
+      \fi
+    \fi
+    \set@hlfcntr{pointsof@thisquestion}{0}%
+    % If there was a question with points immediately preceding
+    % this question (i.e., there were no parts in the previous
+    % question), then @placepoints will still be true, and we need to
+    % cancel it.  (We used to do this inside of the \thepoints macro,
+    % but that allowed for an error if the user specified points for a
+    % question but had a \qformat that didn't mention \thepoints.)  We
+    % also set @placepoints to be false in the \part command.
+    \global \@placepointsfalse
+    % point@toks will normally be empty at this point, but it might be
+    % nonempty if there were points somewhere in the previous question
+    % that never made it onto the page because we never entered
+    % horizontal mode (perhaps because the user was weird and let the
+    % text of a question (or part, etc.) consist entirely of an
+    % enumerate environment, or description environment, or etc.).
+    \global \point@toks={}%
+    % Important: Don't leave any blank lines inside of
+    % \pageinfo@commands!!  This token list will be dumped into
+    % horizontal mode by \everypar, and so any blank lines will
+    % cause paragraph breaks. 
+    \pageinfo@commands={%
+      \edef\@queslabel{question@\arabic{question}}%
+      \PgInfo@write{\@queslabel}%
+      \set@counter@to@pageof{Curr@Page}{\@queslabel}%
+      \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
+        % We're the first \question, \part, \subpart, or \subsubpart
+        % on this page:
+        \global\expandafter\edef
+               \csname Contin@\theCurr@Page\endcsname{\relax}%
+      \fi
+      \the\pagepoint@commands
+      \global \pageinfo@commands={}%
+    }% pageinfo@commands
+    \ifhmode
+      % Remove any skips at the end of the previous paragraph
+      % that might cause a blank line, and then end that paragraph:
+      \unskip\unskip \par
+    \fi
+    \@doitem
+  }% question
+  \def\subpart{%
+    \if@coverpages
+      \cover@question@error
+    \fi
+    \@checkqueslevel{subpart}%
+    \addtocounter{numsubparts}{1}%
+    % Important: Don't leave any blank lines inside of
+    % \pageinfo@commands!!  This token list will be dumped into
+    % horizontal mode by \everypar, and so any blank lines will
+    % cause paragraph breaks. 
+    \temp@toks={%
+      \edef\@subpartlabel{subpart@\arabic{question}%
+        @\arabic{partno}@\arabic{subpart}}%
+      \PgInfo@write{\@subpartlabel}%
+      \set@counter@to@pageof{Curr@Page}{\@subpartlabel}%
+      \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
+        % We're the first \question, \part, \subpart, or \subsubpart
+        % on this page:
+        \global\expandafter\edef\csname
+                       Contin@\theCurr@Page\endcsname{\arabic{question}}%
+      \fi
+      \the\pagepoint@commands
+      \global \pageinfo@commands={}%
+    }% temp@toks
+    \append@toklist \pageinfo@commands \temp@toks
+    \ifhmode
+      % Remove any skips at the end of the previous paragraph
+      % that might cause a blank line, and then end that paragraph:
+      \unskip\unskip \par
+    \fi
+    \@doitem
+  }% subpart
+  \def\subsubpart{%
+    \if@coverpages
+      \cover@question@error
+    \fi
+    \@checkqueslevel{subsubpart}%
+    \addtocounter{numsubsubparts}{1}%
+    % Important: Don't leave any blank lines inside of
+    % \pageinfo@commands!!  This token list will be dumped into
+    % horizontal mode by \everypar, and so any blank lines will
+    % cause paragraph breaks. 
+    \temp@toks={%
+      \edef\@subsubpartlabel{subsubpart@\arabic{question}%
+        @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}%
+      \PgInfo@write{\@subsubpartlabel}%
+      \set@counter@to@pageof{Curr@Page}{\@subsubpartlabel}%
+      \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
+        % We're the first \question, \part, \subpart, or \subsubpart
+        % on this page:
+        \global\expandafter\edef\csname
+                       Contin@\theCurr@Page\endcsname{\arabic{question}}%
+      \fi
+      \the\pagepoint@commands
+      \global \pageinfo@commands={}%
+    }% temp@toks
+    \append@toklist \pageinfo@commands \temp@toks
+    \ifhmode
+      % Remove any skips at the end of the previous paragraph
+      % that might cause a blank line, and then end that paragraph:
+      \unskip\unskip \par
+    \fi
+    \@doitem
+  }% subsubpart
+  \list{\question@number}%
+    {\usecounter{question}%
+    % We use the default definition of \makelabel
+    % so as not to interfere with \qformat commands.
+    % \def\makelabel##1{\hss\llap{##1}}%
+    \settowidth{\leftmargin}{10.\hskip\labelsep}%
+    \labelwidth\leftmargin\advance\labelwidth-\labelsep
+    \partopsep=0pt
+    }%
+  }%
+  {%
+    \endlist
+    % Write the number of points of the final question
+    % to the .aux file:
+    \if@filesw
+      \ifnum \arabic{question} > 0\relax
+        \immediate\write\@mainaux
+          {\string\gdef\string\pointsofq@\romannumeral
+                                \csname c@question\endcsname
+            {\prtaux@hlfcntr{pointsof@thisquestion}}}%
+        % See if this has changed from the last run of LaTeX:
+        \@ifundefined{pointsofq@\romannumeral
+                            \csname c@question\endcsname}%
+          {\global\@pointschangedtrue}%
+          {%
+          % OK; it's defined.  See if it's changed:
+          \begingroup
+            \set@hlfcntr{tmp@hlfcntr}{\csname pointsofq@\romannumeral 
+                         \csname c@question\endcsname\endcsname}%
+            \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
+            \edef\pt@check{\prtaux@hlfcntr{pointsof@thisquestion}}%
+            \ifx \pt@check \othpt@check
+              % Do nothing
+            \else
+              \global\@pointschangedtrue
+            \fi
+          \endgroup
+          }%
+      \fi
+    \fi
+  }
+  
+% \question@number is used as the label in the question list (instead
+% of \questionlabel) so that if the user uses a \qformat command,
+% we'll use the \@questionformat specified by the \qformat command:
+\def\question@number{%
+  \if@qformat
+    \makebox[\hsize][s]{\@questionformat}\hskip-\labelsep
+  \else
+    \questionlabel
+  \fi
+}
+\newcommand\questionlabel{\thequestion.}
+     
+% We want the \part command to be defined *only* inside of a parts
+% environment, so that the user can use the standard sectioning \part
+% command inside of a questions environment (as long as it's outside of
+% a parts environment).
+
+\newenvironment{parts}{%
+  \def\@queslevel{part}%
+  % If the question numbers are being inserted via a \qformat,
+  % and if a question is beginning with a parts environmnt, then
+  % we need to enter horizonal mode to the the qformat printed
+  % on the page, rather than saving up the question label (and
+  % possible points) to be combined with the label of the first
+  % part.  (\if@inlabel tells us if we are still waiting to enter
+  % horizontal mode after seeing a \question command.)
+  \if@qformat
+    \if@inlabel
+      \leavevmode
+      \@inlabelfalse
+    \fi
+    % The following is just in case the question had points,
+    % in which case @placepoints will still be true.
+    % (We used to do this inside of the \thepoints macro,
+    % but that allowed for an error if the user specified points for
+    % a question but had a \qformat that didn't mention \thepoints.)
+    % We also set @placepoints to be false in the \question command,
+    % in case one queation follows a previous one that had no parts.
+    \global \@placepointsfalse
+  \fi
+  \def\part{%
+    \if@coverpages
+      \cover@question@error
+    \fi
+    \@checkqueslevel{part}%
+    \addtocounter{numparts}{1}%
+    % Important: Don't leave any blank lines inside of
+    % \pageinfo@commands!!  This token list will be dumped into
+    % horizontal mode by \everypar, and so any blank lines will
+    % cause paragraph breaks. 
+    \temp@toks={%
+      \edef\@partlabel{part@\arabic{question}@\arabic{partno}}%
+      \PgInfo@write{\@partlabel}%
+      \set@counter@to@pageof{Curr@Page}{\@partlabel}%
+      \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
+        \global\expandafter\edef\csname
+            Contin@\theCurr@Page\endcsname{\arabic{question}}%
+      \fi
+      \the\pagepoint@commands
+      \global \pageinfo@commands={}%
+    }%
+    \append@toklist \pageinfo@commands \temp@toks
+    \ifhmode
+      % Remove any skips at the end of the previous paragraph
+      % that might cause a blank line, and then end that paragraph:
+      \unskip\unskip \par
+    \fi
+    \@doitem
+  }% part
+  \list{\partlabel}%
+    {%
+    \usecounter{partno}\def\makelabel##1{\hss\llap{##1}}%
+    \settowidth{\leftmargin}{(m)\hskip\labelsep}%
+    \labelwidth\leftmargin\advance\labelwidth-\labelsep
+    \topsep=0pt
+    \partopsep=0pt
+    }%
+  }% newenvironment{parts}
+  {\endlist}
+\newcommand\partlabel{(\thepartno)}
+\def\thepartno{\alph{partno}}
+
+\newenvironment{subparts}{%
+  \def\@queslevel{subpart}%
+  \list{\subpartlabel}%
+    {%
+    \usecounter{subpart}\def\makelabel##1{\hss\llap{##1}}%
+    \settowidth{\leftmargin}{vii.\hskip\labelsep}%
+    \labelwidth\leftmargin\advance\labelwidth-\labelsep
+    \topsep=0pt
+    \partopsep=0pt
+    }%
+  }%
+  {\endlist}
+\newcommand\subpartlabel{\thesubpart.}
+\def\thesubpart{\roman{subpart}}
+
+\newenvironment{subsubparts}{%
+  \def\@queslevel{subsubpart}%
+  \list{\subsubpartlabel}%
+    {%
+    \usecounter{subsubpart}\def\makelabel##1{\hss\llap{##1}}%
+    \settowidth{\leftmargin}{($\psi$)\hskip\labelsep}%
+    \labelwidth\leftmargin\advance\labelwidth-\labelsep
+    \topsep=0pt
+    \partopsep=0pt
+    }%
+  }%
+  {\endlist}
+\newcommand\subsubpartlabel{\thesubsubpart)}
+\def\thesubsubpart{\greeknum{subsubpart}}
+
+
+\pagepoint@commands={%
+  \ifhlfcntr@pos{latest@points}%
+    % We're putting a question (or part, etc.)
+    % with points onto this page: 
+    \ifnum \theCurr@Page > \thepageof@pagepoints\relax
+      % These points go on a later page than
+      % the points currently counted in @pagepoints:
+      \ifnum \thepageof@pagepoints = 0\relax
+        % Do nothing...
+      \else
+        \immediate\write\@mainaux
+          {\string\gdef\string\pointsonpage@
+           \romannumeral \csname c@pageof@pagepoints\endcsname
+             {\prtaux@hlfcntr{@pagepoints}}}%
+        % See if this has changed from the last run of LaTeX:
+        \@ifundefined{pointsonpage@\romannumeral
+                            \csname c@pageof@pagepoints\endcsname}%
+          {\global\@pointschangedtrue}%
+          {%
+          % OK; it's defined.  See if it's changed:
+          \begingroup
+            \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral 
+                      \csname c@pageof@pagepoints\endcsname\endcsname}%
+            \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
+            \edef\pt@check{\prtaux@hlfcntr{@pagepoints}}%
+            \ifx \pt@check \othpt@check
+              % Do nothing
+            \else
+              \global\@pointschangedtrue
+            \fi
+          \endgroup
+          }%
+      \fi
+      % The following is a macro because \theCurr@Page and
+      % \thepageof@pagepoints might differ by more than 1:
+      \increment@pageof@pagepoints
+    \else
+      % These points go on the same page as the points
+      % currently counted in @pagepoints:
+      \add@hlfcntrtohlfcntr{@pagepoints}{latest@points}%
+      \set@hlfcntr{latest@points}{0}%
+    \fi
+  \fi
+}
+\def\increment@pageof@pagepoints{%
+  \addtocounter{pageof@pagepoints}{1}%
+  \ifnum \theCurr@Page > \thepageof@pagepoints\relax
+    \immediate\write\@mainaux
+        {\string\gdef\string\pointsonpage@
+         \romannumeral \csname c@pageof@pagepoints\endcsname{0}}%
+    % See if this has changed from the last run of LaTeX:
+    \@ifundefined{pointsonpage@\romannumeral
+                        \csname c@pageof@pagepoints\endcsname}
+      {\global\@pointschangedtrue}%
+      {%
+      % OK; it's defined.  See if it's changed:
+      \begingroup
+        \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral 
+                  \csname c@pageof@pagepoints\endcsname\endcsname}%
+        \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
+        \def\pt@check{0}%
+        \ifx \pt@check \othpt@check
+          % Do nothing
+        \else
+          \global\@pointschangedtrue
+        \fi
+      \endgroup
+      }%
+    \let\next@incr@pageof = \increment@pageof@pagepoints
+  \else
+    \copy@hlfcntr{@pagepoints}{latest@points}%
+    \set@hlfcntr{latest@points}{0}%
+    % \page@withpoints will be used to find the last
+    % page that has points, which will be written to
+    % the .aux file vis \AtEndDocument:
+    \global\edef\page@withpoints{\thepageof@pagepoints}%
+    \let\next@incr@pageof = \relax
+  \fi
+  \next@incr@pageof
+}
+
+
+
+
+
+
+
+\def\@checkqueslevel#1{%
+  \begingroup
+    \def\@temp{#1}%
+    \ifx\@temp\@queslevel
+      % Everything's fine; do nothing.
+    \else
+      \ClassError{exam}{%
+        I found a #1 where I expected to find a
+        \@queslevel\MessageBreak
+      }{%
+        Both #1 and \@queslevel \space can be used only inside the
+        correct \MessageBreak \space \space
+        environment and outside of any smaller environment
+        \MessageBreak
+      }%
+    \fi
+  \endgroup
+}
+
+\def\@doitem{\@ifnextchar[{\@readpoints}%
+                          {\item@points@pageinfo}%
+}
+
+\def\@readpoints[#1]{%
+% We use \def for \@points instead of \edef because we don't want
+% \half (if present) to be expanded yet, so that the command \points
+% can figure out how to deal with it:
+  \def\@points{#1}%
+  \global \@placepointstrue
+  \if@addpoints
+    \addto@hlfcntr{numpoints}{\@points}%
+    \addto@hlfcntr{pointsof@thisquestion}{\@points}%
+    % latest@points is a holding area for points to be
+    % added to @pagepoints after we check whether they're
+    % on the same page as the points currently counted
+    % by @pagepoints:
+    \addto@hlfcntr{latest@points}{\@points}%
+  \fi
+  \item@points@pageinfo
+}
+
+
+
+% do@int@lbl is the command used to create a label for every question,
+% part, subpart, and subsubpart.  We make no use of these labels, but we
+% put them there so that if a question (or part, etc.) is, e.g., moved
+% from one page to another, LaTeX will notice this and warn the user
+% that LaTeX must be run one more time to be sure everything is correct.
+%
+% We need to do this even though we've already included code to check
+% when point totals change because questions (and parts, etc.) know what
+% page they're on from reading the info written to the .aux file on the
+% previous run.  Thus, if a question (or part, etc.) is moved to a
+% different page, then the pointsonpage totals won't notice until the
+% *second* subsequent run of LaTeX, and so there'll be no warning to the
+% user on the *first* run.  Including these labels gives the user a
+% warning on that first run.
+
+\newcounter{lbl@cntr}
+\def\do@int@lbl{%
+  \addtocounter{lbl@cntr}{1}%
+  % Looking at latex.ltx reveals that the argument to \label is
+  % expanded, so we don't really need the \expandafter's in the
+  % following, but I haven't seen any statement anywhere in
+  % documentation about it being expanded, so we'll be paranoid and
+  % protect against future changes in latex.ltx by using
+  % \expandafter's: 
+  \expandafter\label\expandafter{\thelbl@cntr @@exam@lbl}%
+}
+
+
+% Bug fix, 5 April 2004: \item@points@pageinfo
+% Appending \point@toks and \pageinfo@commands to \everypar:
+% Instead of appending the contents of \point@toks and
+% \pageinfo@commands to \everypar using \append@toklist,
+% we instead want to append only the two tokens
+%   \the\point@toks
+% and the two tokens
+%   \the\pageinfo@commands
+% to \everypar.  We need to do this because if a questions environment
+% immediately follows a \section command, then @nobreak will be true,
+% and so the \if@nobreak inside of \everypar will *not* execute the
+% \everypar={} that we had been counting on to keep the points from
+% being inserted a second time in the second paragraph of a question.
+% Since we've put the command \global \point@toks={} inside of 
+% \point@toks and the command \pageinfo@commands={} inside of
+% \pageinfo@commands, when the contents of \point@toks and of
+% \pageinfo@commands are executed when we enter horizontal mode and
+% \everypar is dumped in, the contents of \point@toks and
+% \pageinfo@commands will be made empty, and so if
+% the second paragraph also get \the\point@toks and
+% \the\pageinfo@commands, it won't matter.
+
+\def\item@points@pageinfo{%
+  \item
+  % If @qformat is true, and if we're currently doing a question
+  % (rather than a part, subpart, or subsubpart), then we don't want
+  % to set the points (if any), since the points of a question will
+  % appear only if the user chooses to cause that by putting a
+  % \thepoints in the argument of the \qformat command.
+  % 
+  % Also: We need to do this here, *after* the \item command, rather
+  % than inside the macro \@readpoints, because the \item command
+  % puts the result of the \qformat command into an \hbox (with the
+  % command ``\sbox\@tempboxa{\makelabel{#1}}%''), expanding the
+  % argument of \qformat as it does so.  Thus, @placepoints will be
+  % true when the argument of \qformat is expanded, and so if the
+  % user put a \thepoints command inside that argument it will
+  % correctly expand to the number of points.  (When @placepoints is
+  % false, \thepoints expands to nothing at all).
+  \if@qformat
+    \ifx\ques@ref\@queslevel
+      \global \@placepointsfalse
+    \fi
+  \fi
+  \if@placepoints
+    % \setup@point@toks defines \point@block to be a macro that prints
+    % the points with the correct choice of parentheses, brackets, or
+    % box, and \@pointname or \@marginpointname and puts commands into
+    % \point@toks to place \point@block at the correct spot.  It
+    % doesn't append anything to \everypar (we do that in this macro,
+    % below). 
+    \if@pointsdropped
+      % Do nothing!
+    \else
+      \setup@point@toks
+    \fi
+    \global \@placepointsfalse
+  \fi
+  % We *don't* use \append@toklist; see Bug fix note above
+  % We can append the tokens ``\the\point@toks'' whether or not we're
+  % setting any points because if we're not setting them, \point@toks
+  % will be empty.
+  % Also: It's important to do this *after* the \item command above,
+  % since the \item command discards the previous contents of
+  % \everypar.
+  \edef\append@everypar{\noexpand\everypar={\the\everypar
+                        \noexpand\the \noexpand\pageinfo@commands
+                        \noexpand\the \noexpand\point@toks}}%
+  \append@everypar
+  \do@int@lbl
+}
+
+
+
+
+
+
+
+% Initialize \@points:
+% (Now that I think of it, this seems totally unnecessary,
+% but we're not deleting it because we're chicken.)
+\def\@points{0}
+
+
+\def\setup@point@toks{%
+% We begin by defining \point@block so that it expands to the properly
+% formatted points (including either \pointname or \marginpointname,
+% enclosed in either parentheses, brackets, or a box).  We then set
+% the token list \point@toks equal to the sequence of commands needed
+% to put \point@block at the correct location, followed by the tokens
+% ``\global \point@toks={}''.  The \question, \part, \subpart, or 
+% \subsubpart command then adds the two tokens ``\the\point@toks'' to
+% \everypar.
+%
+% Note: It is not the *contents* of \point@toks that is added to
+% \everypar; just the two tokens ``\the\point@toks''.  This difference
+% is the bug fix of 2 April 2004, described above (the bug was that in
+% earlier versions, we used to append the contents).
+%
+% The result of this is that whenever we finally enter horizontal mode
+% (because we finally encountered the text of a question, part,
+% subpart, or subsubpart) the contents of \point@toks will be dumped
+% into horizontal mode and executed, and so the points will be placed
+% and the token list \point@toks will be set to empty.  Thus, in the
+% occasional circumstances in which \everypar is *not* set to empty
+% after being added to the first paragraph (which occurs when a
+% questions environment immediately follows a \section command), and
+% so \everypar will still contain ``\the\point@toks'' when it
+% encounters a possible second paragraph of the first question, the
+% tokens ``\the\point@toks'' will insert an *empty* token list, which
+% will do no harm.
+%
+%
+% \point@block consists of \point@string surrounded by either
+% parentheses, brackets, or an fbox.
+%
+% \point@string is either \@points\@pointname or
+% \@points\@marginpointname.
+  \setup@point@block
+  \if@pointsinleftmargin
+    \def\point@string{\@points\@marginpointname}%
+    \point@toks={%
+          \llap{\point@block 
+                \hskip\@totalleftmargin
+                \hskip\marginpointssep
+          }%
+          \global \point@toks={}%
+    }%
+  \else
+    \if@pointsinrightmargin
+      \def\point@string{\@points\@marginpointname}%
+      \point@toks={%
+            \rlap{\hskip-\@totalleftmargin
+                  \hskip\textwidth
+                  \hskip\@rightmargin
+                  \hskip-\rightpointsmargin
+                  \llap{\point@block}%
+            }%
+            \global \point@toks={}%
+      }%
+    \else
+      % The points just go after the question number:
+      \def\point@string{\@points\@pointname}%
+      \point@toks={%
+            \point@block
+            \enspace
+            \global \point@toks={}%
+      }%
+    \fi
+  \fi
+}% setup@point@toks
+
+
+\def\setup@point@block{%
+  \if@boxedpoints
+    \def\point@block{\fbox{\point@string}}%
+  \else
+    \if@bracketedpoints
+      \def\point@block{[\point@string]}%
+    \else
+      % plain old parentheses:
+      \def\point@block{(\point@string)}%
+    \fi
+  \fi
+}
+
+\def\droppoints{%
+  \def\point@string{\@points\@marginpointname}%
+  \setup@point@block
+  \leavevmode\unskip\nobreak\hfill
+  \rlap{\hskip\rightmargin  % Defined by the list environment
+        \hskip\@rightmargin % Defined by exam.cls
+        \hskip-\rightpointsmargin
+        \llap{\point@block}%
+  }% rlap
+  \par
+}
+
+% The following is the default definition.
+% It will be redefined if the user givea a \totalformat command.
+\def\setup@total@block{%
+  \def\total@block{%
+    Total for Question \thequestion: \totalpoints\@marginpointname
+  }%
+}
+
+\def\totalformat#1{%
+  \def\setup@total@block{\def\total@block{#1}}%
+}
+% The following is for use in the argument to a \totalformat command:
+\def\totalpoints{\pointsofquestion{\arabic{question}}}
+
+\def\droptotalpoints{%
+  \setup@total@block
+  \leavevmode\unskip\nobreak\hfill
+  \rlap{\hskip\rightmargin  % Defined by the list environment
+        \hskip\@rightmargin % Defined by exam.cls
+        \hskip-\rightpointsmargin
+        \llap{\total@block}%
+  }% rlap
+  \par
+}
+
+
+% @placepoints is set true when we encounter a question (or part, etc.)
+% that has points.  It is set to false (1) when we set \point@toks equal
+% to the sequence of commands required to put the properly formatted
+% points onto the page (this happens only if @qformat is false or if
+% @qformat is true but we're not doing a question), or (2) by a
+% \question or \part command (since if we're doing a question and
+% @qformat is true, we need to leave @placepoints true so that the
+% \thepoints command can tell if it should expand to points or to
+% nothing, and encountering a \question or \part command tells us that
+% we no longer have to deal with a possible \thepoints, since we won't
+% be expanding a qformat).
+\newif\if@placepoints
+\@placepointsfalse
+
+
+% \marginpointssep will be used if the user says
+% \pointsinleftmargin.  It will be the distance from whatever encloses
+% the points (parentheses, brackets, or a box) to the left margin:
+\newlength\marginpointssep
+\setlength{\marginpointssep}{5pt}
+
+% \rightpointsmargin will be used if the user says \pointsinrightmargin.
+% It will be the distance from whatever encloses the point (parentheses,
+% brackets, or a box) to the right edge of the paper:
+\newlength\rightpointsmargin
+\setlength{\rightpointsmargin}{1cm}
+
+
+\newif\if@pointsdropped
+\newif\if@pointsinleftmargin
+\newif\if@pointsinrightmargin
+\def\pointsinleftmargin{\global\@pointsinleftmargintrue 
+                    \global\@pointsinrightmarginfalse
+                    \global\@pointsdroppedfalse}
+\def\pointsinrightmargin{\global\@pointsinrightmargintrue
+                         \global\@pointsinleftmarginfalse
+                         \global\@pointsdroppedfalse}
+\def\nopointsinmargin{\global\@pointsinleftmarginfalse
+                      \global\@pointsinrightmarginfalse
+                      \global\@pointsdroppedfalse}
+\def\pointsdroppedatright{\global\@pointsdroppedtrue
+                          \global\@pointsinleftmarginfalse
+                          \global\@pointsinrightmarginfalse}
+\let\pointsinmargin\pointsinleftmargin
+\let\nopointsinrightmargin\nopointsinmargin
+\let\nopointsinleftmargin\nopointsinmargin
+
+
+\nopointsinmargin
+
+
+% Will the points be displayed inside parentheses (the default), or
+% will they be boxed or bracketed:
+\newif\if@boxedpoints
+\def\boxedpoints{\global\@boxedpointstrue \global\@bracketedpointsfalse}
+\def\noboxedpoints{\global\@boxedpointsfalse \global\@bracketedpointsfalse}
+\@boxedpointsfalse
+
+\newif\if@bracketedpoints
+\def\bracketedpoints{\global\@bracketedpointstrue \global\@boxedpointsfalse}
+\def\nobracketedpoints{\global\@bracketedpointsfalse \global\@boxedpointsfalse}
+\@bracketedpointsfalse
+
+
+
+\def\pointname#1{\gdef\@pointname{#1}}
+% Initialize to leave a space, and then the word `points':
+%%\pointname{ points}
+% The following improvement was contributed by 
+% Mate Wierdl <mw@wierdlmpc.msci.memphis.edu> 
+% If the number of points is ``1'', then the default value of
+% \pointname will print `` point'' instead of `` points'' (and this
+% version of the command doesn't generate an error message if the
+% points entry is something other than a number):
+% Note the space before the \points in the following; it's
+% intentional!)
+\pointname{ \points}
+
+\newcommand\point@sing{point}
+\newcommand\point@plur{points}
+\newcommand\pointpoints[2]{%
+  \renewcommand\point@sing{#1}%
+  \renewcommand\point@plur{#2}%
+}
+
+
+
+% The command \points:
+% We use \ifthenelse and \equal so that if the user types something
+% other than a legit point value, there still won't be any error
+% messages.  We rig it so that if the point value looks like it's
+% intended to be One or one or ONE, or some strange way of attempting
+% one half, then it will expand to the singular value.  Alas, this is
+% only useful for English, but I'm hoping few or no users will try doing
+% this anyway.
+
+% 0 points, one half point, 1 point, 1 and a half points, etc.:
+\newcommand\points{%
+  \begingroup
+    \let\half=\relax
+    \edef\pt@string{\@points}%
+    \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half}}
+          {\point@sing}{\point@plur}%
+  \endgroup
+}
+%\newcommand\points{%
+%  \begingroup
+%    \let\half=\relax
+%    \edef\pt@string{\@points}%
+%    \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half} \or
+%      \equal{\pt@string}{0\half} \or \equal{\pt@string}{0 \half}
+%      \equal{\pt@string}{one} \or \equal{\pt@string}{One} \or
+%      \equal{\pt@string}{ONE}}
+%        {\point@sing}{\point@plur}%
+%  \endgroup
+%}
+
+%\newcommand\points{\ifthenelse{\equal{\@points}{1}}{\point@sing}{\point@plur}}
+% If we used the following line instead, then you'd get an error
+% message if the point value contained something other than a valid
+% integer:
+%\pointname{ \ifthenelse{\@points = 1}{point}{points}}
+
+% We used to define a command named \marks that works like \points,
+% except that it expands to either ``mark'' or ``marks'', but that
+% conflicts with some package or other.  Thus, we'll implement
+% \marksnotpoints using the \pointpoints command instead:
+\newcommand\marksnotpoints{\pointpoints{mark}{marks}}
+
+
+% \@marginpointname is used in place of \@pointname if any of
+% \@pointsinmargin, \@pointsinrightmargin, and \@pointsdropped are
+% true:
+\def\marginpointname#1{\gdef\@marginpointname{#1}}
+\marginpointname{}
+
+
+% The following keeps track of whether the user has requested that we
+% add up the points on the exam.  We make the default false so that
+% users who put other than numbers into the points argument of a
+% question (or part, or subpart) won't get error messages.
+% We use \if@printtotalpoints as a flag to signal that we are counting
+% points, so that we will know to print the total on the screen (and
+% in the log file).  We use this separate flag so that the user can
+% use both \addpoints and \noaddpoints to count some points and not
+% others, but still have the total printed when we finish the file no
+% matter what the state of \if@addpoints.
+\newif\if@addpoints
+\newif\if@printtotalpoints
+\def\addpoints{\global\@addpointstrue\global\@printtotalpointstrue}
+\def\noaddpoints{\global\@addpointsfalse}
+\@addpointsfalse
+\@printtotalpointsfalse
+
+%--------------------------------------------------------------------
+%                   choices (for multiple choice)
+
+
+\renewcommand\thechoice{\Alph{choice}}
+\newcommand\choicelabel{\thechoice.}
+
+% Added 22 April 2004: Increased the \leftmargin by 2.5em,
+% so the choices will be visibly indented.
+\newenvironment{choices}%
+  {\list{\choicelabel}%
+     {\usecounter{choice}\def\makelabel##1{\hss\llap{##1}}%
+       \settowidth{\leftmargin}{W.\hskip\labelsep\hskip 2.5em}%
+       \let\choice=\item
+       \labelwidth\leftmargin\advance\labelwidth-\labelsep
+       \topsep=0pt
+       \partopsep=0pt
+     }%
+  }%
+  {\endlist}
+
+\newenvironment{oneparchoices}%
+  {%
+    \setcounter{choice}{0}%
+    \def\choice{%
+                 \refstepcounter{choice}%
+                 \ifnum\value{choice}>1
+                   \penalty -50\hskip 1em plus 1em\relax
+                 \fi
+                 \choicelabel\nobreak\enskip
+               }%
+    \let\par\@empty
+    % If we're continuing the paragraph containing the question,
+    % then leave a bit of space before the first choice:
+    \ifvmode\else\enskip\fi
+    \ignorespaces
+  }%
+  {}
+
+
+%--------------------------------------------------------------------
+%             Answer Lines (for short answer questions)
+
+% Note: \ques@ref is also used in \item@points@pageinfo
+
+\def\ques@ref{question}
+\def\part@ref{part}
+\def\subpart@ref{subpart}
+\def\subsubpart@ref{subsubpart}
+
+\newlength\answerlinelength
+\newlength\answerskip
+\setlength\answerlinelength{1in}
+\setlength\answerskip{2ex}
+
+\def\answerline{%
+  \ifx\@queslevel\ques@ref
+    \let\ans@l=\questionlabel
+  \else
+    \ifx\@queslevel\part@ref
+      \let\ans@l=\partlabel
+    \else
+      \ifx\@queslevel\subpart@ref
+        \let\ans@l=\subpartlabel
+      \else
+        \ifx\@queslevel\subsubpart@ref
+          \let\ans@l=\subsubpartlabel
+        \else
+          % Oops; no question level defined.
+          % We must be outide of the questions environment.
+          % Just leave out the label, I guess:
+          \def\ans@l{}%
+        \fi
+      \fi
+    \fi
+  \fi
+  \par \nobreak \vskip \answerskip
+  \hfill \ans@l~\hbox to \answerlinelength{\hrulefill}%
+  \par
+}
+
+%--------------------------------------------------------------------
+%                            \fillwithlines
+
+
+% \fillwithlines takes one argument, which is either a length or \fill,
+% and it fills that much vertical space with horizontal lines that run
+% the length of the current line.  That is, the extend from the current
+% left margin (which depends on whether we're in a quesiton, parts,
+% subpart, or subsubpart) to the right margin.
+%
+% The distance between the lines is \linefillheight, whose default value
+% is set with the command
+%
+% \setlength\linefillheight{.25in}
+%
+% This value can be changed by giving a new \setlength command.
+%
+% The thickness of the lines is \linefillthickness, whose default value
+% is set with the command
+%
+% \setlength\linefillthickness{.2pt}
+%
+% This value can be changed by giving a new \setlength command.
+
+
+\newlength\linefillheight
+\newlength\linefillthickness
+\setlength\linefillheight{.25in}
+\setlength\linefillthickness{0.1pt}
+
+\newcommand\linefill{\leavevmode
+    \leaders\hrule height \linefillthickness \hfill\kern\z@}
+
+
+\def\fillwithlines#1{%
+  \begingroup
+  \ifhmode
+    \par
+  \fi
+  \hrule height \z@
+  \nobreak
+  \setbox0=\hbox to \hsize{\hskip \@totalleftmargin
+          \vrule height \linefillheight depth \z@ width \z@
+          \linefill}%
+  % We use \cleaders (rather than \leaders) so that a given
+  % vertical space will always produce the same number of lines
+  % no matter where on the page it happens to start:
+  \cleaders \copy0 \vskip #1 \hbox{}%
+  \endgroup
+}
+
+
+%--------------------------------------------------------------------
+%                      \uplevel and \fullwidth:
+
+% \uplevel is used to print text at the indentation level of the 
+% enclosing environment.  For example, to precede a question with
+% directions about how that question should be answered, you would
+% say \uplevel{Answer this question correctly.}
+% 
+% \fullwidth is similar, but uses the full page of text on the page.
+
+\long\def\uplevel#1{%
+  \par\bigskip
+  \vbox{%
+    % We set \leftskip to provide the correct left margin for whatever
+    % text is in the argument of the \uplevel command:
+    \leftskip=\@totalleftmargin
+    \advance\leftskip-\leftmargin
+    % We adjust \@totalleftmargin (and linewidth?) in case there's a
+    % solution environment inside of the argument to the \uplevel:
+    \advance\@totalleftmargin-\leftmargin
+    \advance\linewidth\leftmargin
+    #1%
+  }% vbox
+  \nobreak
+}
+
+\long\def\fullwidth#1{%
+  \par\bigskip
+  \vbox{%
+    \leftskip=0pt \rightskip=0pt
+    \advance\linewidth\@totalleftmargin
+    \@totalleftmargin=0pt
+    #1%
+  }% vbox
+  \nobreak
+}
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%
+%                        ********************
+%                        ** GRADING TABLES **
+%                        ********************
+
+
+
+\newcounter{@iterator}
+\newlength\@cellwidth
+
+\def\cellwidth#1{\@cellwidth=#1}
+\def\gradetablestretch#1{\def\@gtblstretch{#1}}
+
+% All of the following that begin with `h' are for horizontal tables,
+% and all of them that begin with `v' are for vertical tables:
+\def\hqword#1{\def\@hqword{#1}}
+\def\hpword#1{\def\@hpword{#1}}
+\def\hsword#1{\def\@hsword{#1}}
+\def\htword#1{\def\@htword{#1}}
+\def\vqword#1{\def\@vqword{#1}}
+\def\vpword#1{\def\@vpword{#1}}
+\def\vsword#1{\def\@vsword{#1}}
+\def\vtword#1{\def\@vtword{#1}}
+
+\def\vpgword#1{\def\@vpgword{#1}}
+\def\hpgword#1{\def\@hpgword{#1}}
+
+% Initialize:
+\cellwidth{2em}
+\gradetablestretch{1.5}
+\hpword{Points:}
+\hsword{Score:}
+\htword{Total}
+\vpword{Points}
+\vsword{Score}
+\vtword{Total:}
+
+% For tables indexed by question number:
+\vqword{Question}
+\hqword{Question:}
+
+% For tables indexed by page number:
+\vpgword{Page}
+\hpgword{Page:}
+
+
+
+% The only command here accessible to the user is \gradetable.
+% The possibilities are
+
+%   \gradetable[v][questions]
+%   \gradetable[v][pages]
+%   \gradetable[h][questions]
+%   \gradetable[h][pages]
+
+% If one or both optional arguments are omitted, the defaults are `[v]'
+% and `[questions]'.
+
+\def\gradetable{%
+  % If the user doesn't include the optional argument
+  % choosing between vertical and horizontal,
+  % we give them vertical:
+  \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
+}
+\def\i@gtable[#1]{%
+  % If the user doesn't include the optional argument
+  % choosing between questions and pages,
+  % we give them questions:
+  \@ifnextchar[{\ii@gtable{#1}}{\ii@gtable{#1}[questions]}%
+}
+\def\ii@gtable#1[#2]{%
+  \if@addpoints
+    \@ifundefined{exam@numpoints}%
+      {\ClassWarning{exam}%
+        {%
+          You must run LaTeX again to produce the grade table.
+            \MessageBreak
+        }%
+        \fbox{Run \LaTeX{} again to produce the table}%
+      }%
+      {\do@gtable{#1}{#2}}%
+  \else
+    \ClassError{exam}{%
+      You must give the command \protect\addpoints\MessageBreak
+      \space\space in order to use the command \protect\gradetable
+      \MessageBreak
+      }{%
+      If you don't give the command \protect\addpoints\MessageBreak
+      \space\space then we're not keeping track of point values.
+      \MessageBreak
+      }%
+  \fi
+}
+\def\@questionsref{questions}
+\def\@pagesref{pages}
+\def\do@gtable#1#2{%
+  \begingroup % avoid trouble from using \@temp
+    \def\@temp{#2}%
+    \ifx\@temp\@questionsref
+      \@grdtblquestions{#1}%
+    \else
+      \ifx\@temp\@pagesref
+        \@grdtblpages{#1}%
+      \else
+        \ClassError{exam}{%
+          The second optional argument to \protect\gradetable \MessageBreak
+          \space \space must be either `questions' or `pages'\MessageBreak
+        }{%
+          Grade tables can be indexed by questions or pages;\MessageBreak
+          \space\space for others, you're on your own.\MessageBreak
+        }%
+        \fbox{Error: Grade table: Invalid second optional argument `#1'.}%
+      \fi
+    \fi
+  \endgroup
+}
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+% Grading tables indexed by question numbers:
+
+\def\@grdtblquestions#1{%
+  \if v#1%
+    \@vgrdtblquestions
+  \else
+    \if h#1%
+      \@hgrdtblquestions
+    \else
+      \ClassError{exam}{%
+        The first optional argument to \protect\gradetable \MessageBreak
+        \space \space must be either `h' or `v'\MessageBreak
+      }{%
+        Grade tables can be either horizontal or vertical;\MessageBreak
+        \space\space no diagonals allowed.\MessageBreak
+      }%
+      \fbox{Error: Grade table: Invalid first optional argument `#1'.}%
+    \fi
+  \fi
+}
+
+%--------------------------------------------------------------------
+% Vertical, indexed by question numbers:
+
+\def\@vgrdtblquestions{%
+  \begingroup
+    % Save the current value of question in @iterator, so that
+    % we cna restore it after doing the table:
+    \setcounter{@iterator}{\arabic{question}}%
+    \renewcommand\arraystretch{\@gtblstretch}%
+    \begin{tabular}{|c|c|c|}
+      \hline
+      {\@vqword}& {\@vpword}& {\@vsword}\\
+      \hline
+      \setcounter{question}{0}\do@vloop
+      {\@vtword}& \numpoints&\hbox to \@cellwidth{\hfill}\\
+      \hline
+    \end{tabular}%
+    % Restore the saved value of question:
+    \setcounter{question}{\arabic{@iterator}}%
+  \endgroup
+}
+\def\do@vloop{%
+  \addtocounter{question}{1}%
+  \thequestion & \pointsofquestion{\arabic{question}}&\\
+  \hline
+  \ifnum \arabic{question} < \numquestions\relax
+    \let\next@vloop=\do@vloop
+  \else
+    \let\next@vloop=\relax
+  \fi
+  \next@vloop
+}
+
+%--------------------------------------------------------------------
+% Horizontal, indexed by question numbers:
+
+\def\@hgrdtblquestions{%
+  \begingroup
+    % Save the current value of question in @iterator, so that
+    % we can restore it after doing the table:
+    \setcounter{@iterator}{\arabic{question}}%
+    \renewcommand\arraystretch{\@gtblstretch}%
+    \begin{tabular}{|l|*{\numquestions}{c|}c|}
+      \hline
+      {\@hqword}& \setcounter{question}{0}\do@qnumloop
+      {\@htword}\\
+      \hline
+      {\@hpword}& \setcounter{question}{0}\do@ptloop
+      \numpoints\\
+      \hline
+      {\@hsword}& \setcounter{question}{0}\do@sloop
+      \\
+      \hline
+    \end{tabular}%
+    % Restore the saved value of question:
+    \setcounter{question}{\arabic{@iterator}}%
+  \endgroup
+}
+\def\do@qnumloop{%
+  \addtocounter{question}{1}%
+  \thequestion &
+  \ifnum \arabic{question} < \numquestions\relax
+    \let\next@qnloop=\do@qnumloop
+  \else
+    \let\next@qnloop=\relax
+  \fi
+  \next@qnloop
+}
+\def\do@ptloop{%
+  \addtocounter{question}{1}%
+  \pointsofquestion{\arabic{question}}&
+  \ifnum \arabic{question} < \numquestions\relax
+    \let\next@ptloop=\do@ptloop
+  \else
+    \let\next@ptloop=\relax
+  \fi
+  \next@ptloop
+}
+\def\do@sloop{%
+  \addtocounter{question}{1}%
+  \hbox to \@cellwidth{\hfill}&
+  \ifnum \arabic{question} < \numquestions\relax
+    \let\next@sloop=\do@sloop
+  \else
+    \let\next@sloop=\relax
+  \fi
+  \next@sloop
+}
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+% Grading tables indexed by page numbers:
+%
+% The only pages listed are those on which there is a nonzero number
+% of points.  We check pages 1 through \lastpage@withpoints; this way,
+% once we've checked that \lastpage@withpoints and
+% \pointsonpage@\romannumeral{\lastpage@withpoints} are defined, we
+% can safely (we think) check \pointsonpage@\romannumeral{n} for all n
+% between 1 and \lastpage@withpoints without generating errors.
+
+% Check that there's enough info from the .aux file to do a page
+% indexed grade table:
+\def\@grdtblpages#1{%
+  \@ifundefined{lastpage@withpoints}%
+    {\ClassWarning{exam}{%
+      You must run LaTeX twice more\MessageBreak
+      \space\space to produce the grade table.\MessageBreak}%
+     \fbox{Run \LaTeX{} twice more to produce the grade table}%
+    }%
+    {%
+      \@ifundefined{pointsonpage@\romannumeral
+               \csname lastpage@withpoints\endcsname}%
+        {\ClassWarning{exam}{%
+          You must run LaTeX again\MessageBreak
+          \space\space to produce the grade table.\MessageBreak}%
+         \fbox{Run \LaTeX{} again to produce the grade table}%
+        }%
+        {%
+          \@whchtblpgs#1
+        }%
+    }%
+}
+
+\def\@whchtblpgs#1{%
+  \if v#1%
+    \@vgrdtblpages
+  \else
+    \if h#1%
+      \@hgrdtblpages
+    \else
+      \ClassError{exam}{%
+        The first optional argument to \protect\gradetable \MessageBreak
+        \space \space must be either `h' or `v'\MessageBreak
+      }{%
+        Grade tables can be either horizontal or vertical;\MessageBreak
+        \space\space no diagonals allowed.\MessageBreak
+      }%
+      \fbox{Error: Grade table: Invalid first optional argument `#1'.}%
+    \fi
+  \fi
+}
+
+%--------------------------------------------------------------------
+% Vertical, indexed by pages:
+
+\def\@vgrdtblpages{%
+  \begingroup
+    \renewcommand\arraystretch{\@gtblstretch}%
+    \begin{tabular}{|c|c|c|}
+      \hline
+      {\@vpgword}& {\@vpword}& {\@vsword}\\
+      \hline
+      \setcounter{@iterator}{0}\pg@vloop
+      {\@vtword}& \numpoints&\hbox to \@cellwidth{\hfill}\\
+      \hline
+    \end{tabular}%
+  \endgroup
+}
+\def\pg@vloop{%
+  \addtocounter{@iterator}{1}%
+  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
+                              \csname c@@iterator\endcsname\endcsname}%
+%  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\roman{@iterator}\endcsname}%
+%  spanish.ldf redefines \@roman, so we'll avoid \roman
+  \ifhlfcntr@pos{tmp@hlfcntr}%
+    \pg@vloopline
+  \fi
+  \ifnum \the@iterator < \lastpage@withpoints\relax
+    \let\next@pg@vloop=\pg@vloop
+  \else
+    \let\next@pg@vloop=\relax
+  \fi
+  \next@pg@vloop
+}
+\def\pg@vloopline{%
+  % We still don't understand why we need to hide this inside of a
+  % macro; there's some weird interaction with the \ifnum checking to
+  % see if something is ``>0''; checking that something is ``=0''
+  % doesn't cause the ``\ifnum incomplete'' (or whatever) error.
+  \the@iterator & \pointsonpage{\the@iterator}&\\
+  \hline
+}
+
+%--------------------------------------------------------------------
+% Horizontal, indexed by pages:
+
+% For a horizontal table, we need to know how many pages there are
+% with points on them:
+\newcounter{numpgs@withpts}
+\def\count@pgswpts{%
+  \setcounter{numpgs@withpts}{0}%
+  \setcounter{@iterator}{0}%
+  \docount@pgswpts
+}
+\def\docount@pgswpts{%
+  \addtocounter{@iterator}{1}%
+  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
+                              \csname c@@iterator\endcsname\endcsname}%
+%  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\roman{@iterator}\endcsname}%
+%  spanish.ldf redefines \@roman, so we'll avoid \roman
+  \ifhlfcntr@pos{tmp@hlfcntr}%
+    \addtocounter{numpgs@withpts}{1}%
+  \fi
+  \ifnum \the@iterator < \lastpage@withpoints\relax
+    \let\next@docount=\docount@pgswpts
+  \else
+    \let\next@docount=\relax
+  \fi
+  \next@docount
+}
+
+
+\def\@hgrdtblpages{%
+  \begingroup
+    \renewcommand\arraystretch{\@gtblstretch}%
+    \count@pgswpts
+    \begin{tabular}{|l|*{\thenumpgs@withpts}{c|}c|}
+      \hline
+      {\@hpgword}& \setcounter{@iterator}{0}\do@pgnumloop
+      {\@htword}\\
+      \hline
+      {\@hpword}& \setcounter{@iterator}{0}\do@pgptloop
+      \numpoints\\
+      \hline
+      {\@hsword}& \setcounter{@iterator}{0}\do@pgsloop
+      \\
+      \hline
+    \end{tabular}%
+  \endgroup
+}
+
+\def\do@pgnumloop{%
+  \addtocounter{@iterator}{1}%
+  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
+                             \csname c@@iterator\endcsname\endcsname}%
+%  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\roman{@iterator}\endcsname}%
+%  spanish.ldf redefines \@roman, so we'll avoid \roman
+  \ifhlfcntr@pos{tmp@hlfcntr}%
+    \pg@line
+  \fi
+  \ifnum \the@iterator < \lastpage@withpoints\relax
+    \let\next@pgnumloop=\do@pgnumloop
+  \else
+    \let\next@pgnumloop=\relax
+  \fi
+  \next@pgnumloop
+}
+\def\pg@line{%
+  \the@iterator &
+}
+
+\def\do@pgptloop{%
+  \addtocounter{@iterator}{1}%
+  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
+                              \csname c@@iterator\endcsname\endcsname}%
+%  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\roman{@iterator}\endcsname}%
+%  spanish.ldf redefines \@roman, so we'll avoid \roman
+  \ifhlfcntr@pos{tmp@hlfcntr}%
+    \pgpt@line
+  \fi
+  \ifnum \the@iterator < \lastpage@withpoints\relax
+    \let\next@pgptloop=\do@pgptloop
+  \else
+    \let\next@pgptloop=\relax
+  \fi
+  \next@pgptloop
+}
+\def\pgpt@line{%
+  \csname pointsonpage@\romannumeral \csname c@@iterator\endcsname\endcsname &
+%  \csname pointsonpage@\roman{@iterator}\endcsname &
+%  spanish.ldf redefines \@roman, so we'll avoid \roman
+}
+
+\def\do@pgsloop{%
+  \addtocounter{@iterator}{1}%
+%  \ifnum \csname pointsonpage@\roman{@iterator}\endcsname > 0\relax
+  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
+                              \csname c@@iterator\endcsname\endcsname}%
+%  \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\roman{@iterator}\endcsname}%
+%  spanish.ldf redefines \@roman, so we'll avoid \roman
+  \ifhlfcntr@pos{tmp@hlfcntr}%
+    \pg@sline
+  \fi
+  \ifnum \the@iterator < \lastpage@withpoints\relax
+    \let\next@pgsloop=\do@pgsloop
+  \else
+    \let\next@pgsloop=\relax
+  \fi
+  \next@pgsloop
+}
+\def\pg@sline{%
+  \hbox to \@cellwidth{\hfill}&
+}
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+%
+%                     ***************************
+%                     ** SOLUTION ENVIRONMENTS **
+%                     ***************************
+
+
+
+% If the documentclass options include ``answers'', then the command
+% \@printanswerstrue is given at the beginning of the run.
+
+% If the documentclass options include ``noanswers'', then the command
+% \@printanswersfalse is given at the beginning of the run.
+
+\def\printanswers{\@printanswerstrue}
+\def\noprintanswers{\@printanswersfalse}
+
+
+% If @printanswers is true, we print the solution using a TheSolution
+% environment.  If @printanswers is false, we insert blank vertical space
+% equal to the optional argument (the default value of which is 0pt).
+\newenvironment{solution}[1][0pt]%
+  {%
+    \if@printanswers
+      \begin{TheSolution}%
+    \else
+      \par
+      \vspace*{#1}%
+      \setbox\z@\vbox\bgroup
+    \fi
+  }{%
+    \if@printanswers
+      \end{TheSolution}%
+    \else
+      \egroup
+    \fi
+  }%
+
+% If @printanswers is true, we print the solution using a TheSolution
+% environment.  If @printanswers is false, we insert lined vertical space
+% equal to the optional argument (the default value of which is 0pt).
+\newenvironment{solutionorlines}[1][0pt]%
+  {%
+    \if@printanswers
+      \begin{TheSolution}%
+    \else
+      \par
+      \fillwithlines{#1}%
+      \setbox\z@\vbox\bgroup
+    \fi
+  }{%
+    \if@printanswers
+      \end{TheSolution}%
+    \else
+      \egroup
+    \fi
+  }%
+
+  
+% The environment TheSolution is called from the solution environment
+% when @printanswers is true.  It uses Donald Arseneau's
+% framed.sty macros (included at the end if this file) to allow the
+% solution to be broken across pages and have each piece enclosed in
+% an fbox (or a colorbox, if the user has given the command
+% \shadedsolution).
+%
+% Of course, the user can change TheSolution with a \renewenvironment
+% command.
+\newcommand{\solutiontitle}{\noindent\textbf{Solution:}\enspace}
+\newenvironment{TheSolution}%
+  {%
+    \vspace{\parskip}%
+    % If we don't set \leftskip and \rightskip to 0pt, then if we
+    % appear inside of an \uplevel command we'd have indentation
+    % inside of the solution box:
+    \leftskip=0pt
+    \rightskip=0pt
+    \if@framedsolutions
+      % Do nothing; we'll use the default \FrameCommand
+    \else
+      \def\FrameCommand{\colorbox{SolutionColor}}%
+    \fi
+    \MakeFramed{\advance\hsize-\width}%
+    \solutiontitle
+    \ignorespaces
+  }%
+  {%
+    \unskip
+    \endMakeFramed
+  }%
+
+\newif\if@framedsolutions
+\@framedsolutionstrue
+
+\def\framedsolutions{\@framedsolutionstrue}
+\def\shadedsolutions{%
+  \@ifundefined{definecolor}
+  {%
+    \ClassError{exam}{%
+      You must load the color package with the command\MessageBreak
+      \space\space\protect\usepackage{color}\MessageBreak
+      in order to use the command \protect\colorsolutions
+      \MessageBreak
+      }{%
+      This command makes use of the package color.sty,\MessageBreak
+      and so you have to load color.sty before your\MessageBreak
+      \protect\begin{document} command.\MessageBreak
+      }%
+  }%
+  {%
+    \definecolor{SolutionColor}{gray}{0.8}
+    \@framedsolutionsfalse
+  }%
+}
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+
+% The following stuff is lifted from:
+%
+% framed.sty   v 0.8a   21-Jul-2003
+% Copyright (C) 1992-2003 by Donald Arseneau
+% These macros may be freely transmitted, reproduced, or modified
+% provided that this notice is left intact.
+%
+% The modifications I made are marked with ``psh'' in a comment:
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create framed or shaded regions that can break across pages using 
+% \begin{framed} ... \end{framed}    -- ordinary frame box (box at margin)
+% \begin{shaded} ... \end{shaded}    -- shaded background (into margin)
+%    ... leftbar ...                 -- line on left side
+% \begin{MakeFramed}{settings} ... \end{MakeFramed}
+%                        -- generic frame (for new environments)
+%
+% The "framed" environment puts the text into "\fbox" with the
+% settings "\fboxrule=\FrameRule" and "\fboxsep=\FrameSep".
+% You can change these lengths (using "\setlength") and you
+% can even change the definition of "\FrameCommand" to use
+% much fancier boxes.
+%
+% In fact, the "shaded" environment just redefines "\FrameCommand"
+% to use "\colorbox{shadecolor}" (and you have to define the
+% color "shadecolor": \newcolor{shadecolor}...).
+%
+% A page break is allowed, and even encouraged, before the framed
+% environment.  If you want to attach some text (a box title) to the
+% frame, then the text should be inserted by \FrameCommand
+%
+% The contents of the framed regions are restricted: 
+% Floats, footnotes, marginpars and head-line entries will be lost.
+% (Some of these may be handled in a later version.)
+% This package will not work with the page breaking of multicol.sty,
+% or other systems that perform column-balancing.
+%
+% The MakeFramed environment does the work.  Its "settings" argument
+% should contain any adjustments to the text width (applied to \hsize,
+% and using the "\width" of the frame itself) as well as a `restore' 
+% command -- \@parboxrestore or \FrameRestore or something similar.
+% 
+% Expert commands:
+% \MakeFramed, \endMakeFramed: the "MakeFramed" environment
+% \FrameCommand: command to draw the frame around its argument
+% \FrameRestore: restore some text settings, but fewer than \@parboxrestore
+% \FrameRule: length register; \fboxrule for default "framed".
+% \FrameSep: length register; \fboxsep for default "framed".
+% \FrameHeightAdjust: macro; height of frame above baseline at top of page
+% 
+% This is still a `pre-production' version because I can think of many
+% features/improvements that should be made.  Nevertheless, starting 
+% with version 0.5 it should be bug-free.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%psh: Commented out \ProvidesPackage:
+%\ProvidesPackage{framed}[2003/07/21 v 0.8a: 
+%   framed or shaded text with page breaks]
+
+%psh: Created \saved@totalleftmargin and \@sollistdepth:
+\newdimen\saved@totalleftmargin
+\newcount\@sollistdepth
+
+\newenvironment{framed}% using default \FrameCommand
+  {\MakeFramed {\advance\hsize-\width \FrameRestore}}%
+  {\endMakeFramed}
+
+\newenvironment{shaded}{%
+  \def\FrameCommand{\colorbox{shadecolor}}%
+  \MakeFramed {\FrameRestore}}%
+ {\endMakeFramed}
+
+\newenvironment{leftbar}{%
+  \def\FrameCommand{\vrule width 3pt \hspace{10pt}}%
+  \MakeFramed {\advance\hsize-\width \FrameRestore}}%
+ {\endMakeFramed}
+
+\chardef\FrameRestore=\catcode`\| % for debug
+\catcode`\|=\catcode`\% % (debug: insert space after backslash)
+
+\def\MakeFramed#1{\par
+ % measure added width and height; call result \width and \height
+ \setbox\z@\vbox{\vskip-1in \hbox{\hskip-1in 
+   \FrameCommand{\hbox{\vrule \@height .7in \@depth.3in \@width 1in}}}%
+   \vskip\z@skip}%
+ \def\width{\wd\z@}\def\height{\ht\z@}%
+ \edef\fb@frw{\the\width}\edef\fb@frh{\the\height}%
+ % insert pre-penalties and skips
+ \begingroup
+ \skip@\lastskip
+ \if@nobreak\else 
+    \penalty9999 % updates \page parameters
+    \ifdim\pagefilstretch=\z@ \ifdim\pagefillstretch=\z@
+       \edef\@tempa{\the\skip@}%
+       \ifx\@tempa\zero@glue \penalty-30
+       \else \vskip-\skip@ \penalty-30 \vskip\skip@
+    \fi\fi\fi
+    \penalty\z@
+    % Give a stretchy breakpoint that will always be taken in preference
+    % to the \penalty 9999 used to update page parameters.  The cube root
+    % of 10000/100 indicates a multiplier of 0.21545, but the maximum 
+    % calculated badness is really 8192, not 10000, so the multiplier
+    % is 0.2301. 
+    \advance\skip@ \z@ plus-.5\baselineskip
+    \advance\skip@ \z@ plus-.231\height
+    \advance\skip@ \z@ plus-.231\skip@
+    \advance\skip@ \z@ plus-.231\topsep
+    \vskip-\skip@ \penalty 1800 \vskip\skip@
+ \fi
+ \addvspace{\topsep}%
+ \endgroup
+ % clear out pending page break
+ \penalty\@M \vskip 2\baselineskip \vskip\height
+ \penalty9999 \vskip -2\baselineskip \vskip-\height
+ \penalty9999 % updates \pagetotal
+|\message{After clearout, \pagetotal=\the\pagetotal, \pagegoal=\the\pagegoal. }%
+ \fb@adjheight 
+%psh: Added commands:
+  \advance\hsize-\@totalleftmargin
+  \saved@totalleftmargin=\@totalleftmargin
+  \@totalleftmargin=0pt
+  \parshape 0
+  \let\@listdepth=\@sollistdepth
+  \@sollistdepth=0
+  \leftmargin=0pt
+%psh: end of added commands
+ \setbox\@tempboxa\vbox\bgroup
+   #1% Modifications to \hsize (can use \width and \height)
+   \textwidth\hsize \columnwidth\hsize
+%psh: added one line:
+   \linewidth=\hsize
+}
+
+\def\endMakeFramed{\par
+     \kern\z@ \penalty-100 % put depth into height
+ \egroup
+ \begingroup \put@frame \endgroup
+%psh: Added one line:
+ \@totalleftmargin=\saved@totalleftmargin
+}
+
+% \put@frame takes the contents of \@tempboxa and puts all, or a piece,
+% of it on the page with a frame (\FrameCommand).  It recurses until
+% all of \@tempboxa has been used up. (\@tempboxa must have zero depth.)
+
+\def\put@frame{\relax
+ \ifdim\pagegoal=\maxdimen \pagegoal\vsize \fi
+|   \message{=============== Entering putframe ====================^^J
+|     \pagegoal=\the\pagegoal,  \pagetotal=\the\pagetotal. }%
+ \ifinner \else
+    \dimen@\pagegoal \advance\dimen@-\pagetotal % natural space left on page
+  \ifdim\dimen@<2\baselineskip 
+|   \message{Page has only \the\dimen@\space room left; eject. }%
+    \eject \fb@adjheight \put@frame
+  \else % there's appreciable room left on the page
+|    \message{\string\pagetotal=\the\pagetotal,
+|        \string\pagegoal=\the\pagegoal, 
+|        \string\pagestretch=\the\pagestretch,
+|        \string\pageshrink=\the\pageshrink,
+|        \string\fb@frh=\fb@frh. \space}
+|    \message{Box of size \the\ht\@tempboxa\space + \fb@frh}%
+     \begingroup % temporarily set \dimen@ to be...
+     \advance\dimen@.8\pageshrink  % maximum space available on page
+     \advance\dimen@-\fb@frh\relax % space available for frame's contents
+     \expandafter\endgroup
+     % restore \dimen@ to real room left on page
+     \ifdim\dimen@>\ht\@tempboxa % whole box does fit
+|       \message{fits in \the\dimen@. }%
+     \else % box must be split
+|       \message{must be split to fit in \the\dimen@. }%
+        \setbox\@tempboxa\vbox{% simulate frame and flexiblity of the page:
+           \vskip \fb@frh \@plus\pagestretch \@minus.8\pageshrink
+           \kern137sp\kern-137sp\penalty-30
+           \unvbox\@tempboxa}%
+        \edef\fb@resto@set{\boxmaxdepth\the\boxmaxdepth \splittopskip\the\splittopskip}%
+        \boxmaxdepth\z@ \splittopskip\z@
+        \setbox\tw@\vsplit\@tempboxa to\dimen@
+        \setbox\tw@\vbox{\unvbox\tw@}% natural-sized
+|       \message{Box of size \the\ht\@tempboxa\space split to \the\dimen@. 
+|          Natural height of split box is \the\ht\tw@. }%
+        % If the split-to size > (\vsize-\topskip), then set box to full size
+        \begingroup
+          \advance\dimen@\topskip
+          \expandafter\endgroup
+        \ifdim\dimen@>\pagegoal
+|         \message{Frame is big -- Use up the full column. }%
+          \dimen@ii\pagegoal
+          \advance\dimen@ii -\topskip
+          \advance\dimen@ii \FrameHeightAdjust\relax
+        \else  % suspect this is wrong:
+          % If the split-to size > feasible room_on_page, rebox it smaller.
+          \advance\dimen@.8\pageshrink
+          \ifdim\ht\tw@>\dimen@
+|           \message{Box too tall; rebox it to \the\dimen@. }%
+            \dimen@ii\dimen@
+          \else % use natural size
+            \dimen@ii\ht\tw@
+          \fi
+        \fi
+        % Re-box contents to desired size \dimen@ii
+        \advance\dimen@ii -\fb@frh
+        \setbox\tw@\vbox to\dimen@ii \bgroup
+        % remove simulated frame and page flexibility:
+        \vskip -\fb@frh \@plus-\pagestretch \@minus-.8\pageshrink
+        \unvbox\tw@ \unpenalty\unpenalty
+        \ifdim\lastkern=-137sp % whole box went to next page
+|          \message{box split at beginning! }%
+           \egroup \fb@resto@set \eject % (\vskip for frame size was discarded) 
+           \fb@adjheight
+        \else %
+           \egroup \fb@resto@set
+           \ifvoid\@tempboxa % it all fit after all
+|             \message{box split at end! }%
+              \setbox\@tempboxa\box\tw@
+           \else % it really did split
+|             \message{box split as expected. Its reboxed height is \the\ht\tw@. }%
+              \ifdim\wd\tw@>\z@
+%psh: Changed the command that inserts the box:
+%     Instead of \centerline, we shift right by \saved@totalleftmargin:
+%              \centerline{\FrameCommand{\box\tw@}}%  ??? \centerline bad idea
+       \hbox{\hskip \saved@totalleftmargin\FrameCommand{\box\tw@}}%
+              \else
+|               \message{Zero width means likely blank. Don't frame it (guess)}%
+                \box\tw@
+              \fi
+              \hrule \@height\z@
+              \eject
+              \fb@adjheight
+              \put@frame
+  \fi\fi\fi\fi\fi
+  \ifvoid\@tempboxa\else
+%psh: Changed the command that inserts the box:
+%     Instead of \centerline, we shift right by \saved@totalleftmargin:
+%    \centerline{\FrameCommand{\box\@tempboxa}}%
+    \hbox{\hskip\saved@totalleftmargin\FrameCommand{\box\@tempboxa}}%
+    \nointerlineskip \null %{\showoutput \showlists}
+    \penalty-30 \vskip\topsep
+  \fi}
+
+\def\fb@adjheight{%
+  \vbox to\FrameHeightAdjust{}% get proper baseline skip from above.
+  \penalty\@M \nointerlineskip
+  \vskip-\FrameHeightAdjust
+  \penalty\@M} % useful for tops of pages
+
+\edef\zero@glue{\the\z@skip}
+
+\catcode`\|=\FrameRestore
+
+% Provide configuration commands:
+\providecommand\FrameCommand{\fboxrule=\FrameRule \fboxsep=\FrameSep \fbox}
+\@ifundefined{FrameRule}{\newdimen\FrameRule \FrameRule=\fboxrule}{}
+\@ifundefined{FrameSep} {\newdimen\FrameSep  \FrameSep =3\fboxsep}{}
+
+% Height of frame above first baseline when frame starts a page:
+\providecommand\FrameHeightAdjust{6pt}
+
+% \FrameRestore has parts of \@parboxrestore.  See how it is used in the 
+% "settings" argument of \MakeFrame.  Previous behavior can be restored by 
+% using \@parboxrestore there, or redefining:
+% \makeatletter \renewcommand\FrameRestore{\@parboxrestore} \makeatother
+\def\FrameRestore{%
+  \let\if@nobreak\iffalse
+  \let\if@noskipsec\iffalse
+%  \let\par\@@par  ??
+  \let\-\@dischyph
+  \let\'\@acci\let\`\@accii\let\=\@acciii
+%  \parindent\z@ \parskip\z@skip    Definitely omit!
+%  \everypar{}%  ??
+  \linewidth\hsize
+%  \@totalleftmargin\z@
+%  \leftskip\z@skip \rightskip\z@skip \@rightskip\z@skip
+%  \parfillskip\@flushglue \lineskip\normallineskip
+%  \baselineskip\normalbaselineskip
+  \sloppy
+%  \let\\\@normalcr
+}
+
+%  Compatibility with previous versions (temporary!):
+\let\fram@d=\MakeFramed  \let\endfram@d=\endMakeFramed
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% This ends the stuff that's lifted from:
+% % framed.sty   v 0.8a   21-Jul-2003
+% % Copyright (C) 1992-2003 by Donald Arseneau
+
+
+%--------------------------------------------------------------------
+%--------------------------------------------------------------------
+
+\endinput
+%---------------------------------------------------------------------
+%---------------------------------------------------------------------
+%---------------------------------------------------------------------
+%---------------------------------------------------------------------
+%---------------------------------------------------------------------