% \iffalse meta-comment
% ==================================================
% exam-ltr.dtx – LaTeX Exam Package (LTR)
% Version: 1.0
% Date: 2026/08/20
% 
% Copyright (C) 2026 by Nadeer Aljaroudi
%
% This file may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
% version 1.3c of this license or (at your option) any later
% version.
% ==================================================
% \fi
%
% \iffalse
%<*driver>
\documentclass{ltxdoc}
\usepackage{exam-ltr}
\usepackage{array}
\usepackage{enumitem}
\usepackage{underscore}
\usepackage[hyperindex=false]{hyperref}
\hypersetup{colorlinks=true,linkcolor=blue}
\EnableCrossrefs
\RecordChanges
\begin{document}
  \DocInput{exam-ltr.dtx}
\end{document}
%</driver>
% \fi
%
% \changes{v1.0}{2026/08/20}{Initial public release}
%
% \GetFileInfo{exam-ltr.dtx}
%
% \title{^^A
%   \textsf{exam-ltr} --- A Comprehensive LaTeX Exam Package\thanks{^^A
%     This file has version v1.0, dated 2026-08-20.}^^A
% }
%
% \author{Nadeer Aljaroudi}
% \date{2026-08-20}
%
% \maketitle
%
% \begin{abstract}
%   The \textsf{exam-ltr} package provides a comprehensive framework for
%   designing professional exams and academic assessments in \LaTeX.
%   Developed specifically for educators and exam setters, it supports
%   a wide variety of question types, including Multiple Choice,
%   True/False, Fill in the Blank, Ordering, Matching, Essay, Short Answer,
%   and Reading Passages.
%
%   Key features include automatic answer key generation, controlled
%   randomization, metadata display, and flexible layout for both
%   simple quizzes and complex examinations.
% \end{abstract}
%
% \tableofcontents
%
% \section{Introduction}
%
% The \textsf{exam-ltr} package provides a clean and robust environment for
% building professional exams without manual formatting. Built with educators
% in mind, it allows you to focus on creating high-quality question content
% while the package handles layout, alignment, and answer key generation
% automatically.
%
% \medskip
% \textbf{Key features:}
% \begin{itemize}
%   \item \textbf{8 Dedicated Question Types}: MC, TF, FillBlank, Ordering,
%         Matching, Essay, ShortAnswer, and Reading Passage (ReadingPassage).
%   \item \textbf{Automated Answer Keys}: Answers are collected and displayed
%         directly after each question in teacher mode.
%   \item \textbf{Smart Randomization}: Shuffles options, matching columns,
%         and ordering items in a reproducible manner.
%   \item \textbf{Metadata Display}: Show or hide marks, difficulty levels,
%         and question type tags.
%   \item \textbf{Dual-Mode Output}: Switch between student version (answers
%         hidden) and teacher version (answers shown).
% \end{itemize}
%
% \section{Installation}
%
% The \texttt{exam-ltr} package is distributed through CTAN and is included
% in all major LaTeX distributions (TeX Live, MiKTeX, MacTeX). In most cases,
% no manual installation is needed; the system's package manager will handle
% it automatically.
%
% If manual installation is required, use one of the following methods.
%
% \subsection*{Quick Installation (Single Project)}
%
% This method is suitable for users who need the package for a single document.
%
% \begin{enumerate}
%   \item Copy \texttt{exam-ltr.sty} into the same folder as the main
%         \texttt{.tex} file.
%   \item Add \texttt{\textbackslash usepackage\{exam-ltr\}} to the document
%         preamble.
% \end{enumerate}
%
% \subsection*{Permanent Installation (System-Wide)}
%
% This method installs the package into the user's local TeX tree, making it
% available for all future documents.
%
% \subsubsection*{Linux / macOS}
%
% \begin{enumerate}
%   \item Create the target directory:\\
%         \texttt{mkdir -p \~{}/texmf/tex/latex/exam-ltr}
%
%   \item Copy the package file into this directory:\\
%         \texttt{cp exam-ltr.sty \~{}/texmf/tex/latex/exam-ltr/}
%
%   \item Update the LaTeX file database:\\
%         \texttt{texhash \~{}/texmf}
% \end{enumerate}
%
% \subsubsection*{Windows}
%
% \begin{itemize}
%   \item \textbf{MiKTeX:}
% \begin{enumerate}
%   \item Create the folder:
%         \texttt{C:\textbackslash texmf\textbackslash tex\textbackslash latex\textbackslash exam-ltr}
%   \item Copy \texttt{exam-ltr.sty} into it.
%   \item Refresh the database via the MiKTeX Console (``Refresh FNDB'').
% \end{enumerate}
%
%   \item \textbf{TeX Live:}:
% \begin{enumerate}
%   \item Create the folder:
%         \texttt{C:\textbackslash texlive\textbackslash texmf-local\textbackslash tex\textbackslash latex\textbackslash exam-ltr}
%   \item Copy \texttt{exam-ltr.sty} into it.
%   \item Refresh the database by running \texttt{texhash}.
% \end{enumerate}
% \end{itemize}
%
% \subsection*{Requirements}
%
% The package requires the following LaTeX packages, which are loaded
% automatically: \texttt{xcolor}, \texttt{tcolorbox}, \texttt{expl3},
% and \texttt{xparse}.
%
% \subsection*{Engine Compatibility}
%
% The package is compatible with all major LaTeX engines:
% pdfLaTeX, LuaLaTeX, and XeLaTeX.
%
% \section{Quick Start}
%
% This section outlines the standard workflow for creating an exam with
% the \texttt{exam-ltr} package.
%
% \subsection*{Step 1: Load the Package and Configure Mode}
%
% Include the package in your document preamble and set the desired output
% mode:
%
% \begin{flushleft}\ttfamily
% \cs{documentclass}\{article\}\\
% \cs{usepackage}\{exam-ltr\}\\[1em]
% \cs{TeacherMode} \quad \% Show answer keys\\
% \cs{ShowMarks} \quad \% Display marks\\
% \cs{ShowCorrection} \quad \% Show answer boxes\\
% \cs{ExamID}\{123\} \quad \% Fix randomization seed
% \end{flushleft}
%
% \subsection*{Step 2: Structure Your Questions}
%
% Wrap every question in the \texttt{Question} environment. You must
% specify four arguments: \meta{Type}, \meta{Difficulty}, \meta{Marks},
% and \meta{Question text}:
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\marg{Type}\marg{Difficulty}\marg{Marks}\marg{Question text}\\
% \hspace*{2em}\textit{question content}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection*{Step 3: Choose the Environment for Your Question}
%
% Inside the \texttt{Question} environment, select the environment that
% matches your question type: \texttt{MC} (Multiple Choice), \texttt{TF}
% (True/False), \texttt{FillBlank}, \texttt{Ordering}, \texttt{Matching},
% \texttt{Essay}, \texttt{ShortAnswer}, or \texttt{ReadingPassage}.
%
% \subsection*{Step 4: Compile and View Output}
%
% Compile your document with \texttt{pdflatex} (or \texttt{xelatex}/
% \texttt{lualatex}). The output depends on the mode set in Step 1:
%
% \begin{itemize}
%   \item \textbf{Student Mode (default):} Answer keys are hidden.
%   \item \textbf{Teacher Mode:} Answer keys appear when \cs{ShowCorrection}
%         is also enabled.
% \end{itemize}
%
% \subsection*{Minimal Working Example}
%
% \begin{flushleft}\ttfamily
% \cs{documentclass}\{article\}\\
% \cs{usepackage}\{exam-ltr\}\\[1em]
% \cs{TeacherMode}\\
% \cs{ShowCorrection}\\[1em]
% \cs{begin}\{document\}\\[1em]
% \cs{begin}\{Question\}\{MC\}\{Easy\}\{2\}\{Multiple Choice Quiz\}\\
% \hspace*{2em}\cs{begin}\{MC\}\\
% \hspace*{4em}\cs{MCQuestion}\{What is 2+2?\}\{2\}\\
% \hspace*{6em}\cs{MCOption}\{3\}\\
% \hspace*{6em}\cs{MCOption}\{4\}\\
% \hspace*{6em}\cs{MCOption}\{5\}\\
% \hspace*{2em}\cs{end}\{MC\}\\
% \cs{end}\{Question\}\\[1em]
% \cs{end}\{document\}
% \end{flushleft}
%
% \section{Mode Commands}
%
% The package provides several switches that control the appearance of
% the final exam sheet. These switches allow you to toggle between student
% and teacher views, display metadata, and show answer boxes.
%
% \subsection*{Student and Teacher Modes}
%
% \DescribeMacro{\StudentMode}
% \DescribeMacro{\TeacherMode}
% These commands toggle between student and teacher views.
%
% \begin{flushleft}\ttfamily
% \cs{StudentMode} \quad \% Hide answer keys (default)\\
% \cs{TeacherMode} \quad \% Show answer keys
% \end{flushleft}
%
% The default mode is \cs{StudentMode}. When \cs{TeacherMode} is active,
% answer keys become visible.
%
% \subsection*{Metadata Visibility}
%
% \DescribeMacro{\ShowMarks}
% \DescribeMacro{\ShowDifficulty}
% \DescribeMacro{\ShowType}
% These commands control the visibility of question metadata.
%
% \begin{flushleft}\ttfamily
% \cs{ShowMarks} \quad \% Display marks\\
% \cs{ShowDifficulty} \quad \% Display difficulty levels\\
% \cs{ShowType} \quad \% Display question type
% \end{flushleft}
%
% Each switch is independent; any combination may be enabled.
%
% \subsection*{Correction Boxes}
%
% \DescribeMacro{\ShowCorrection}
% Enables the display of correction boxes for teacher use.
%
% \begin{flushleft}\ttfamily
% \cs{ShowCorrection}
% \end{flushleft}
%
% Only takes effect when \cs{TeacherMode} is explicitly enabled.
%
% \subsection*{Randomization Seed}
%
% \DescribeMacro{\ExamID}
% Sets a fixed seed for all randomization operations (shuffling MC options,
% ordering items, and matching pairs).
%
% \begin{flushleft}\ttfamily
% \cs{ExamID}\marg{number}
% \end{flushleft}
%
% Using the same seed guarantees identical output across compilations.
%
% \section{Question Environment}
%
% \DescribeEnv{Question}
% The Question environment is the primary container for all question
% types. It handles automatic numbering, manages metadata display
% (type, difficulty, marks), and integrates answer key collection
% in teacher mode.
%
% \subsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\marg{Type}\marg{Difficulty}\marg{Marks}\marg{Question Text}\\
% \hspace*{2em}\textit{question content}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection*{Arguments}
%
% \begin{itemize}
%   \item \meta{Type}: Question category (MC, TF, FillBlank, Ordering,
%         Matching, Essay, ShortAnswer, ReadingPassage).
%   \item \meta{Difficulty}: Descriptive label (e.g., Easy, Medium, Hard).
%   \item \meta{Marks}: Numeric score assigned to the question.
%   \item \meta{Question Text}: Main prompt or instruction.
% \end{itemize}
%
% \subsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Automatic Numbering:} Questions are numbered sequentially.
%
%   \item \textbf{Metadata Display:} When enabled via \cs{ShowType},
%         \cs{ShowDifficulty}, and \cs{ShowMarks}, the corresponding
%         labels are displayed alongside the question.
%
%   \item \textbf{Answer Key Collection:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, all answers are collected
%         and displayed in a dedicated answer key box.
%
%   \item \textbf{Consistent Formatting:} All question types placed
%         inside this environment share consistent spacing and layout.
% \end{itemize}
%
% \subsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{Matching\}\{Easy\}\{3\}\{Match the opposite words.\}\\
% \hspace*{2em}\cs{begin}\{Matching\}\\
% \hspace*{4em}\cs{MatchPair}\{Tall\}\{Short\}\\
% \hspace*{4em}\cs{MatchPair}\{Big\}\{Small\}\\
% \hspace*{4em}\cs{MatchPair}\{High\}\{Low\}\\
% \hspace*{2em}\cs{end}\{Matching\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \section{Question Types}
%
% \subsection{Multiple Choice (MC)}
% \DescribeEnv{MC}
% \DescribeMacro{\MCQuestion}
% \DescribeMacro{\MCOption}
% The MC environment creates multiple-choice questions with automatically
% shuffled options. Multiple questions can be placed inside a single
% MC environment, each with its own set of options. The correct answer
% is stored internally and appears in the answer key in teacher mode.
% Options are displayed in a grid layout with a customizable number
% of columns.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{MC\}\oarg{columns}\\
% \hspace*{2em}\cs{MCQuestion}\marg{question text}\marg{correct\_index}\\
% \hspace*{4em}\cs{MCOption}\marg{option 1}\\
% \hspace*{4em}\cs{MCOption}\marg{option 2}\\
% \hspace*{4em}\cs{MCOption}\marg{option 3}\\
% \hspace*{4em}...\\
% \cs{end}\{MC\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Column Layout (Default: 4):} The optional \oarg{columns}
%         argument sets the number of columns for displaying options.
%         Any number can be used as long as it fits the page width.
%
%   \item \textbf{Correct Answer Index:} The \marg{correct\_index}
%         is a single number indicating which option is correct
%         (e.g., 2 means the second option is correct). This index
%         is used internally to track the correct answer after
%         shuffling.
%
%   \item \textbf{Randomization:} All options inside \cs{MCQuestion}
%         are shuffled based on the global exam seed set by
%         \cs{ExamID}. This ensures reproducibility when a fixed
%         seed is provided.
%
%   \item \textbf{Answer Key Integration:} The correct answer is
%         collected automatically and displayed in the answer key
%         when \cs{TeacherMode} and \cs{ShowCorrection} are enabled.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{MC\}\{Easy\}\{1\}\{Basic Arithmetic\}\\
% \hspace*{2em}\cs{begin}\{MC\}[3]\\
% \hspace*{4em}\cs{MCQuestion}\{What is 2+2?\}\{2\}\\
% \hspace*{6em}\cs{MCOption}\{3\}\\
% \hspace*{6em}\cs{MCOption}\{4\}\\
% \hspace*{6em}\cs{MCOption}\{5\}\\
% \hspace*{2em}\cs{end}\{MC\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{True/False (TF)}
% \DescribeEnv{TF}
% \DescribeMacro{\TFQuestion}
% The TF environment creates True/False questions. Multiple statements
% can be placed inside a single TF environment, each with its own
% correct answer. Two display styles are available: bracket style
% (default) and options style, allowing flexibility for different
% assessment needs.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{TF\}\oarg{style}\\
% \hspace*{2em}\cs{TFQuestion}\marg{statement}\marg{answer}\\
% \hspace*{2em}\cs{TFQuestion}\marg{statement}\marg{answer}\\
% \hspace*{2em}...\\
% \cs{end}\{TF\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Visual Style:} The optional \oarg{style} argument
%         selects the display format:
%     \begin{itemize}
%       \item \texttt{bracket} (default): Places an empty answer slot
%             \texttt{( )} after each statement.
%       \item \texttt{options}: Places ``True'' and ``False'' labels
%             to the right of each statement.
%     \end{itemize}
%
%   \item \textbf{Statement Input:} The \marg{statement} argument
%         receives the text that students must evaluate.
%
%   \item \textbf{Answer Specification:} The \marg{answer} argument
%         accepts any text, which will be displayed in the answer key
%         as provided (e.g., ``True'', ``False'', ``T'', ``F'').
%
%   \item \textbf{Answer Key:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, the correct answers are
%         collected and displayed in the answer key.
%
%   \item \textbf{Multiple Questions:} Multiple \cs{TFQuestion}
%         commands can be placed sequentially within one TF environment.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{TF\}\{Easy\}\{2\}\{True or False\}\\
% \hspace*{2em}\cs{begin}\{TF\}[bracket]\\
% \hspace*{4em}\cs{TFQuestion}\{The Earth is flat.\}\{False\}\\
% \hspace*{4em}\cs{TFQuestion}\{Water boils at 100°C.\}\{True\}\\
% \hspace*{2em}\cs{end}\{TF\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{Fill in the Blank (FillBlank)}
% \DescribeEnv{FillBlank}
% \DescribeMacro{\WordBank}
% \DescribeMacro{\FillQuestion}
% \DescribeMacro{\Blank}
% The FillBlank environment creates fill-in-the-blank questions where
% students complete sentences with appropriate words. It supports
% single or multiple blanks per question, multiple correct answers
% per blank (separated by \texttt{\textbar}), and an optional word
% bank to assist students during assessment.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{FillBlank\}\oarg{wordbank}\\
% \hspace*{2em}\cs{WordBank}\oarg{separator}\marg{word1, word2, ...}\\
% \hspace*{2em}\cs{FillQuestion}\marg{text with \cs{Blank}}\marg{answer}\\
% \cs{end}\{FillBlank\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Blank Creation:} The \cs{Blank} command creates an
%         underline field where students write their answers.
%         Its optional argument \oarg{width} sets the line length
%         (default: 4.25em).
%
%   \item \textbf{Word Bank Activation:} The optional \oarg{wordbank}
%         argument controls whether a word bank is displayed.
%         Set to \texttt{true} to show a framed list of words
%         above the questions (default is \texttt{false}).
%
%   \item \textbf{Word Bank Configuration:} The \cs{WordBank} command
%         defines the vocabulary list. Words must be separated by commas.
%         The optional \oarg{separator} controls spacing between words
%         (default: \cs{quad}).
%
%   \item \textbf{Multiple Answers:} When a question has multiple blanks,
%         separate the answers with \texttt{\textbar} in the order
%         they appear. Example: \texttt{Red\textbar Green\textbar Blue}.
%
%   \item \textbf{Answer Key:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, correct answers are
%         collected and displayed in a dedicated answer key box.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{FillBlank\}\{Medium\}\{4\}\{Complete the sentences\}\\
% \hspace*{2em}\cs{begin}\{FillBlank\}[true]\\
% \hspace*{4em}\cs{WordBank}\{gravity, light, oxygen\}\\
% \hspace*{4em}\cs{FillQuestion}\{Humans need \cs{Blank}\ to breathe.\}\{oxygen\}\\
% \hspace*{4em}\cs{FillQuestion}\{Plants need \cs{Blank}\ from the sun.\}\{light\}\\
% \hspace*{2em}\cs{end}\{FillBlank\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{Ordering}
% \DescribeEnv{Ordering}
% \DescribeMacro{\OrderQuestion}
% \DescribeMacro{\OrderOption}
% \DescribeMacro{\OrderAnswer}
% The Ordering environment creates sequencing questions where students
% must arrange items in their correct logical order. Items must be
% written in their proper sequence inside the environment, but are
% presented to students in a shuffled layout. The original order
% is preserved for the teacher's answer key. Options are displayed
% in a grid layout with a customizable number of columns.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Ordering\}\oarg{columns}\\
% \hspace*{2em}\cs{OrderQuestion}\marg{instruction}\\
% \hspace*{4em}\cs{OrderOption}\marg{item 1}\\
% \hspace*{4em}\cs{OrderOption}\marg{item 2}\\
% \hspace*{4em}\cs{OrderOption}\marg{item 3}\\
% \hspace*{4em}...\\
% \hspace*{2em}\cs{OrderAnswer}\oarg{width}\\
% \cs{end}\{Ordering\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Correct Sequence:} Items must be written inside
%         \cs{OrderOption} in their correct logical order. This order
%         is preserved for the answer key.
%
%   \item \textbf{Randomization:} Items are shuffled for the student
%         based on the global exam seed (\cs{ExamID}), ensuring
%         consistent randomization across compilations.
%
%   \item \textbf{Column Layout (Default: 4):} The optional \oarg{columns} argument
%         sets the number of columns for displaying shuffled items.
%         Any number can be used as long as it fits the page width.
%
%   \item \textbf{Answer Space:} The \cs{OrderAnswer} command adds
%         an optional answer space (with customizable width) where
%         students write their final ordered sequence.
%
%   \item \textbf{Answer Key:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, the correct sequence is
%         collected and displayed in the answer key.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{Ordering\}\{Medium\}\{3\}\{Arrange in correct order\}\\
% \hspace*{2em}\cs{begin}\{Ordering\}[3]\\
% \hspace*{4em}\cs{OrderQuestion}\{Steps of the water cycle\}\\
% \hspace*{6em}\cs{OrderOption}\{Evaporation\}\\
% \hspace*{6em}\cs{OrderOption}\{Condensation\}\\
% \hspace*{6em}\cs{OrderOption}\{Precipitation\}\\
% \hspace*{4em}\cs{OrderAnswer}\\
% \hspace*{2em}\cs{end}\{Ordering\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{Matching}
% \DescribeEnv{Matching}
% \DescribeMacro{\MatchPair}
% The Matching environment creates two-column association questions.
% Items must be written in their correct pairs inside the environment.
% The left column remains fixed and numbered, while the right column
% is automatically shuffled for students. The original pairings
% are preserved for the teacher's answer key.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Matching\}\oarg{left\_ratio}\\
% \hspace*{2em}\cs{MatchPair}\marg{left item}\marg{right item}\\
% \hspace*{2em}\cs{MatchPair}\marg{left item}\marg{right item}\\
% \hspace*{2em}...\\
% \cs{end}\{Matching\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Pair Definition:} Each pair is defined using \cs{MatchPair}.
%         The order of definition determines the correct answer key.
%         The left column is fixed and numbered, while the right column
%         is automatically shuffled.
%
%   \item \textbf{Column Width Control:} The optional \oarg{left\_ratio}
%         adjusts the width of the left column as a decimal fraction
%         between 0 and 1. Default is 0.5 (equal split). This is useful
%         when the left column contains short terms and the right column
%         has lengthy descriptions (e.g., 0.3 for 30\% width).
%
%   \item \textbf{Randomization:} The right column is shuffled based on
%         the global exam seed (\cs{ExamID}), ensuring consistency
%         across compilations.
%
%   \item \textbf{Answer Key:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, the correct mappings are
%         displayed as numbered-to-lettered pairs (e.g., (1) $\Rightarrow$ (b)).
%
%   \item \textbf{Capacity:} Supports a maximum of 26 pairs per question
%         (limited by the alphabet A--Z).
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{Matching\}\{Medium\}\{4\}\{Match countries with capitals\}\\
% \hspace*{2em}\cs{begin}\{Matching\}[0.3]\\
% \hspace*{4em}\cs{MatchPair}\{France\}\{Paris\}\\
% \hspace*{4em}\cs{MatchPair}\{Germany\}\{Berlin\}\\
% \hspace*{4em}\cs{MatchPair}\{Italy\}\{Rome\}\\
% \hspace*{2em}\cs{end}\{Matching\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{Essay}
% \DescribeEnv{Essay}
% \DescribeMacro{\EssayQuestion}
% The Essay environment creates open-ended, long-form written response
% questions. It provides a writing area with either ruled lines or
% blank space, depending on the selected style. The instructor's
% answer summary is stored and displayed in the answer key in teacher
% mode.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Essay\}\oarg{lines}\\
% \hspace*{2em}\cs{EssayQuestion}\oarg{line\_count}\marg{question}\marg{answer summary}\\
% \hspace*{2em}...\\
% \cs{end}\{Essay\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Writing Space Style:} The optional environment argument
%         \oarg{lines} controls the appearance of the writing area:
%     \begin{itemize}
%       \item \texttt{true}: Generates ruled notebook lines (default).
%       \item \texttt{false}: Provides blank white space for free-form
%             text or diagrams.
%     \end{itemize}
%
%   \item \textbf{Writing Space Size (Default: 4):} The optional \oarg{line\_count}
%         argument specifies the number of lines allocated for the
%         student's answer.
%
%   \item \textbf{Question Components:} \cs{EssayQuestion} command
%         takes two mandatory arguments: the question prompt and a
%         concise answer summary for the instructor's reference.
%
%   \item \textbf{Multiple Questions:} Multiple \cs{EssayQuestion}
%         commands can be placed sequentially within one Essay environment.
%
%   \item \textbf{Answer Key:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, all answer summaries are
%         collected and displayed in a dedicated answer key box.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{Essay\}\{Hard\}\{10\}\{Written Response\}\\
% \hspace*{2em}\cs{begin}\{Essay\}[true]\\
% \hspace*{4em}\cs{EssayQuestion}\{What is cloud computing?\}\{Cloud computing\}\\
% \hspace*{4em}\cs{EssayQuestion}[10]\{What is cybersecurity?\}\{Cybersecurity\}\\
% \hspace*{2em}\cs{end}\{Essay\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{Short Answer (ShortAnswer)}
% \DescribeEnv{ShortAnswer}
% \DescribeMacro{\ShortQuestion}
% The ShortAnswer environment creates questions that require brief,
% direct responses — such as single words, short phrases, or concise
% statements. The answer space can be customized (0, 1, or 2 lines)
% to keep the exam layout clear and space-efficient. The instructor's
% answer is stored and displayed in the answer key in teacher mode.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{ShortAnswer\}\oarg{lines}\\
% \hspace*{2em}\cs{ShortQuestion}\oarg{size}\marg{question}\marg{answer}\\
% \hspace*{2em}...\\
% \cs{end}\{ShortAnswer\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Writing Space Style:} The optional environment argument
%         \oarg{lines} controls the appearance of the answer space:
%     \begin{itemize}
%       \item \texttt{true}: Generates ruled notebook lines (default).
%       \item \texttt{false}: Provides blank white space without lines.
%     \end{itemize}
%
%   \item \textbf{Answer Space Size:} The optional \oarg{size} argument
%         specifies the number of lines for the student's answer:
%     \begin{itemize}
%       \item \texttt{0}: Prints a short underline directly after the
%             question text — ideal for single-word answers.
%             (Always prints a line regardless of the environment style.)
%       \item \texttt{1}: Generates a one-line writing space below the
%             question.
%       \item \texttt{2}: Generates a two-line writing space below the
%             question.
%     \end{itemize}
%
%   \item \textbf{Question Components:} \cs{ShortQuestion} command
%         takes two mandatory arguments: the question prompt and the
%         model answer or keyword solution.
%
%   \item \textbf{Multiple Questions:} Multiple \cs{ShortQuestion}
%         commands can be placed sequentially within one ShortAnswer
%         environment.
%
%   \item \textbf{Answer Key:} When \cs{TeacherMode} and
%         \cs{ShowCorrection} are enabled, all answers are collected
%         and displayed in a dedicated answer key box.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{ShortAnswer\}\{Easy\}\{3\}\{Answer briefly\}\\
% \hspace*{2em}\cs{begin}\{ShortAnswer\}[true]\\
% \hspace*{4em}\cs{ShortQuestion}[0]\{Diameter of Earth?\}\{12,742 km\}\\
% \hspace*{4em}\cs{ShortQuestion}[1]\{Strongest gravity planet?\}\{Jupiter\}\\
% \hspace*{2em}\cs{end}\{ShortAnswer\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \subsection{Reading Passage}
% \DescribeEnv{ReadingPassage}
% The ReadingPassage environment provides a container for reading
% comprehension texts. The passage is printed exactly as written —
% preserving all formatting, paragraph breaks, and inline styling —
% without any modification or randomization. The passage is displayed
% in a standalone box, and authors can place any question type after
% it to assess comprehension.
%
% \subsubsection*{Syntax}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{ReadingPassage\}\marg{title}\\
% \hspace*{2em}\textit{passage text}\\
% \cs{end}\{ReadingPassage\}
% \end{flushleft}
%
% \subsubsection*{How It Works}
%
% \begin{itemize}
%   \item \textbf{Passage Rendering:} The text is displayed in a framed
%         box, exactly as entered, preserving all formatting.
%
%   \item \textbf{Title:} The mandatory \marg{title} argument sets the
%         centered heading above the passage. If left empty \{\},
%         the default title ``Reading Passage'' is used.
%
%   \item \textbf{Content Flexibility:} The passage can include multiple
%         paragraphs, inline text styles (bold, italic, etc.), and
%         custom lists.
%
%   \item \textbf{Question Integration:} Any question type can follow
%         a ReadingPassage within the same \texttt{Question} block
%         to assess comprehension.
% \end{itemize}
%
% \subsubsection*{Example}
%
% \begin{flushleft}\ttfamily
% \cs{begin}\{Question\}\{ReadingPassage\}\{Medium\}\{10\}\{Read and answer\}\\
% \hspace*{2em}\cs{begin}\{ReadingPassage\}\{The Solar System\}\\
% \hspace*{4em}\textit{Our solar system has eight planets that orbit the Sun: }\\
% \hspace*{4em}\textit{Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and}\\
% \hspace*{4em}\textit{Neptune.}\\
% \hspace*{2em}\cs{end}\{ReadingPassage\}\\[2pt]
% \hspace*{2em}\cs{begin}\{FillBlank\}\\
% \hspace*{4em}\cs{FillQuestion}\{\cs{Blank}\ is the smallest planet.\}\{Mercury\}\\
% \hspace*{4em}\cs{FillQuestion}\{\cs{Blank}\ is the largest planet.\}\{Jupiter\}\\
% \hspace*{2em}\cs{end}\{FillBlank\}\\
% \cs{end}\{Question\}
% \end{flushleft}
%
% \section{Complete Example}
%
% A fully functional sample exam file, \texttt{example.tex}, is
% included with the package to demonstrate its capabilities in a realistic
% academic context. The example file covers all question types supported
% by the package: \texttt{MC}, \texttt{TF}, \texttt{Ordering},
% \texttt{FillBlank}, \texttt{Matching}, \texttt{ShortAnswer},
% \texttt{Essay}, and \texttt{ReadingPassage}.
%
% \medskip
% \textbf{Usage Instructions:}
%
% \begin{enumerate}
%   \item Ensure you have the file \texttt{example.tex} in your
%         working directory (usually found in the package documentation
%         folder).
%
%   \item Open it in your \LaTeX{} editor and compile with \texttt{pdflatex},
%         \texttt{xelatex}, or \texttt{lualatex}.
%
%   \item To switch between student and teacher views, uncomment or comment
%         the \cs{TeacherMode} and \cs{ShowCorrection} commands in the
%         preamble. This toggles the display of answer keys and correction
%         boxes.
% \end{enumerate}
%
% \section{Common Mistakes}
%
% The following list addresses frequent errors encountered during exam
% creation. Adhering to these guidelines ensures correct compilation
% and output.
%
% \begin{itemize}
%   \item \textbf{Enabling \cs{ShowCorrection} without \cs{TeacherMode}:}
%         \cs{ShowCorrection} alone does not display answers. Both
%         \cs{TeacherMode} and \cs{ShowCorrection} must be active for
%         solutions to appear.
%
%   \item \textbf{Omitting the \texttt{Question} Environment:}
%         All question types must be wrapped inside the \texttt{Question}
%         environment. Failing to do so prevents metadata and answer keys
%         from appearing.
%
%   \item \textbf{Using Invalid Type Identifiers:}
%         The first argument of \texttt{Question} must be a valid
%         identifier: \texttt{MC}, \texttt{TF}, \texttt{FillBlank},
%         \texttt{Ordering}, \texttt{Matching}, \texttt{Essay},
%         \texttt{ShortAnswer}, or \texttt{ReadingPassage}. Using
%         non-standard identifiers (e.g., \texttt{MCQ}) will result in
%         missing or incorrect metadata labels.
%
%   \item \textbf{Missing Pipe Separator in \texttt{FillBlank}:}
%         For questions with multiple answers, separate them with a
%         vertical pipe \texttt{\textbar} (e.g., \texttt{Red\textbar Green\textbar Blue}).
%         Omitting this causes the package to treat multiple answers as
%         a single string.
%
%   \item \textbf{Incorrect Column Placement in \texttt{Matching}:}
%         The \texttt{Matching} environment always shuffles the right
%         column. Items intended for randomization must be placed in
%         the second argument. Placing them in the first argument results
%         in an illogical question.
%
%   \item \textbf{Incorrect Input Sequence in \texttt{Ordering}:}
%         The order in which you write the \cs{OrderOption} commands
%         in your document defines the correct answer. Entering them
%         in the wrong order will result in incorrect grading.
%
%   \item \textbf{Omitting the Title in \texttt{ReadingPassage}:}
%         The \texttt{ReadingPassage} environment requires a title
%         argument. If no custom title is needed, use empty braces
%         \texttt{\{\}}. Omitting the argument causes LaTeX to misinterpret
%         the first character of the passage text as the title.
% \end{itemize}
%
% \section{Known Limitations}
%
% The \texttt{exam-ltr} package has the following limitations in its
% current version.
%
% \begin{itemize}
%   \item \textbf{Directionality:}
%         The package is optimized for Left-to-Right (LTR) languages
%         (e.g., English). For Right-to-Left (RTL) languages (e.g., Arabic),
%         use the companion package \texttt{exam-rtl}.
%
%   \item \textbf{Mandatory Randomization:}
%         Option shuffling cannot be fully disabled. Even without the
%         \cs{ExamID} macro, a default randomization is applied.
%
%   \item \textbf{Scope of Randomization:}
%         Randomization is limited to internal elements: choices in
%         \texttt{MC}, items in \texttt{Ordering}, and the right-hand
%         column in \texttt{Matching}. Shuffling the entire sequence
%         of question blocks is not supported in this version.
%
%   \item \textbf{Item Capacity:}
%         Each question within \texttt{Ordering} and \texttt{Matching}
%         is limited to a maximum of 26 items (tracked using Latin
%         letters A--Z).
%
%   \item \textbf{Answer Key Placement:}
%         Answer keys are displayed individually beneath each question.
%         A centralized answer sheet at the end of the document is not
%         supported in this version.
% \end{itemize}
%
% \section{License}
%
% This package is distributed under the LaTeX Project Public License (LPPL),
% version 1.3c or later.
%
% The latest version of this license is available at:
% \url{http://www.latex-project.org/lppl.txt}
%
% \StopEventually{^^A
%   \PrintChanges
%   \PrintIndex
% }
%
% \section{Implementation}
%
% This section contains the complete source code of the \texttt{exam-ltr}
% package. Each macro, variable, and environment is documented with its
% purpose and usage.
%
% \iffalse
%<*package>
% \fi
%
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{exam-ltr}[2026/08/20 v1.0 LTR Exam Core]

\RequirePackage{xcolor}
\RequirePackage{tcolorbox}
\tcbuselibrary{skins, breakable}
\RequirePackage{expl3}
\RequirePackage{xparse}
%    \end{macrocode}

%    \begin{macrocode}
\ExplSyntaxOn
\cs_generate_variant:Nn \tl_if_eq:nnT { VVT }
\cs_generate_variant:Nn \msg_warning:nnn { nnx }
%    \end{macrocode}

% \begin{macro}{\PrintNumber}
%   Converts a number to its standard representation.
%    \begin{macrocode}
\newcommand{\PrintNumber}[1]{\number#1}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\g__mode_teacher_bool}
% \begin{macro}{\g__mode_marks_bool}
% \begin{macro}{\g__mode_difficulty_bool}
% \begin{macro}{\g__mode_type_bool}
% \begin{macro}{\g__mode_correction_bool}
%   Core boolean variables for controlling mode and metadata visibility.
%    \begin{macrocode}
\bool_new:N \g__mode_teacher_bool
\bool_new:N \g__mode_marks_bool
\bool_new:N \g__mode_difficulty_bool
\bool_new:N \g__mode_type_bool
\bool_new:N \g__mode_correction_bool
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}

% \begin{macro}{\g__exam_id_int}
% \begin{macro}{\g__question_number_int}
% \begin{macro}{\g__question_seed_int}
%   Core integer variables for exam ID, question numbering, and seed.
%    \begin{macrocode}
\int_new:N \g__exam_id_int
\int_new:N \g__question_number_int
\int_new:N \g__question_seed_int
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}

% \begin{macro}{\g__question_answer_tl}
% \begin{macro}{\g__question_type_tl}
% \begin{macro}{\g__question_level_tl}
% \begin{macro}{\g__question_marks_tl}
%   Token lists for storing question data.
%    \begin{macrocode}
\tl_new:N \g__question_answer_tl
\tl_new:N \g__question_type_tl
\tl_new:N \g__question_level_tl
\tl_new:N \g__question_marks_tl
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}

% \begin{macro}{\g__question_type_prop}
%   Property list that maps question type identifiers to their display names.
%    \begin{macrocode}
\prop_new:N \g__question_type_prop
\prop_put:Nnn \g__question_type_prop {MC} {Multiple~Choice}
\prop_put:Nnn \g__question_type_prop {TF} {True/False}
\prop_put:Nnn \g__question_type_prop {FillBlank} {Fill~in~the~Blank}
\prop_put:Nnn \g__question_type_prop {Ordering} {Ordering}
\prop_put:Nnn \g__question_type_prop {Matching} {Matching}
\prop_put:Nnn \g__question_type_prop {Essay} {Essay}
\prop_put:Nnn \g__question_type_prop {ShortAnswer} {Short~Answer}
\prop_put:Nnn \g__question_type_prop {ReadingPassage} {Reading~Passage}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\g__exam_letters_seq}
%   Sequence of Latin letters (a--z) for labeling options.
%    \begin{macrocode}
\seq_new:N \g__exam_letters_seq
\seq_set_from_clist:Nn \g__exam_letters_seq
{
  a , b , c , d , e , f , g , h , i , j , k , l , m , n , o , p , q ,
  r , s , t , u , v , w , x , y , z
}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\StudentMode}
% \begin{macro}{\TeacherMode}
%   Set the teacher/student mode booleans.
%    \begin{macrocode}
\NewDocumentCommand{\StudentMode}{}
  { \bool_gset_false:N \g__mode_teacher_bool }
\NewDocumentCommand{\TeacherMode}{}
  { \bool_gset_true:N \g__mode_teacher_bool }
%    \end{macrocode}
% \end{macro}
% \end{macro}

% \begin{macro}{\ShowType}
% \begin{macro}{\ShowDifficulty}
% \begin{macro}{\ShowMarks}
% \begin{macro}{\ShowCorrection}
%   Set metadata visibility booleans.
%    \begin{macrocode}
\NewDocumentCommand{\ShowType}{}
  { \bool_gset_true:N \g__mode_type_bool }
\NewDocumentCommand{\ShowDifficulty}{}
  { \bool_gset_true:N \g__mode_difficulty_bool }
\NewDocumentCommand{\ShowMarks}{}
  { \bool_gset_true:N \g__mode_marks_bool }
\NewDocumentCommand{\ShowCorrection}{}
  { \bool_gset_true:N \g__mode_correction_bool }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}

% \begin{macro}{\ExamID}
%   Sets the randomization seed. Use \texttt{0} for default system seed.
%    \begin{macrocode}
\NewDocumentCommand{\ExamID}{m}{
  \int_gset:Nn \g__exam_id_int {#1}
  \sys_gset_rand_seed:n {#1}
}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\__question_build_seed}
%   Builds a unique seed for each question based on the exam ID and
%   question number. This ensures consistent randomization across
%   compilations.
%    \begin{macrocode}
\cs_new_protected:Npn \__question_build_seed: {
  \int_gset:Nn \g__question_seed_int
  { \int_eval:n { \g__exam_id_int * 1000 + \g__question_number_int } }
  \sys_gset_rand_seed:n { \g__question_seed_int }
}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\__exam_print_answer_box}
%   Prints a formatted answer key box in teacher mode.
%    \begin{macrocode}
\cs_new_protected:Npn \__exam_print_answer_box:
{
    \par\smallskip
    \begin{tcolorbox}[
enhanced,
breakable,
colback=white,
colframe=black,
arc=0pt,
outer~arc=0pt,
boxrule=1pt,
top=10pt,
bottom=10pt,
left=10pt,
right=10pt,
parbox=true,
fontupper=\linespread{1.2}\selectfont,
before~upper={\begin{flushleft}},
after~upper={\end{flushleft}},
coltitle=black,
fonttitle=\bfseries,
title={Answer~Key},
attach~boxed~title~to~top~left={
    xshift=5mm,
    yshift=-3.5mm
},
boxed~title~style={
    colback=white,
    colframe=white,
    left=5pt, right=5pt
}
]{
    \setlength{\baselineskip}{1.2\normalbaselineskip}
        \tl_use:N \g__question_answer_tl
}
    \end{tcolorbox}
    \par\smallskip
}
%    \end{macrocode}
% \end{macro}

% \begin{environment}{Question}
%   Main container for all question types. Handles numbering, metadata,
%   and answer collection.
%    \begin{macrocode}
\dim_new:N \g__question_number_width_dim
\dim_new:N \g__question_metadata_width_dim
\dim_new:N \g__question_text_width_dim

\NewDocumentEnvironment{Question}{ m m m m }
  {
    \int_gincr:N \g__question_number_int

    \tl_gset:Nn \g__question_type_tl   {#1}
    \tl_gset:Nn \g__question_level_tl  {#2}
    \tl_gset:Nn \g__question_marks_tl  {#3}

    \tl_gclear:N \g__question_answer_tl

    \__question_build_seed:

    \tl_clear:N \l_tmpa_tl
    \bool_if:nT { \g__mode_type_bool }
      {
        \tl_put_right:Nn \l_tmpa_tl
          { [\prop_item:Nn \g__question_type_prop {#1}] }
      }
    \bool_if:nT { \g__mode_difficulty_bool }
      { \tl_put_right:Nn \l_tmpa_tl { ~[#2] } }
    \bool_if:nT { \g__mode_marks_bool }
      { \tl_put_right:Nn \l_tmpa_tl { ~[#3~marks] } }

    \settowidth{\g__question_metadata_width_dim}
      { \footnotesize \l_tmpa_tl }

    \settowidth{\g__question_number_width_dim}
      { \bfseries Question~\PrintNumber{ \g__question_number_int }:~ }

    \dim_set:Nn \g__question_text_width_dim
      {
        \linewidth
        - \g__question_number_width_dim
        - \g__question_metadata_width_dim
        - 1em
      }

    \dim_compare:nNnT { \g__question_text_width_dim } < { 0pt }
      { \dim_set:Nn \g__question_text_width_dim { 0pt } }

    \par\medskip
    \noindent
    \makebox[\linewidth][l]
      {
        \makebox[\g__question_number_width_dim][l]
          {\bfseries Question~\PrintNumber{\g__question_number_int}:~}

        \parbox[t]{\g__question_text_width_dim}
          { \bfseries #4 }

        \hfill
        { \footnotesize
          \bool_if:nT { \g__mode_type_bool }
            { [\prop_item:Nn \g__question_type_prop {#1}] }
          \bool_if:nT { \g__mode_difficulty_bool }
            { ~[#2] }
          \bool_if:nT { \g__mode_marks_bool }
            { ~[#3~marks] }
        }
      }
    \par\smallskip
  }
  {
    \bool_if:nT { \g__mode_teacher_bool && \g__mode_correction_bool }
      {
        \tl_if_empty:NF \g__question_answer_tl
          { \__exam_print_answer_box: }
      }
    \par\smallskip
  }
%    \end{macrocode}
% \end{environment}

% \begin{environment}{MC}
%   Creates multiple-choice questions with shuffled options.
%    \begin{macrocode}
\dim_new:N \l__mc_label_width_dim
\dim_new:N \l__mc_label_sep_dim
\dim_new:N \l__mc_col_sep_dim
\dim_new:N \l__mc_text_width_dim

\dim_set:Nn \l__mc_label_width_dim { 1.25em }
\dim_set:Nn \l__mc_label_sep_dim { 0.5em }
\dim_set:Nn \l__mc_col_sep_dim { 1.5em }

\dim_new:N \l__mc_before_first_question_dim
\dim_new:N \l__mc_after_question_text_dim
\dim_new:N \l__mc_between_questions_dim
\dim_new:N \l__mc_after_options_dim
\dim_new:N \l__mc_between_option_lines_dim

\dim_set:Nn \l__mc_before_first_question_dim { 0.2em }
\dim_set:Nn \l__mc_after_question_text_dim { 0.4em }
\dim_set:Nn \l__mc_between_questions_dim { 0.3em }
\dim_set:Nn \l__mc_after_options_dim { 0.3em }
\dim_set:Nn \l__mc_between_option_lines_dim { 0.7em }

\int_new:N \l__mc_question_counter_int
\int_new:N \l__mc_option_counter_int
\int_new:N \l__mc_columns_int
\int_new:N \l__mc_correct_index_int
\seq_new:N \l__mc_options_seq
\tl_new:N \l__mc_question_text_tl

\NewDocumentEnvironment{MC}{ O{4} }
  {
    \int_set:Nn \l__mc_columns_int {#1}
    \int_zero:N \l__mc_question_counter_int
    \int_zero:N \l__mc_option_counter_int
    \par
  }
  {
    \int_compare:nNnT { \l__mc_option_counter_int } > { 0 }
      { \__mc_display_options: }
    \par
  }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\MCQuestion}
%   Defines a multiple-choice question within the MC environment.
%    \begin{macrocode}
\NewDocumentCommand{\MCQuestion}{ m m }
  {
    \int_compare:nNnT { \l__mc_option_counter_int } > { 0 }
      {
        \__mc_display_options:
        \par\vspace{\l__mc_after_options_dim}
      }

    \int_incr:N \l__mc_question_counter_int

    \int_compare:nNnTF { \l__mc_question_counter_int } = { 1 }
      { \par\vspace{\l__mc_before_first_question_dim} }
      { \par\vspace{\l__mc_between_questions_dim} }

    \par\noindent
    \textbf{\PrintNumber{\l__mc_question_counter_int}.~#1}
    \par\vspace{\l__mc_after_question_text_dim}

    \int_set:Nn \l__mc_correct_index_int {#2}
    \int_zero:N \l__mc_option_counter_int
    \seq_clear:N \l__mc_options_seq
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\MCOption}
%   Defines an option for a multiple-choice question.
%    \begin{macrocode}
\NewDocumentCommand{\MCOption}{ m }
  {
    \int_incr:N \l__mc_option_counter_int
    \seq_put_right:Nn \l__mc_options_seq {#1}
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\__mc_display_options}
%   Displays the shuffled options in a grid layout.
%    \begin{macrocode}
\cs_new_protected:Npn \__mc_display_options:
  {
    \int_compare:nNnT { \l__mc_option_counter_int } = { 0 }
      {
        \msg_warning:nn { mc } { no-options }
        \par
        \scan_stop:
      }

    \tl_set:Nx \l_tmpa_tl
      { \seq_item:Nn \l__mc_options_seq { \l__mc_correct_index_int } }

    \seq_shuffle:N \l__mc_options_seq

    \int_set:Nn \l_tmpa_int
      {\int_mod:nn { \l__mc_option_counter_int} {\l__mc_columns_int }}

    \int_compare:nNnT { \l_tmpa_int } > { 0 }
      {
        \int_set:Nn \l_tmpb_int { \l__mc_columns_int - \l_tmpa_int }
        \prg_replicate:nn { \l_tmpb_int }
          { \seq_put_right:Nn \l__mc_options_seq { \hspace{0pt} } }
      }

    \dim_set:Nn \l_tmpb_dim
      { \int_eval:n { \l__mc_columns_int - 1 } \l__mc_col_sep_dim }
    \dim_set:Nn \l_tmpa_dim
      { ( \linewidth - \l_tmpb_dim ) / \l__mc_columns_int }

    \dim_set:Nn \l__mc_text_width_dim
      { \dim_eval:n
        { \l_tmpa_dim - \l__mc_label_width_dim - \l__mc_label_sep_dim }
      }

    \dim_compare:nNnT { \l__mc_text_width_dim } < { 0pt }
      { \dim_set:Nn \l__mc_text_width_dim { 0pt } }

    \noindent
    \int_step_inline:nn { \seq_count:N \l__mc_options_seq }
      {
        \tl_set:Nx \l_tmpb_tl {\seq_item:Nn \l__mc_options_seq {##1}}

        \makebox[\l_tmpa_dim][l]
          {
            \makebox[\l__mc_label_width_dim][r]
              {
                \int_compare:nNnTF {##1} > {\l__mc_option_counter_int}
                  { \hspace{0pt} }
                  { \seq_item:Nn \g__exam_letters_seq {##1}) }
              }%
            \hspace{\l__mc_label_sep_dim}%
            \parbox[t]{\l__mc_text_width_dim}
              {
                \setlength{\baselineskip}{1.2\normalbaselineskip}
                \raggedright
                \l_tmpb_tl
                \par
              }%
          }

        \int_compare:nNnT { ##1 } < { \l__mc_option_counter_int + 1 }
          {
            \tl_if_eq:VVT \l_tmpb_tl \l_tmpa_tl
              {
                \tl_gput_right:Nx \g__question_answer_tl
                  {
                    \exp_not:N \makebox[5.25em][l]
                      {
                        (\PrintNumber{\l__mc_question_counter_int})~
                         $\Rightarrow$~
                        (\seq_item:Nn \g__exam_letters_seq {##1})
                      }%
                    \qquad
                  }
              }
          }

        \int_compare:nNnF
          { \int_mod:nn {##1} { \l__mc_columns_int } } = { 0 }
          { \hspace{\l__mc_col_sep_dim} }

        \int_compare:nNnT
          { \int_mod:nn {##1} { \l__mc_columns_int } } = { 0 }
          {
            \par\prevdepth=\dp\strutbox%
            \vspace{\l__mc_between_option_lines_dim}
            \noindent
          }
      }
    \par
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\msg_new:nnn{mc}{no-options}}
%   Warning message for MC questions without options.
%    \begin{macrocode}
\msg_new:nnn { mc } { no-options }
  {
    Warning: No options for question
    \int_use:N \l__mc_question_counter_int.
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{TF}
%   Creates True/False questions with two display styles.
%    \begin{macrocode}
\int_new:N \l__tf_question_counter_int
\tl_new:N \l__tf_question_text_tl
\tl_new:N \l__tf_correct_answer_tl
\bool_new:N \l__tf_style_bool

\dim_const:Nn \l__tf_number_width_dim { 5.3mm }
\dim_const:Nn \l__tf_bracket_width_dim { 3em }
\dim_const:Nn \l__tf_option_width_dim { 8em }

\dim_new:N \l__tf_before_first_question_dim
\dim_new:N \l__tf_between_questions_dim
\dim_set:Nn \l__tf_before_first_question_dim { 0.3em }
\dim_set:Nn \l__tf_between_questions_dim { 0.7em }

\NewDocumentEnvironment{TF}{ O{bracket} }
  {
    \int_zero:N \l__tf_question_counter_int

    \str_if_eq:nnTF {#1} {bracket}
      { \bool_set_true:N \l__tf_style_bool }
      { \bool_set_false:N \l__tf_style_bool }
  }
  { \vspace{0.3em} }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\TFQuestion}
%   Defines a True/False question.
%    \begin{macrocode}
\NewDocumentCommand{\TFQuestion}{ m m }
  {
    \int_incr:N \l__tf_question_counter_int

    \int_compare:nNnTF { \l__tf_question_counter_int } = { 1 }
      { \par\vspace{\l__tf_before_first_question_dim} }
      { \par\vspace{\l__tf_between_questions_dim} }

    \par\noindent
    \makebox[5.0mm][r]
      { \PrintNumber{\l__tf_question_counter_int}\vphantom{(}. }%
    \hspace{0.7em}%

    \bool_if:NTF \l__tf_style_bool
      {
        \parbox[t]{\dim_eval:n{\linewidth-8.0mm}}
          {
            \setlength{\baselineskip}{1.2\normalbaselineskip}
            #1\unskip\nobreak\hspace{1em}%
            \makebox[3em][c]{( \hspace{1.5em} )}
            \par
          }
      }
      {
        \parbox[t]
          {\dim_eval:n{\linewidth-8.0mm-\l__tf_option_width_dim}}
          {
            \setlength{\baselineskip}{1.2\normalbaselineskip}
            #1
            \par
          }%
        \hfill
        \makebox[\l__tf_option_width_dim][c]
          {
            \makebox[3em][c]{True}%
            \hspace{1em}%
            \makebox[3em][c]{False}
          }
      }
    \par\prevdepth=\dp\strutbox%

    \tl_gput_right:Nx \g__question_answer_tl
      {
        \exp_not:N \makebox[5.25em][l]
          {
            (\PrintNumber{\l__tf_question_counter_int})~
             $\Rightarrow$~
            #2
          }%
        \quad
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{FillBlank}
%   Creates fill-in-the-blank questions with optional word bank.
%    \begin{macrocode}
\int_new:N \l__fb_question_counter_int
\tl_new:N \l__fb_answer_tl
\bool_new:N \l__fb_wordbank_bool

\dim_const:Nn \l__fb_number_width_dim { 5.3mm }

\dim_new:N \l__fb_before_first_question_dim
\dim_new:N \l__fb_between_questions_dim
\dim_set:Nn \l__fb_before_first_question_dim { 0.5em }
\dim_set:Nn \l__fb_between_questions_dim { 0.8em }

\NewDocumentEnvironment{FillBlank}{ O{false} }
  {
    \int_zero:N \l__fb_question_counter_int
    \tl_clear:N \l__fb_answer_tl
    \str_if_eq:nnTF {#1} {true}
      { \bool_set_true:N \l__fb_wordbank_bool }
      { \bool_set_false:N \l__fb_wordbank_bool }
  }
  {
    \tl_gset_eq:NN \g__question_answer_tl \l__fb_answer_tl
    \vspace{0.35em}%
  }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\WordBank}
%   Displays a dynamic word bank box.
%    \begin{macrocode}
\NewDocumentCommand{\WordBank}{ O{\quad} m }
  {
    \bool_if:NT \l__fb_wordbank_bool
      {
        \par\vspace{0.5em}\noindent

        \tl_clear:N \l_tmpa_tl
        \clist_set:Nn \l_tmpa_clist {#2}

        \hbox_set:Nn \l_tmpa_box { \clist_use:Nn \l_tmpa_clist {#1} }
        \dim_set:Nn \l_tmpa_dim { \box_wd:N \l_tmpa_box }

        \dim_set:Nn \l_tmpb_dim { 0.9\linewidth }

        \dim_compare:nNnTF { \l_tmpa_dim } > { \l_tmpb_dim }
          { \dim_set:Nn \l_tmpa_dim { \l_tmpb_dim } }
          { }

        \dim_add:Nn \l_tmpa_dim { 10pt }

        \makebox[\linewidth][c]
          {
            \fbox
              {%
                \begin{minipage}{\l_tmpa_dim}
                  \centering
                  \vspace{4pt}
                  \setlength{\baselineskip}{1.2\normalbaselineskip}
                  \clist_use:Nn \l_tmpa_clist {#1}
                  \vspace{3pt}
                \end{minipage}%
              }
          }%
        \par\vspace{0.3em}
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\Blank}
%   Creates an underline field for student answers.
%    \begin{macrocode}
\NewDocumentCommand{\Blank}{ O{4.25em} }
  { \underline{\hspace{#1}} }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\FillQuestion}
%   Defines a fill-in-the-blank question with its answer.
%    \begin{macrocode}
\NewDocumentCommand{\FillQuestion}{ m m }
  {
    \int_incr:N \l__fb_question_counter_int

    \int_compare:nNnTF { \l__fb_question_counter_int } = { 1 }
      { \par\vspace{\l__fb_before_first_question_dim} }
      { \par\vspace{\l__fb_between_questions_dim} }

    \par\noindent
    \makebox[5.0mm][r]
      { \PrintNumber{\l__fb_question_counter_int}\vphantom{(}. }%
    \hspace{0.7em}%

    \parbox[t]{\dim_eval:n{\linewidth-8.0mm}}
      {
        \setlength{\baselineskip}{1.2\normalbaselineskip}
        #1
        \par
      }
    \par\prevdepth=\dp\strutbox%

    \seq_set_split:Nnn \l_tmpa_seq { | } {#2}
    \int_zero:N \l_tmpa_int

    \seq_map_inline:Nn \l_tmpa_seq
      {
        \int_incr:N \l_tmpa_int

        \int_compare:nNnTF { \seq_count:N \l_tmpa_seq } > { 1 }
          {
            \tl_put_right:Nx \l__fb_answer_tl
              {
                \exp_not:N
                  (\PrintNumber{\l__fb_question_counter_int} -
                   \int_use:N \l_tmpa_int)~$\Rightarrow$~##1
                \exp_not:N \par
                \exp_not:N \noindent
              }
          }
          {
            \tl_put_right:Nx \l__fb_answer_tl
              {
                \exp_not:N (\PrintNumber{\l__fb_question_counter_int})~
                $\Rightarrow$~
                ##1
                \exp_not:N \par
                \exp_not:N \noindent
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{Ordering}
%   Creates sequencing questions with shuffled options.
%    \begin{macrocode}
\int_new:N \l__ord_question_counter_int
\int_new:N \l__ord_option_counter_int
\int_new:N \l__ord_columns_int
\seq_new:N \l__ord_options_seq
\seq_new:N \l__ord_original_order_seq
\tl_new:N  \l__ord_answer_tl

\bool_new:N \l__ord_answer_pending_bool

\dim_new:N \l__ord_answer_width_dim
\dim_set:Nn \l__ord_answer_width_dim { 1.5em }

\dim_new:N \l__ord_label_width_dim
\dim_new:N \l__ord_label_sep_dim
\dim_new:N \l__ord_col_sep_dim
\dim_new:N \l__ord_text_width_dim
\dim_set:Nn \l__ord_label_width_dim { 1.25em }
\dim_set:Nn \l__ord_label_sep_dim { 0.5em }
\dim_set:Nn \l__ord_col_sep_dim { 1.5em }

\dim_new:N \l__ord_before_first_question_dim
\dim_new:N \l__ord_after_question_text_dim
\dim_new:N \l__ord_between_questions_dim
\dim_new:N \l__ord_after_options_dim
\dim_new:N \l__ord_between_option_lines_dim

\dim_set:Nn \l__ord_before_first_question_dim { 0.2em }
\dim_set:Nn \l__ord_after_question_text_dim { 0.4em }
\dim_set:Nn \l__ord_between_questions_dim { 0.3em }
\dim_set:Nn \l__ord_after_options_dim { 0.3em }
\dim_set:Nn \l__ord_between_option_lines_dim { 0.7em }

\NewDocumentEnvironment{Ordering}{ O{4} }
  {
    \int_set:Nn \l__ord_columns_int {#1}
    \int_zero:N \l__ord_question_counter_int
    \int_zero:N \l__ord_option_counter_int
    \tl_clear:N \l__ord_answer_tl
    \seq_clear:N \l__ord_options_seq
    \seq_clear:N \l__ord_original_order_seq
    \bool_set_false:N \l__ord_answer_pending_bool
    \par
  }
  {
    \int_compare:nNnT { \l__ord_option_counter_int } > { 0 }
      { \__ord_display_options: }

    \tl_gset_eq:NN \g__question_answer_tl \l__ord_answer_tl

    \par
  }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\OrderQuestion}
%   Defines an ordering question.
%    \begin{macrocode}
\NewDocumentCommand{\OrderQuestion}{ m }
  {
    \int_compare:nNnT { \l__ord_option_counter_int } > { 0 }
      {
        \__ord_display_options:
        \par\vspace{\l__ord_after_options_dim}
      }

    \int_incr:N \l__ord_question_counter_int

    \int_compare:nNnTF { \l__ord_question_counter_int } = { 1 }
      { \par\vspace{\l__ord_before_first_question_dim} }
      { \par\vspace{\l__ord_between_questions_dim} }

    \par\noindent
    \textbf{\PrintNumber{\l__ord_question_counter_int}.~#1}
    \par\vspace{\l__ord_after_question_text_dim}

    \int_zero:N \l__ord_option_counter_int
    \seq_clear:N \l__ord_options_seq
    \seq_clear:N \l__ord_original_order_seq
    \bool_set_false:N \l__ord_answer_pending_bool
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\OrderOption}
%   Defines an option for an ordering question.
%    \begin{macrocode}
\NewDocumentCommand{\OrderOption}{ m }
  {
    \int_incr:N \l__ord_option_counter_int
    \seq_put_right:Nn \l__ord_options_seq {#1}
    \seq_put_right:Nn \l__ord_original_order_seq {#1}
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\OrderAnswer}
%   Adds an optional answer space after ordering options.
%    \begin{macrocode}
\NewDocumentCommand{\OrderAnswer}{ O{1.5em} }
  {
    \bool_set_true:N \l__ord_answer_pending_bool
    \dim_set:Nn \l__ord_answer_width_dim {#1}
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\__ord_display_options}
%   Displays shuffled ordering options and builds the answer key.
%    \begin{macrocode}
\cs_new_protected:Npn \__ord_display_options:
  {
    \int_compare:nNnT { \l__ord_option_counter_int } = { 0 }
      {
        \msg_warning:nn { ord } { no-options }
        \par
        \scan_stop:
      }

    \seq_shuffle:N \l__ord_options_seq

    \int_set:Nn \l_tmpa_int
      {\int_mod:nn {\l__ord_option_counter_int} {\l__ord_columns_int}}

    \int_compare:nNnT { \l_tmpa_int } > { 0 }
      {
        \int_set:Nn \l_tmpb_int { \l__ord_columns_int - \l_tmpa_int }
        \prg_replicate:nn { \l_tmpb_int }
          { \seq_put_right:Nn \l__ord_options_seq { \hspace{0pt} } }
      }

    \dim_set:Nn \l_tmpb_dim
      { \int_eval:n { \l__ord_columns_int - 1 } \l__ord_col_sep_dim }
    \dim_set:Nn \l_tmpa_dim
      { ( \linewidth - \l_tmpb_dim ) / \l__ord_columns_int }

    \dim_set:Nn \l__ord_text_width_dim
      { \dim_eval:n
        {\l_tmpa_dim - \l__ord_label_width_dim - \l__ord_label_sep_dim}
      }

    \dim_compare:nNnT { \l__ord_text_width_dim } < { 0pt }
      { \dim_set:Nn \l__ord_text_width_dim { 0pt } }

    \noindent
    \int_step_inline:nn { \seq_count:N \l__ord_options_seq }
      {
        \tl_set:Nx \l_tmpb_tl {\seq_item:Nn \l__ord_options_seq {##1}}

        \makebox[\l_tmpa_dim][l]
          {
            \makebox[\l__ord_label_width_dim][l]
              {
                \int_compare:nNnTF {##1} > {\l__ord_option_counter_int}
                  { \hspace{0pt} }
                  { \seq_item:Nn \g__exam_letters_seq {##1}) }
              }%
            \hspace{\l__ord_label_sep_dim}%
            \parbox[t]{\l__ord_text_width_dim}
              {
                \setlength{\baselineskip}{1.2\normalbaselineskip}
                \raggedright
                \l_tmpb_tl
                \par
              }
          }

        \int_compare:nNnF
          { \int_mod:nn {##1} { \l__ord_columns_int } } = { 0 }
          { \hspace{\l__ord_col_sep_dim} }

        \int_compare:nNnT
          { \int_mod:nn {##1} { \l__ord_columns_int } } = { 0 }
          {
            \par\prevdepth=\dp\strutbox%
            \vspace{\l__ord_between_option_lines_dim}
            \noindent
          }
      }
    \par

    \__ord_build_correct_order:

    \bool_if:NT \l__ord_answer_pending_bool
      {
        \__ord_print_answer:
        \bool_set_false:N \l__ord_answer_pending_bool
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\__ord_build_correct_order}
%   Builds the correct order string for the answer key.
%    \begin{macrocode}
\cs_new_protected:Npn \__ord_build_correct_order:
  {
    \tl_clear:N \l_tmpa_tl

    \int_step_inline:nn { \l__ord_option_counter_int }
      {
        \int_zero:N \l_tmpb_int
        \tl_set:Nx \l_tmpb_tl
          { \seq_item:Nn \l__ord_original_order_seq {##1} }

        \int_step_inline:nn { \l__ord_option_counter_int }
          {
            \tl_set:Nx \l_tmpc_tl
              { \seq_item:Nn \l__ord_options_seq {####1} }
            \tl_if_eq:NNT \l_tmpb_tl \l_tmpc_tl
              { \int_set:Nn \l_tmpb_int {####1} }
          }

        \tl_put_right:Nx \l_tmpa_tl
          {\seq_item:Nn \g__exam_letters_seq {\int_use:N \l_tmpb_int}}

        \int_compare:nNnF {##1} = { \l__ord_option_counter_int }
          { \tl_put_right:Nn \l_tmpa_tl { ~,~ } }
      }

    \tl_put_right:Nx \l__ord_answer_tl
      {
        \exp_not:N \makebox[4em][l]
          {
            (\PrintNumber{\l__ord_question_counter_int})~
             $\Rightarrow$~
            \l_tmpa_tl
          }%
        \par
        \noindent
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\__ord_print_answer}
%   Prints the answer space for ordering questions.
%    \begin{macrocode}
\cs_new_protected:Npn \__ord_print_answer:
  {
    \par
    \noindent
    Order:\quad
    \int_step_inline:nn { \l__ord_option_counter_int }
      {
        \underline{\hspace{\l__ord_answer_width_dim}}\,
        \int_compare:nNnT {##1} < {\l__ord_option_counter_int} { ,\ }
      }
    \par\vspace{0.3\baselineskip}
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{Matching}
%   Creates two-column matching questions with shuffled right column.
%    \begin{macrocode}
\seq_new:N \l__match_left_seq
\seq_new:N \l__match_right_seq
\seq_new:N \l__match_index_seq
\int_new:N \l__match_count_int
\tl_new:N  \l__match_answer_tl

\dim_new:N \l__match_label_width_dim
\dim_new:N \l__match_label_sep_dim
\dim_new:N \l__match_col_sep_dim
\dim_new:N \l__match_left_text_width_dim
\dim_new:N \l__match_right_text_width_dim
\dim_new:N \l__match_left_width_dim
\dim_new:N \l__match_right_width_dim

\dim_new:N \l__match_before_first_dim
\dim_new:N \l__match_between_pairs_dim

\dim_set:Nn \l__match_label_width_dim { 1.5em }
\dim_set:Nn \l__match_label_sep_dim { 0.5em }
\dim_set:Nn \l__match_col_sep_dim { 2em }
\dim_set:Nn \l__match_before_first_dim { 0.3em }
\dim_set:Nn \l__match_between_pairs_dim { 0.7em }

\NewDocumentEnvironment{Matching}{ O{0.5} }
  {
    \seq_clear:N \l__match_left_seq
    \seq_clear:N \l__match_right_seq
    \seq_clear:N \l__match_index_seq
    \tl_clear:N  \l__match_answer_tl

    \dim_set:Nn \l__match_left_width_dim
      {#1\linewidth-\l__match_label_width_dim-\l__match_label_sep_dim}
    \dim_set:Nn \l__match_right_width_dim
      {\linewidth - \l__match_left_width_dim - \l__match_col_sep_dim}

    \dim_set:Nn \l__match_left_text_width_dim
      { \l__match_left_width_dim
        - \l__match_label_width_dim
        - \l__match_label_sep_dim }
    \dim_set:Nn \l__match_right_text_width_dim
      { \l__match_right_width_dim
        - \l__match_label_width_dim
        - \l__match_label_sep_dim }
  }
  {
    \int_compare:nNnT { \seq_count:N \l__match_left_seq } = { 0 }
      { \msg_error:nn { matching } { empty-pair } }

    \int_compare:nNnF { \seq_count:N \l__match_left_seq } =
      { \seq_count:N \l__match_right_seq }
      {
        \msg_warning:nnx { matching } { odd-number }
          { \int_use:N \seq_count:N \l__match_left_seq }
          { \int_use:N \seq_count:N \l__match_right_seq }
      }

    \int_set:Nn \l__match_count_int
      { \seq_count:N \l__match_right_seq }

    \int_step_inline:nn { \l__match_count_int }
      { \seq_put_right:Nn \l__match_index_seq {##1} }

    \seq_shuffle:N \l__match_index_seq

    \par\vspace{\l__match_before_first_dim}
    \noindent
    \begin{minipage}[t]{\l__match_left_width_dim}
      \raggedright
      \int_step_inline:nn { \l__match_count_int }
        {
          \makebox[\l__match_label_width_dim][r]
            { \PrintNumber{##1}) }%
          \hspace{\l__match_label_sep_dim}%
          \parbox[t]{\l__match_left_text_width_dim}
            {
              \setlength{\baselineskip}{1.2\normalbaselineskip}
              \raggedright
              \seq_item:Nn \l__match_left_seq {##1}
              \par
              \vspace{0.1em}
            }
          \par\prevdepth=\dp\strutbox%
          \vspace{\l__match_between_pairs_dim}
        }
    \end{minipage}
    \hspace{\l__match_col_sep_dim}
    \begin{minipage}[t]{\l__match_right_width_dim}
      \raggedright
      \int_step_inline:nn { \l__match_count_int }
        {
          \makebox[\l__match_label_width_dim][r]
            { \seq_item:Nn \g__exam_letters_seq {##1}) }%
          \hspace{\l__match_label_sep_dim}%
          \parbox[t]{\l__match_right_text_width_dim}
            {
              \setlength{\baselineskip}{1.2\normalbaselineskip}
              \raggedright
              \seq_item:Nn \l__match_right_seq
                { \seq_item:Nn \l__match_index_seq {##1} }
              \par
              \vspace{0.1em}
            }
          \par\prevdepth=\dp\strutbox%
          \vspace{\l__match_between_pairs_dim}
        }
    \end{minipage}
    \par

    \tl_clear:N \l__match_answer_tl

    \int_step_inline:nn { \l__match_count_int }
      {
        \int_zero:N \l_tmpa_int

        \int_step_inline:nn { \l__match_count_int }
          {
            \int_compare:nNnT
              { \seq_item:Nn \l__match_index_seq {####1} } = { ##1 }
              { \int_set:Nn \l_tmpa_int {####1} }
          }

        \tl_put_right:Nx \l__match_answer_tl
          {
            \exp_not:N \makebox[5.25em][l]
              {
                (\PrintNumber{##1})~
                 $\Rightarrow$~
                (\seq_item:Nn \g__exam_letters_seq
                  { \int_use:N \l_tmpa_int })
              }%
            \qquad
          }
      }

    \tl_gset_eq:NN \g__question_answer_tl \l__match_answer_tl
  }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\MatchPair}
%   Defines a matching pair.
%    \begin{macrocode}
\NewDocumentCommand{\MatchPair}{mm}
  {
    \seq_put_right:Nn \l__match_left_seq {#1}
    \seq_put_right:Nn \l__match_right_seq {#2}
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{Essay}
%   Creates essay questions with ruled or blank lines.
%    \begin{macrocode}
\int_new:N \l__essay_question_counter_int
\tl_new:N \l__essay_answer_tl
\bool_new:N \l__essay_lines_bool

\dim_const:Nn \l__essay_number_width_dim { 5.3mm }
\dim_new:N \l__essay_line_skip_dim
\dim_set:Nn \l__essay_line_skip_dim { 0.4\baselineskip }

\dim_new:N \l__essay_before_first_question_dim
\dim_new:N \l__essay_between_questions_dim
\dim_new:N \l__essay_after_question_dim

\dim_set:Nn \l__essay_before_first_question_dim { 0.2em }
\dim_set:Nn \l__essay_between_questions_dim { 0.2\baselineskip }
\dim_set:Nn \l__essay_after_question_dim { 0.65\baselineskip }

\NewDocumentEnvironment{Essay}{ O{true} }
  {
    \int_zero:N \l__essay_question_counter_int
    \tl_clear:N \l__essay_answer_tl

    \str_if_eq:nnTF {#1} {true}
      { \bool_set_true:N \l__essay_lines_bool }
      { \bool_set_false:N \l__essay_lines_bool }
  }
  {
    \tl_gset_eq:NN \g__question_answer_tl \l__essay_answer_tl
  }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\EssayQuestion}
%   Defines an essay question (no limit on number of lines).
%    \begin{macrocode}
\NewDocumentCommand{\EssayQuestion}{ O{4} m m }
  {
    \int_incr:N \l__essay_question_counter_int

    \int_set:Nn \l_tmpa_int {#1}

    \int_compare:nNnTF { \l__essay_question_counter_int } = { 1 }
      { \par\vspace{\l__essay_before_first_question_dim} }
      { \par\vspace{\l__essay_between_questions_dim} }

    \par\noindent
    \makebox[5.0mm][r]{\PrintNumber{\l__essay_question_counter_int}.}%
    \hspace{0.7em}%
    \parbox[t]{\dim_eval:n{\linewidth-8.0mm}}
      {
        \setlength{\baselineskip}{1.2\normalbaselineskip}
        #2
        \par
      }
    \par\prevdepth=\dp\strutbox%
    \vspace{\l__essay_after_question_dim}

    \int_step_inline:nn {#1}
      {
        \noindent
        \hspace*{6.0mm}%
        \rule{\dim_eval:n{\linewidth-6.0mm}}
          { \bool_if:NTF \l__essay_lines_bool {0.4pt} {0pt} }
        \par\vspace{\l__essay_line_skip_dim}
      }

    \tl_put_right:Nx \l__essay_answer_tl
      {
        \exp_not:N (\PrintNumber{\l__essay_question_counter_int})~
         $\Rightarrow$~
        #3
        \par
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{ShortAnswer}
%   Creates short answer questions (0, 1, or 2 lines).
%    \begin{macrocode}
\int_new:N \l__short_question_counter_int
\tl_new:N \l__short_answer_tl
\bool_new:N \l__short_lines_bool

\dim_const:Nn \l__short_number_width_dim { 5.3mm }
\dim_new:N \l__short_line_height_dim
\dim_set:Nn \l__short_line_height_dim { 0.4\baselineskip }

\dim_new:N \l__short_before_first_question_dim
\dim_new:N \l__short_between_questions_dim
\dim_new:N \l__short_after_question_dim

\dim_set:Nn \l__short_before_first_question_dim { 0.2em }
\dim_set:Nn \l__short_between_questions_dim { 0.2\baselineskip }
\dim_set:Nn \l__short_after_question_dim { 0.65\baselineskip }

\NewDocumentEnvironment{ShortAnswer}{ O{true} }
  {
    \int_zero:N \l__short_question_counter_int
    \tl_clear:N \l__short_answer_tl

    \str_if_eq:nnTF {#1} {true}
      { \bool_set_true:N \l__short_lines_bool }
      { \bool_set_false:N \l__short_lines_bool }
  }
  {
    \tl_gset_eq:NN \g__question_answer_tl \l__short_answer_tl
  }
%    \end{macrocode}
% \end{environment}

% \begin{macro}{\ShortQuestion}
%   Defines a short answer question (0, 1, or 2 lines, capped at 2 without warning).
%    \begin{macrocode}
\NewDocumentCommand{\ShortQuestion}{ O{1} m m }
  {
        \int_incr:N \l__short_question_counter_int

    \int_set:Nn \l_tmpa_int {#1}
    \int_compare:nNnT {#1} > { 2 }
      { \int_set:Nn \l_tmpa_int { 2 } }

    \int_compare:nNnTF { \l__short_question_counter_int } = { 1 }
      { \par\vspace{\l__short_before_first_question_dim} }
      { \par\vspace{\l__short_between_questions_dim} }

    \par\noindent
    \makebox[5.0mm][r]{\PrintNumber{\l__short_question_counter_int}.}%
    \hspace{0.7em}%
    \parbox[t]{\dim_eval:n{\linewidth-8.0mm}}
      {
        \setlength{\baselineskip}{1.2\normalbaselineskip}
        #2
        \int_compare:nNnT {#1} = { 0 }
          { \quad \underline{\hspace{6em}} }
      }
    \par\prevdepth=\dp\strutbox%
    \vspace{\l__short_after_question_dim}

    \int_compare:nNnT {#1} > { 0 }
      {
        \int_step_inline:nn { \l_tmpa_int }
          {
            \par
            \noindent
            \hspace*{6.0mm}%
            \rule{\dim_eval:n{\linewidth-6.0mm}}
              { \bool_if:NTF \l__short_lines_bool {0.4pt} {0pt} }
            \par\vspace{\l__short_line_height_dim}
          }
      }
    \par

    \tl_put_right:Nx \l__short_answer_tl
      {
        \exp_not:N (\PrintNumber{\l__short_question_counter_int})~
         $\Rightarrow$~
        #3
        \par
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{environment}{ReadingPassage}
%   Creates a boxed environment for reading passages.
%    \begin{macrocode}
\NewDocumentEnvironment{ReadingPassage}{ O{} m }
  {
    \par
    \begin{tcolorbox}[
      enhanced,
      breakable,
      colback=white,
      colframe=black,
      arc=0pt,
      outer~arc=0pt,
      boxrule=1pt,
      top=10pt,
      bottom=10pt,
      left=10pt,
      right=10pt,
      parbox=true,
      fontupper=\linespread{1.4}\selectfont,
      coltitle=black,
      fonttitle=\bfseries,
      title={\textbf{\tl_if_empty:nTF {#2} {Reading Passage} {#2}}},
      #1,
      attach~boxed~title~to~top~center={
        yshift=-3mm,
        yshifttext=-1mm
      },
      boxed~title~style={
        colback=white,
        colframe=white,
        left=5pt, right=5pt
      }
    ]
  }
  {
    \end{tcolorbox}
    \par\smallskip
  }
%    \end{macrocode}
% \end{environment}

%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}

% \iffalse
%</package>
% \fi

% \Finale