summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2010-03-05 00:35:14 +0000
committerKarl Berry <karl@freefriends.org>2010-03-05 00:35:14 +0000
commit1c7434bb6484069a01c6dad0c3cde3685a4e5d65 (patch)
tree5506aaacb010153c646ba0cbcbc6704b5f5b995d
parentbee7379de288cd8caaec136a9bf4d51c84990842 (diff)
new latex package skeyval 0.5 (4mar10)
git-svn-id: svn://tug.org/texlive/trunk@17321 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/latex/skeyval/README35
-rw-r--r--Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex32
-rw-r--r--Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdfbin0 -> 312704 bytes
-rw-r--r--Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex1230
-rw-r--r--Master/texmf-dist/tex/latex/skeyval/skeyval.sty1679
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/skeyval.tlpsrc0
8 files changed, 2978 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/skeyval/README b/Master/texmf-dist/doc/latex/skeyval/README
new file mode 100644
index 00000000000..5d4fc0d8070
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/skeyval/README
@@ -0,0 +1,35 @@
+%++++++++++++++++++++++++++++++++++++ MOTIVATION ++++++++++++++++++++++++++++++++++++%
+% %
+% The elaborate and useful xkeyval package introduced \define@cmdkeys and %
+% \define@boolkeys, which allow for the setting of multiple command keys and %
+% boolean keys, but in each category those keys must have the same default value %
+% and no key macro/function. This package seeks to remove these restrictions, %
+% so that multiple keys of all categories (ordinary keys, command keys, boolean %
+% keys, and choice keys) can be set at one go and those keys can have different %
+% default values and functions. This greatly saves tokens, as hundreds of keys %
+% can, in principle, be issued simultaneously by one command. %
+% %
+% Also, the xkeyval package doesn't have the notion of complementary keys, %
+% which is useful in the case of boolean keys. The present package introduces %
+% this concept and additionally permits the submission of individual/different %
+% key macros to the complementary keys. %
+% %
+%+++++++++++++++++++++++++++++++++++++ LICENSE ++++++++++++++++++++++++++++++++++++++%
+% %
+% This package and accompanying files may be distributed and/or modified under %
+% the conditions of the LaTeX Project Public License, either version 1.3 of %
+% this license or any later version. The latest version of this license is in %
+% http://www.latex-project.org/lppl.txt and version 1.3 or later is part of all %
+% distributions of LaTeX version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, either %
+% expressed or implied, including, but not limited to, the implied warranties of %
+% merchantability and fitness for a particular purpose. %
+% %
+% Version 0.5 %
+% %
+% Copyright (c) 2010 Ahmed Musa (a.musa@rocketmail.com). %
+% %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \ No newline at end of file
diff --git a/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex b/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex
new file mode 100644
index 00000000000..b27304826df
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex
@@ -0,0 +1,32 @@
+%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file skeyval-bugreport.tex, the bug report file for the %
+% skeyval package, version 0.5. %
+% %
+% (c) Ahmed Musa 2010 (a.musa@rocketmail.com) %
+%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% %
+% IMPORTANT %
+% %
+% Fill in the details below, compile the file and email the %
+% sample file, the log file, and the auxiliary file to %
+% a.musa@rocketmail.com. %
+% %
+%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+\documentclass{article}
+\listfiles
+\usepackage[logonly]{trace}
+\traceon
+% \usepackage[Put your options here]{skeyval}
+
+% Load your select packages here:
+
+% Provide other elements of your preamble here:
+
+\traceoff
+\begin{document}
+\traceon
+% Provide sample text here:
+
+
+\traceoff
+\end{document}
diff --git a/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf
new file mode 100644
index 00000000000..ac1afaa461e
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex
new file mode 100644
index 00000000000..acef82c6d8a
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex
@@ -0,0 +1,1230 @@
+\documentclass[
+ final,language=UKenglish,review=false,parskip,lettrine
+]{amltxdoc}
+\makeatletter
+\amltxdoc{%
+ frontpagestyle = empty,
+ pretitleskip = 0cm,
+ afttitleskip = 1ex,
+ natbib = {numbers,sort&compress},
+ xcolor = {dvipsnames,table,hyperref},
+ lhead = {The \textcolor{\amd@specolor}{skeyval} Package},
+ rhead = {Page~\thepage~of~\zpageref{LastPage}},
+ cmdcolor = xmagenta1,
+ stycolor = ForestGreen,
+ specolor = teal
+}
+\begin{document}
+\begin{titlematter}
+\suptitle{}
+\title{The \texttt{\color{blue}skeyval} Package}
+\subtitle{Version 0.5}
+\titlenote{The package was formerly called the \sty{keyreader} package until version~0.5. The \sty{keyreader} package is obsolete and no longer supported.}
+\author{Ahmed Musa\Email{a.musa@rocketmail.com}\\ Preston, Lancashire, UK}
+\nonumbernote{The \sty{skeyval} package is available at
+ \url{http://www.ctan.org/tex-archive/macros/latex/contrib/skeyval/}}
+\end{titlematter}
+
+\frameshade[width=\hsize,fillcolor=yellow!20,framesep=2pt,framerule=2pt,
+ framecolor=brown]{%
+ \frameshade[fillcolor=white,width=2cm,framecolor=red,framerule=2pt]%
+ {\centering\textsf{Abstract}}\small
+ \noindent This package supplements the \sty{xkeyval} package, hence the ``s'' in ``skeyval.'' It introduces toggle keys and complementary (boolean and toggle) keys. It also provides mechanisms for reserving, unreserving, suspending, restoring, and removing keys. Furthermore, it introduces a set of commands for key definition which bar the developer or user from inadvertently redefining existing keys of the same family and prefix. Commands are provided for checking the statuses of keys across multiple key prefixes and families. Also, the package provides a scheme for defining multiple keys of different genres using only one command, thereby making it possible to considerably economize on tokens when defining keys. Some other general-purpose developer macros are provided within the package.
+}
+
+\vskip\baselineskip
+\frameshade[width=\hsize,fillcolor=white,framesep=2pt,framerule=2pt,
+ framecolor=brown]{\small
+\centerline{\large\scshape License}
+\endgraf
+This work (\ie, all the files in the \sty{skeyval} bundle) may be distributed and/or modified under the conditions of the \lppl (LPPL), either version~1.3 of this license or any later version.
+\endgraf
+The LPPL maintenance status of this software is ``author-maintained''. This software is provided ``as it is,'' without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose.
+\endgraf
+The package is now at open beta stage and package distributors, such as makers of \miktex and \texlive, should wait for at least a stable version~1.0 before embarking on distribution. Bug reports are particularly welcome. Correspondents should use the file \sty{skeyval-bugreport.tex} provided as part of the bundle. \textcolor{red}{\CopyRightYear}
+}
+
+\newpage
+
+\frameshade[fillcolor=yellow!20,framecolor=brown,framerule=2pt,framesep=2pt,
+ width=1.1\hsize]{%
+ \begin{multicols}{2}%
+ \small\tableofcontents\normalsize
+ \end{multicols}%
+}%
+
+\section{Motivation}
+
+\lletter{T}oggle switches or booleans were introduced by the \sty{etoolbox} package and have proved very useful mainly for two reasons: unlike the legacy \tex switches which require three commands per switch, toggles require only one command per switch, and toggles occupy their own separate namespace, thereby avoiding clashes with other macros. So we can effectively have both the following sets in the same file:
+\begin{example}
+\newif\ifmyboolean -> 3 separate commands:
+ \ifmyboolean \mybooleantrue
+ \mybooleanfalse
+
+\newtoggle{myboolean} -> only 1 command and no clash with
+ commands in other namespaces.
+\end{example}
+
+However, the \sty{xkeyval} package can't be used to define and set toggle keys. The present package fills this gap, by providing facilities for defining and setting toggle keys. The work relies on some of the macros from the \sty{xkeyval} package.
+
+Secondly, the \sty{xkeyval} package can't be used to define and set complementary keys, which can be handy in the case of boolean and toggle keys. The present package introduces this concept and additionally permits the submission of individual/different custom key macros to complementary boolean and toggle keys.
+
+The third motivation for this package relates to economy of tokens in style files. The \sty{xkeyval} package provides \fx{\define@cmdkeys} and \fx{\define@boolkeys} for defining and setting multiple command keys and boolean keys, but in each category the keys must have the same default value and no key macro/function. This package seeks to lift these restrictions, so that multiple keys of all categories (ordinary keys, command keys, boolean keys, tog keys, and choice keys) can be defined in one go (using only one command) and those keys can have different default values and functions. This greatly minimizes tokens, as hundreds of keys can, in principle, be issued simultaneously by one command.
+
+Fourthly, macros are introduced for defining all key types without the fear of inadvertently redefining existing keys in the same family and with the same key prefix. This is similar to the \fx{\newcommand} concept in \LaTeX.
+
+The package also provides facilities for disabling, suspending, restoring and removing keys across multiple families of keys.
+
+The new macros can be used together with the machinery from the \sty{xkeyval} package for efficient and versatile key management.
+
+\section{Loading the \textcolor{\amd@stycolor}{skeyval} package}
+
+The package can be loaded in style and class files by
+\begin{example}
+\RequirePackage[options]{skeyval}
+\end{example}
+and in document files via
+\begin{example}
+\usepackage[options]{skeyval}
+\end{example}
+where the options and their default values are
+\begin{macrocode}
+keyparser=;, macroprefix=mp@, keyprefix=KV, keyfamily=fam,
+xchoicelist=false.
+\end{macrocode}
+The \fn{keyparser} is the separator between the keys in the key list to be defined in one go (see examples in \secref{sec:examples}). The \fn{macroprefix}, \fn{keyprefix}, and \fn{keyfamily} are, respectively, the macro prefix, key prefix and key family for all the keys to be defined upon the declaration of these options. All these options can be set or changed dynamically by using the \fx{\skvoptions} macro:
+\begin{macrocode}
+\skvoptions{keyparser=;, macroprefix=mp@, keyprefix=KV,
+ keyfamily=fam, xchoicelist=false}.
+\end{macrocode}
+
+If, as unlikely as it may seem, a clash arises between package and/or user macros as a result of the use of the defaults for \fn{macroprefix}, \fn{keyprefix} and \fn{keyfamily}, then the user will have to make his own choices for these defaults so as to avoid clashes.
+
+\section{Complementary boolean keys}
+\label{sec:comp-boolkeys}
+
+The syntax for creating complementary boolean keys is
+\begin{macrocode}
+\define@compboolkeys[|fv(keyprefix)]{|fv(family)}[|fv(macroprefix)]
+ {|fv(primary boolean)}[|fv(default value for primary boolean)]
+ {|fv(secondary boolean)}{|fv(func for primary boolean)}
+ {|fv(func for secondary boolean)}.
+\end{macrocode}
+This command is robust and can be used in expansion contexts, but expandable commands must be protected. When the user doesn't supply the \fn{keyprefix} and/or \fn{macroprefix}, the package will use \fn{KV} and \fn{mp@}, respectively. When one complementary boolean key (primary or secondary) is true, the other is automatically set false; and vice versa: when one complementary boolean key (primary or secondary) is false, the other is automatically set true. Infinite loops, which are possible in back-linked key settings, are avoided in the \sty{skeyval} package. The tools of the \sty{xkeyval} package, such as \fx{\setkeys}, \fx{\presetkeys}, \fx{\savekeys}, \fx{\savevalue}, \fx{\usevalue}, \etc, are all applicable to complementary boolean keys.
+
+As an example, we define below two complementary boolean keys \fn{draft} and \fn{final} with different key macros:
+\begin{example}
+\define@compboolkeys[KV]{fam}[mp@]{draft}[true]{final}%
+ {%
+ \def\gobble##1{}%
+ }{%
+ \def\notgobble##1{##1}%
+ }.
+\end{example}
+The key prefix (default \fn{KV}), macro prefix (default \fn{mp@}), and key macros (no default) can be empty:
+\begin{example}
+\define@compboolkeys{fam}{draft}[true]{final}{}{}.
+\end{example}
+
+The defined complementary keys \fn{draft} and \fn{final} can now be set as follows:
+\begin{example}
+\setkeys[KV]{fam}{draft=true}
+
+\setkeys[KV]{fam}{final=true}
+\end{example}
+The second statement above reverses the boolean \fn{draft} to \fn{false}, which had been set in the first statement to \fn{true}. There is no apparent meaning to the following:
+\begin{example}
+\setkeys[KV]{fam}{draft=true,final=true}.
+\end{example}
+
+Most applications of the \sty{xkeyval} package do indeed use key and macro prefixes; so it presumably makes sense here to assume that all uses of the present package will somehow involve key and macro prefixes.
+
+\section{Toggle switches and keys}
+\label{sec:toggles}
+
+\subsection{Toggle switches}
+\label{sec:toggle-switches}
+
+The following toggle switches are defined in the \sty{skeyval} package. They largely mimic those in the \sty{etoolbox} package, except for the commands \fx{\deftog} and \fx{\requiretog}. There is no fear that the commands in this package will interfere with those from the \sty{etoolbox} package, since the control sequence names used in the two packages are different.
+
+All the commands in this section are robust and can be used in expansion contexts.
+
+\begin{macrocode}
+\deftog{|fv(toggle)}
+\end{macrocode}
+This defines a new \fn{toggle} whether or not \fn{toggle} is already defined. If \fn{toggle} is already defined, a warning message is logged in the transcript file and the new definition is effected.
+
+\begin{macrocode}
+\newtog{|fv(toggle)}
+\end{macrocode}
+This defines a new \fn{toggle} if \fn{toggle} is not already defined; otherwise the package issues a fatal error.
+
+\begin{macrocode}
+\providetog{|fv(toggle)}
+\end{macrocode}
+This defines a new \fn{toggle} if \fn{toggle} is not already defined. If \fn{toggle} is already defined, the command does nothing.
+
+\begin{macrocode}
+\requiretog{|fv(toggle)}
+\end{macrocode}
+\fx{\requiretog} takes arguments like \fx{\newtog} and behaves like \fx{\providetog} with the difference: if the toggle is already defined, the command \fx{\requiretog} calls \LaTeX's \fx{\CheckCommand} to make sure that the new and existing definitions are identical, whereas \fx{\providetog} assumes that if the toggle is already defined, the existing definition should persist. \fx{\requiretog} assures that a toggle will have the given definition, but \fx{\requiretog} also warns the user if there was a previous and different existing definition. For example, if the toggle \fn{toga} is currently \fn{true}, then since all new toggles start out as \fn{false}, a call \fx{\requiretog{toga}} will issue a warning in the log file that the new and old definitions of \fn{toga} don't agree and the new definition, therefore, can't go ahead.
+
+The \sty{skeyval} package also provides the command \fx{\requirecmd}, which has the same logic as \fx{\requiretog} but can be used for general \latex commands, including those with optional arguments (see \secref{sec:misce-commands}).
+
+\begin{macrocode}
+\settog{|fv(toggle)}{|fv(true |amdvert false)}
+\end{macrocode}
+This command sets \fn{toggle} to \fn{value}, where \fn{value} may be either \fn{true} or \fn{false}. This statement will issue an error if \fn{toggle} wasn't previously defined.
+
+\begin{macrocode}
+\togtrue{|fv(toggle)}
+\end{macrocode}
+This sets \fn{toggle} to \fn{true}. It will issue an error if \fn{toggle} wasn't previously defined.
+
+\begin{macrocode}
+\togfalse{|fv(toggle)}
+\end{macrocode}
+This sets \fn{toggle} to \fn{false}. It will issue an error if \fn{toggle} wasn't previously defined.
+
+\begin{macrocode}
+\iftog{|fv(toggle)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+This yields the \fn{true} statement if the boolean \fn{toggle} is currently \fn{true}, and \fn{false} otherwise. It will issue an error if \fn{toggle} wasn't previously defined.
+
+\begin{macrocode}
+\ifnottog{|fv(toggle)}{|fv(not true)}{|fv(not false)}
+\end{macrocode}
+This behaves like \fx{\iftog} but the logic of the test is reversed. It will issue an error if \fn{toggle} wasn't previously defined.
+
+\subsection{Toggle keys}
+\label{sec:toggle-keys}
+
+The syntax for defining toggle keys is exactly like those for boolean keys in the \sty{xkeyval} package. This allows all the machinery of the \sty{xkeyval} package (including \fx{\setkeys}, \fx{\presetkeys}, \fx{\savekeys}, \fx{\savevalue}, \fx{\usevalue}, etc) to be applicable to toggle keys.
+
+As mentioned earlier, toggles have their own separate namespace. However, the \fx{\setkeys} command (and friends) of the \sty{xkeyval} package is unaware of this. This can cause problems when the user uses the same name for boolean and toggle keys (or indeed any key type) in the same family and with the same key prefix, believing rightly that toggle keys have their own separate namespace. If this is a source of significant concern to any user, he will be well advised to instead use the commands \fx{\newboolkey}, \fx{\newboolkeys}, \fx{\newtogkey}, \fx{\newtogkeys}, \etc, of \secref{sec:redef-keys}. In those commands a mechanism is included to bar keys from having the same name as other keys in the same family and with the same prefix. Toggle keys can still share the same names with keys across families and key prefixes. Since it is not always certain which of the keys the user may want to first define (before its definition is possibly repeated), the fear of interference has necessitated new syntaxes for defining all key types, which completely avoid interference (see \secref{sec:redef-keys}).
+
+The user interfaces for defining toggle keys are
+
+\begin{macrocode}
+\define@togkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(function)}
+
+\define@togkey|redplus[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(function1)}{|fv(function2)}
+\end{macrocode}
+
+If the macro prefix \fn{mp} is not specified, these create a toggle of the form \fnn{prefix}{family}{key}{} using \fx{\deftog} (which initializes the toggle switch to \fn{false}) and a key macro of the form \bs\fnn{prefix}{family}{key}{} which first checks the validity of the user input. If the value is valid, it uses it to set the toggle and then executes \fn{function}. If the user input wasn't valid (\ie, neither \fx{true} nor \fx{false}), then the toggle will not be set and the package will generate a fatal error to this effect.
+
+If \fn{mp} is specified, then the key definition process will create a toggle of the form \fnm{mp}{key}{}{} and a key macro of the form \bs\fnm{mp}{key}{}{}. The value \fn{default} will be used by the key macro when the user sets the key without a value.
+
+If the plus (\redplus) version of the macro is used, the user can specify two key macros \fn{function1} and \fn{function2}. If user input is valid, the macro will set the toggle and executes \fn{function1}; otherwise, it will not set the boolean but will execute \fn{function2}.
+
+As an example, consider the following (adapted from the \sty{xkeyval} package to suit toggle keys):
+\begin{example}
+\define@togkey{fam}[my@]{frame}{%
+ \iftog{my@frame}{%
+ \PackageInfo{mypack}{Turning frames on}%
+ }{%
+ \PackageInfo{mypack}{Turning frames off}%
+ }%
+}
+
+\define@togkey|redplus{fam}{shadow}{%
+ \iftog{KV@fam@shadow}{%
+ \PackageInfo{mypack}{Turning shadows on}%
+ }{%
+ \PackageInfo{mypack}{Turning shadows off}%
+ }%
+}{%
+ \PackageWarning{mypack}{Erroneous input `#1' ignored}%
+}
+\end{example}
+
+The first example creates the toggle \fn{my@frame} and defines the key macro
+\fx{\KV@fam@frame} to set the boolean (if the input is valid). The second key intimates
+the user of changed settings, or produces a warning when input was incorrect.
+
+It is also possible to define multiple toggle keys with a single command:
+\begin{macrocode}
+\define@togkeys[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(keys)}[|fv(default)]
+\end{macrocode}
+This creates a toggle key for every entry in the comma-separated list \fn{keys}. As is the case with the commands \fx{\define@cmdkeys} and \fx{\define@boolkeys} from the \sty{xkeyval} package, the individual keys in this case can't have a custom function. See section~\ref{sec:multiplekeys} for how to define multiple keys with custom functions.
+
+As an example of defining multiple toggle keys, consider
+\begin{example}
+\define@togkeys{fam}[my@]{toga,togb,togc}
+\end{example}
+
+This is an abbreviation for
+\begin{example}
+\define@togkey{fam}[my@]{toga}{}
+\define@togkey{fam}[my@]{togb}{}
+\define@togkey{fam}[my@]{togc}{}
+\end{example}
+
+Now we can do
+\begin{example}
+\define@togkey{fam}[my@]{book}{%
+ \iftog{my@book}{\setkeys[KV]{fam}{togc=true}}{}%
+}
+\setkeys[KV]{fam}{book=true}
+\end{example}
+Toggle keys can be set in the same way that other key types are set.
+
+The status of toggles can be examined by doing
+\begin{example}
+\show\SKV@toggle@|fv(mp)|fv(key)
+\end{example}
+when the \fn{mp} is present. When the user has specified no \fn{mp} in defining the key, he has to issue
+\begin{example}
+\show\SKV@toggle@|fv(prefix)@|fv(family)@|fv(key).
+\end{example}
+
+\section{Complementary toggle keys}
+
+Similar to complementary boolean keys of \secref{sec:comp-boolkeys}, the \sty{skeyval} package introduces a facility for creating complementary toggle keys. The syntax for this is similar to that for defining complementary toggle keys:
+\begin{macrocode}
+\define@comptogkeys[|fv(keyprefix)]{|fv(family)}[|fv(macroprefix)]
+ {|fv(primary toggle)}[|fv(default value for primary toggle)]
+ {|fv(secondary toggle)}{|fv(func for primary toggle)}
+ {|fv(func for secondary toggle)}.
+\end{macrocode}
+This command is robust and can be used in expansion contexts, but non-robust commands have to be protected. When the user doesn't supply the \fn{keyprefix} and/or \fn{macroprefix}, the package will use \fn{KV} and \fn{mp@}, respectively. When one toggle key (primary or secondary) is true, the other is automatically set false; and vice versa: when one toggle key (primary or secondary) is false, the other is automatically set true.
+
+As an example, we define below two complementary toggle keys \fn{xdraft} and \fn{xfinal} with different key macros:
+\begin{example}
+\define@comptogkeys[KV]{fam}[mp@]{xdraft}[true]{xfinal}%
+ {%
+ \def\gobble##1{}%
+ }{%
+ \def\notgobble##1{##1}%
+ }.
+\end{example}
+The key prefix (whose default is \fn{KV}), macro prefix (whose default is \fn{mp@}), and key macros (no default) can be empty:
+\begin{example}
+\define@comptogkeys{fam}{xdraft}[true]{xfinal}{}{}.
+\end{example}
+
+The defined complementary toggle keys \fn{xdraft} and \fn{xfinal} can now be set as follows:
+\begin{example}
+\setkeys[KV]{fam}{xdraft=true}
+
+\setkeys[KV]{fam}{xfinal=true}
+\end{example}
+The second statement above reverses the toggle \fn{xdraft} to \fn{false}, which had been set in the first statement to \fn{true}.
+
+Toggle keys may easily be confused with the conventional boolean keys, at the time of definition and setting. It is therefore always safer to use the syntaxes in \secref{sec:redef-keys} for defining keys; they avoid interference between new and existing keys.
+
+\paragraph{Note} If we were to use the key names \fx{draft} and \fx{final} as toggle keys above, instead of \fx{xdraft} and \fx{xfinal}, there would have been a clash with the keys \fx{draft} and \fx{final} defined as (complementary) boolean keys in \secref{sec:comp-boolkeys}---because they share the same family \fn{fam} and prefix \fn{KV}. The names \fx{draft} and \fx{final} can be used as toggles only if the family \fn{fam} or prefix \fn{KV} is changed.
+
+\section[Defining multiple keys by one command]%
+ {Defining multiple keys of all genres by one command}
+\label{sec:multiplekeys}
+
+The interface for defining multiple keys of all kinds in one go is the command \fx{\define@keylist}, whose syntax is
+\begin{macrocode}
+\define@keylist{|fv(key type/id), |fv(key), |fv(key default value),
+ |fv(key macro/function); |fv(another set of key specifiers); etc}
+\end{macrocode}
+
+There are five key types: 1 (ordinary key), 2 (command key), 3 (boolean key),
+4 (toggle key), and 5 (choice key). The key and its attributes are separated by commas; they constitute one \fx{object}. The objects are separated by the \fn{keyparser}, which is the semicolon in the above example.
+
+If the key list is available in a macro, say,
+\begin{example}
+\def\keylist{|fv(key type/id), |fv(key), |fv(key default value),
+ |fv(key macro/function); |fv(another set of key specifiers); etc},
+\end{example}
+then the keys can be defined by the starred form of \fx{\define@keylist}:
+\begin{example}
+\define@keylist|redstar\keylist.
+\end{example}
+\fx{\define@keylist}\redstarr takes a macro as argument, while \fx{\define@keylist} accepts a key list.
+
+The \fx{\define@keylist} macro uses the following commands in the background:
+\begin{example}
+\define@key, \define@cmdkey, \define@boolkey,
+\define@choicekey, \define@togkey.
+\end{example}
+Therefore, it assumes that it is safe to redefine a previously defined key. If this assumption is unwarranted, then the user should consider using the machinery of \secref{sec:redef-keys}\footnote{In fact, I now often use the machinery of \secref{sec:redef-keys} to safely define new keys without the fear of inadvertently redefining an existing key within the same family and with the same key prefix.}.
+
+\subsection{Choice key values}
+
+The \fx{\ChoiceKeyValues} macro is needed for choice keys; it lists the alternate
+admissible values for a choice key and thus can't be empty when a choice key
+is being defined. Its syntax is
+\begin{macrocode}
+\ChoiceKeyValues{|fv(key)}{|fv(list)},
+\end{macrocode}
+where \fn{list} is a comma-separated list of admissible key values.
+To further save tokens, the macro \fx{\ChoiceKeyValues} may be abbreviated by \fx{\CKVS}. It has to be defined each time a choice key is being defined. For example, if we want to define two choice keys \fx{align} and \fx{election}, then before the call to \fx{\define@keylist}, we have to set
+\begin{example}
+\CKVS{align}{center,right,left,justified}
+\CKVS{election}{state,federal,congress,senate}.
+\end{example}
+It doesn't matter which choice key first gets a \fx{\CKVS}. The prevailing key prefix and key family are used internally by \fx{\ChoiceKeyValues} to build distinct alternate values lists for choice keys.Unless the key family changes, you can't set two \fx{\ChoiceKeyValues} for the same choice key. This will be possible only if the package option \fx{xchoicelist} (meaning ``allow overwriting of choice list'') has been set \fn{true}, either through \fx{\documentclass}, \fx{\usepackage}, or \fx{\skvoptions}. Therefore, any number of choice keys are allowed to appear in one \fx{\define@keylist} or \fx{\define@keylist}\redstarr statement if their lists of alternate/admissible values have been set by \fx{\CKVS}.
+
+As mentioned earlier, the key family and other package options can be changed dynamically via
+\begin{example}
+\skvoptions{keyparser=value,macroprefix=value,keyprefix=value,
+ keyfamily=value,xchoicelist=value}.
+\end{example}
+
+In line with the philosophy of the \sty{xkeyval} package, all the choice keys to be defined using the \sty{skeyval} package require \fx{\ChoiceKeyValues}: choice keys, by definition, have pre-ordained or acceptable values.
+
+\subsection{Some internals}
+
+The internal equivalent of \fx{\ChoiceKeyValues} (the choice key list of alternative values) is the macro \bs\fnn{keyprefix}{keyfamily}{key}{altlist}. For example, for a key \fx{align} in the family \fx{fam}, and with prefix \fx{KV}, the internal of \fx{\CKVS} is \fx{\KV@fam@align@altlist}.
+
+For all keys in a family, the internal of the key macro (provided at key definition time) can be accessed via the macros
+\begin{macrocode}
+\|fv(keyprefix)@|fv(keyfamily)@|fv(key)@|fv(func).
+\end{macrocode}
+These internals are available for only the keys defined via \fx{\define@keylist} or \fx{\newkeylist}!
+
+It should be noted that the \sty{xkeyval} package will save and provide a key value when the value is saved (using the pointers \fx{\savevalue} or \fx{\gsavevalue}) at the time the key is set, or when the key is included in the \fx{\savekeys} (or \fx{\gsavekeys}) list. In that case, the saved value will be available in
+\begin{example}
+\XKV@|fv(keyprefix)@|fv(keyfamily)@|fv(key)@|fv(value),
+\end{example}
+where the prefix \fx{XKV@} is usually added. The saved value can also be accessed via \fx{\usevalue}\unskip\sv{key} but only within \fx{\setkeys} command. Since the \sty{skeyval} package uses the machinery of the \sty{\xkeyval} in the background, all these pointers can still be utilized for the keys defined via all the new key definition mechanisms introduced by the \sty{skeyval} package (\eg, the commands \fx{\define@togkey}, \fx{\define@keylist}, \fx{\newkeylist}, \etc).
+
+The macro \bs\fnn{keyprefix}{keyfamily}{key}{func} is undefined if \fn{key} has not been defined or if it has been removed; and the macro
+\begin{example}
+\XKV@|fv(keyprefix)@|fv(keyfamily)@|fv(key)@|fv(value)
+\end{example}
+is undefined whenever \fn{key} has no value specified, or has not been set. So it is advisable to always test for the existence of these macros before they are used.
+
+\subsection{Some examples}
+\label{sec:examples}
+
+In this section we provide a glimpse of the potential applications of the tools provided by the \sty{skeyval} package in the context of defining multiple keys by one command.
+
+Suppose that the key family and other attributes have been set as
+\begin{example}
+\skvoptions{keyparser=;,macroprefix=mp@,keyprefix=KV,
+ keyfamily=fam,xchoicelist=false}.
+\end{example}
+Further, suppose we wish to define a set of keys \fn{color,angle,scale,align}. The keys \fx{color}, \fx{angle} and \fx{scale} will de defined as command keys, while the key \fx{align} will be defined as a choice key. Assume that the \fx{align} key can only assume one of the values $\langle$\unskip\fx{center} \amdvert\ \fx{right} \amdvert\ \fx{left} \amdvert\ \fx{justified}\unskip$\rangle$, where the first three values would further imply \fx{\centering}, \fx{\flushright}, and \fx{\flushleft}, respectively. Moreover, we assume that the key \fx{scale} will be associated with a macro called \fx{\mydo}, which depends on a previously defined macro \fx{\do}. Together with \fx{align}, we would also like to define another choice key: \fx{weather}. The keys \fx{color} and \fx{angle} aren't associated with macros. Then we can do:
+\begin{example}
+\CKVS{align}{center,right,left,justified}
+\CKVS{weather}{sunny,cloudy,lightrain,heavyrain,snow,
+ sleet,windy,\someweather}
+ % |color(gray) We assume that \someweather is defined
+ % |color(gray) somewhere and holds an admissible value
+ % |color(gray) for the key ``weather'' at any level.|color(verbcolor)
+\def\f@align{%
+ \ifcase\nr\relax
+ \def\mp@align{\centering}%
+ \or
+ \def\mp@align{\flushright}%
+ \or
+ \def\mp@align{\flushleft}%
+ \or
+ \let\mp@align\relax
+ \fi
+}
+
+\define@keylist{2,color,gray!25,;2,angle,45,;
+ 2,scale,1,\def\mydo##1{\do ##1};5,align,center,\f@align;
+ |color(red)\stopread|color(verbcolor);3,mybool,true,;
+ 5,weather,sunny,\protected@edef\VWeather{\val}}.
+\end{example}
+The \fx{\nr} and \fx{\val} macros are bin parameters for choice keys, as defined by the \sty{xkeyval} package. \fx{\val} contains the user input for the current key and \fx{\nr} contains the numeral corresponding to the user input in the \fx{\CKVS} list, starting from 0 (zero). For example, in the \fx{\CKVS{align}} list, the \fx{\nr} values are \fx{center}~(0), \fx{right}~(1), \fx{left}~(2), and \fx{justified}~(3). These parameters thus refresh with the choice key and its user-supplied value.
+
+Instead of defining the macro \fx{\f@align} before hand, we can submit its replacement text directly to the macro \fx{\define@keylist}, but, because \fx{\f@align} contains a conditional, some care is needed in doing so (see section~\ref{sec:conditionals}). Once the key \fx{align} has been defined, the macro \fx{\f@align} can be reused---perhaps to define other keys---even before the key \fx{align} is set. This is because it isn't \fx{\f@align} that is used in defining the key \fx{align} but its internal counterpart (\ie, a prefix and family-dependent internal of \fx{\f@align}, which is \fx{\KV@fam@align@func}). In this way, the user can economize on tokens. The same applies to all the macros that may be used in defining keys via \fx{\define@keylist}.
+
+Note the \fx{\stopread} command inserted above. Because of it, the key \fx{mybool} will not be read and defined; the rest (\ie, \fx{color}, \fx{angle}, \fx{scale} and \fx{align}) will be read and defined. All the entries for \fx{mybool} and \fx{weather} will instead be saved in the macro \fx{\SKV@remainder}, possibly for some other uses.
+
+Hundreds of keys can be defined efficiently in this way, using very few tokens.
+
+As another example, we consider the following keys:
+\begin{example}
+\CKVS{align}{center,right,left,justified}
+\CKVS{election}{state,federal,congress,senate}
+% |color(gray)\CKVS needs to be defined only once for each key in a family.|normalcolor
+
+\define@keylist{%
+ 3,boolvar,true,;1,paperheight,\paperheight,;
+ 1,paperwidth,\paperwidth,\f@paperwidth;
+ 2,textheight,\textheight,\f@textheight;
+ 2,textwidth,\textwidth,\f@textwidth;
+ 1,evensidemargin,\evensidemargin,;
+ 5,align,center,\f@align;
+ 5,election,congress,;
+ 2,testdim,2cm,\long\def\f@testdim##1{A test dimension ##1
+ \par\bigskip}%
+ % |color(gray) Note the number of parameter characters
+ % |color(gray) in the definition of \f@testdim.
+}
+\end{example}
+which have the following trivial key macros:
+\begin{example}
+\def\f@textwidth{\AtBeginDocument{\wlog{`textwidth' %
+ is \mp@textwidth}}}
+
+\def\f@textheight{%
+ \ifx\@empty\mp@textheight
+ \wlog{`textheight' value empty}%
+ \else
+ \wlog{`textheight' value not empty}%
+ \fi
+}
+
+\def\f@paperwidth{\wlog{`paperwidth' was defined as %
+ ordinary key.}}
+\newcommand\f@align{%
+ \ifcase\nr\relax
+ \def\mp@align{\centering}%
+ \or
+ \def\mp@align{\flushright}%
+ \or
+ \def\mp@align{\flushleft}%
+ \or
+ \let\mp@align\relax
+ \fi
+}
+\end{example}
+Again, once the keys have been defined, these macros can be reused.
+
+The same set of keys can be defined via the starred form of \fx{\define@keylist}:
+\begin{example}
+\def\keylist{%
+ 3,boolvar,true,;1,paperheight,\paperheight,;
+ 1,paperwidth,\paperwidth,\f@paperwidth;
+ 2,textheight,\textheight,\f@textheight;
+ 2,textwidth,\textwidth,\f@textwidth;
+ 1,evensidemargin,\evensidemargin,;
+ 4,mytoggle,true,\let\settoggle\settog;
+ 5,align,center,\f@align;
+ 5,election,congress,;
+ 2,testdim,2cm,\long\def\f@testdim##1%
+ {Do something with ##1}%
+}
+\define@keylist|redstar\keylist.
+\end{example}
+
+Since the keys have been defined, they can now be set. In the following, we set only two of the keys:
+\begin{example}
+\setkeys[KV]{fam}{align=right,testdim=3cm}
+\end{example}
+
+The macro \fx{\mp@align} holds the value \fx{\flushright}, while
+\begin{example}
+\KV@fam@testdim
+\end{example}
+holds the macros:
+\begin{example}
+\def\mp@testdim{#1}
+\long\def\f@testdim##1{A test dimension##1\par\bigskip},
+\end{example}
+where \WithHash{1} is the value submitted for the key \fx{testdim}.
+Try \fx{\show\mp@align}, \fx{\show\KV@fam@testdim}, and \fx{\show\f@testdim} to confirm the above assertions.
+
+The rest of the defined keys can now be set as follows:
+\begin{example}
+\setkeys[KV]{fam}{boolvar=true,paperheight,paperwidth,
+ textheight,textwidth=6cm}
+\end{example}
+Try \fx{\show\ifmp@boolvar} to confirm that \fx{boolvar} is now \fn{true}; it was originally set as \fn{false}. The macro \fx{\KV@fam@paperwidth} holds the function \fx{\f@paperwidth}; \fx{\mp@textheight} holds the value submitted to key \fx{textheight} at any instance of \fx{\setkeys}. By the above \fx{\setkeys}, only the default values of \fx{paperheight}, \fx{paperwidth}, and \fx{textheight} are presently available.
+
+Instead of using macros to pass key macros and functions, it is also possible to use token registers. An example is provided below:
+\begin{example}
+\toks0={\long\def\f@testdim#1{A test dimension #1\par\bigskip}}
+\define@keylist{3,boolvar,true,;2,testdim,2cm,\the\toks0}.
+\end{example}
+The advantage of using token registers is that the parameter characters need not be doubled in the token registers, unlike when using macros. The token register \fx{\toks0} can be reused as soon as the key \fx{testdim} is defined. See \secref{sec:condit-in-macros} for more information on using macros and token registers to pass key functions.
+
+\section{Input error}
+
+Boolean, toggle and choice keys issue error messages if the key value is not valid, \ie, not in the list of admissible values. The admissible values of boolean and toggle keys are \fn{true} and \fn{false}. The valid values of choice keys are set by the user via \fx{\VKVS}. The default input error is defined by \fx{\SKV@inputerr} macro to be
+\begin{macrocode}
+\SKV@err{Erroneous value `#1' for key `#2'}{%
+ Please use the correct value for key `#2'.}.
+\end{macrocode}
+\fx{\SKV@inputerr} can be redefined by the user. It takes two arguments (\ie, value and key).
+
+\section{Conditionals in key macros}
+\label{sec:conditionals}
+
+The \tex conditional primitives \fx{\if} and \fx{\fi} cannot appear in the key macro when \fx{\define@keylist} is being invoked. The reason can be traced to the discussion on page~211 of the \TeX Book and the loop used in the \sty{skeyval} package to define keys. There are three approaches to resolving this problem, and the user can choose anyone he/she prefers.
+
+\subsection[Using macros or token registers]%
+ {Burying conditionals in macros or token registers}
+\label{sec:condit-in-macros}
+
+Key macros/functions involving conditional operations such as
+\begin{example}
+\ifmp@bool \do \fi
+\end{example}
+can be submitted to \fx{\define@keylist} via macros, as seen above. We give more examples below.
+
+Suppose we want to submit the following:
+\begin{example}
+\define@keylist{3,bool,true,\ifmp@bool \do \fi}.
+\end{example}
+The presence of \fx{\if} and \fx{\fi} in the argument will trigger an error when \tex is scanning or skipping tokens, and, secondly, because of the loop and conditional used by the \sty{skeyval} package in defining keys. Neither \fx{\protect} nor \fx{\noexpand} is helpful here. One solution is to first define
+\begin{example}
+\def\f@bool{\ifmp@bool \do \fi}
+\end{example}
+and then do
+\begin{example}
+\define@keylist{3,bool,true,\f@bool},
+\end{example}
+which will execute \fx{\f@bool} when the key \fx{bool} is set. Once the key \fx{bool} has been defined by the above statement, the function \fx{\f@bool} may be redefined and reused many times, any time, even before the setting of the key \fx{bool}. It isn't the function \fx{\f@bool} that is used in defining the key \fx{bool}, but an internal or meaning of \fx{\f@bool}, depending on the contents of \fx{\f@bool}.
+
+As another example, we may do
+\begin{example}
+\def\f@abool{\ifmp@abool\def\do####1{%
+ \def####1########1{\expandafter\expandafter\expandafter\in@
+ \expandafter\expandafter\expandafter{\expandafter####1
+ \expandafter}\expandafter{########1}}}\fi}
+
+\define@keylist{3,abool,true,\f@abool}.
+\end{example}
+
+Token registers (including scratch token registers) can be used here economically instead of macros:
+\begin{example}
+\toks0{\ifmp@abool\def\do#1{%
+ \def#1##1{\expandafter\expandafter\expandafter\in@
+ \expandafter\expandafter\expandafter{\expandafter#1
+ \expandafter}\expandafter{##1}}}\fi}
+
+\toks1{\iftog{toggleone}{def\tempa#1{Use #1}}{}}
+
+\define@keylist{3,abool,true,\the\toks0;
+ 4,toggleone,true,\the\toks1}
+
+\setkeys[KV]{fam}{abool=true,toggleone=true}.
+\end{example}
+You can see the significant reduction in the number of parameter characters when using token registers. The token registers \fx{\toks0} and \fx{\toks1} can be reused to define many other keys as soon as the keys \fn{abool} and \fn{toggleone} have been defined, even before they are set.
+
+\subsection{Using a trick to submit the conditionals}
+\label{sec:dirty-trick}
+
+There are two downsides to the above approach of hiding conditionals in macros:
+\begin{enumerate}
+\item The macros have to be defined and, although they can be redefined and reused, they tend to defeat the initial aim of the package, which is to economize on tokens.
+\item If the conditionals involve macro definitions as in the above example, the parameter characters have to be doubled in each instance, except when using token registers.
+\end{enumerate}
+
+Suppose we want to define a boolean key \fx{mybool} with the following key macro:
+\begin{example}
+\ifmp@mybool\def\hold##1{\def##1####1{####1}}\fi,
+\end{example}
+where the macro prefix is \fx{mp@} and the key family has been defined previously. Then, instead of hiding the conditional in a macro, we can go
+\begin{example}
+\define@keylist{3,mybool,true,
+ \fif{mp@mybool}\def\hold##1{\def##1####1{####1}}\ffi}.
+\end{example}
+Here we have used \fx{\fif{mp@mybool}} and \fx{\ffi} for \fx{\ifmp@mybool} and \fx{\fi}, respectively, to hide the latter two from \TeX's scanning and skipping mechanism. Please note that \fx{\fif{mp@mybool}} requires that the argument \fn{mp@mybool} be enclosed in braces. Something like \fx{\fifmp@mybool} will be interpreted by \tex as undefined control sequence when the key \fx{mybool} is being set.
+
+We have redefined the \fx{\setkeys} of the \sty{xkeyval} package to understand that \fx{\fif} and \fx{\ffi} stand for \fx{\if} and \fx{\fi}, respectively. The redefined \fx{\setkeys} command has the same syntax as as in \sty{xkeyval} package:
+\begin{macrocode}
+\setkeys[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)}
+\setkeys|redstar[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)}
+\setkeys|redplus[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)}
+\setkeys|redstar|redplus[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)}.
+\end{macrocode}
+The reader who is unfamiliar with the meaning of star and plus signs in the \fx{\setkeys} command should consult the documentation for the \sty{xkeyval} package. No errors are produced if any of the sets \fn{prefix}, \fn{families}, \fn{na}, and \fn{keys=values} is empty. In fact, an instruction such as \fx{\setkeys[]{}[]{}} is completely benign, and so is \fx{\setkeys{}{}}.
+
+In the case of conditionals starting with \fx{\ifcase}, a \fx{\noexpand} before the \fx{\ifcase} solves the problem:
+\begin{example}
+\CKVS{focus}{center,left,right,justified}
+
+\define@keylist{5,focus,center,|color(red)\noexpand|color(verbcolor)\ifcase\nr\relax
+ \def\mp@focus{\centering}\or\def\mp@focus{\flushright}
+ \or\def\mp@focus{\flushleft}\or\let\mp@focus\relax\fi
+}
+\end{example}
+However, such conditionals may also be buried in macros or token registers.
+
+\subsection{Using toggles}
+
+Toggle switches, described in \secref{sec:toggles}, can also be used to circumvent the problem of matching \fx{\if} and \fx{\fi} in difficult circumstances, since toggles aren't \TeX\ primitives. For example, the following works:
+\begin{example}
+\define@keylist{4,toggleone,true,
+ \iftog{toggleone}{\def\temp{This is defined by a toggle}}{}}.
+\end{example}
+And, as noted in \secref{sec:toggles}, toggles are very economical.
+
+\section{Checking and redefining keys}
+\label{sec:redef-keys}
+
+\subsection{Checking the status of a key}
+
+Three mechanism have been introduced in the \sty{skeyval} package to ascertain the statuses of keys. These are as follows.
+
+\begin{macrocode}
+\ifkeydefined[|fv(prefixes)]{|fv(families)}{|fv(key)}{|fv(true)}{|fv(false)}.
+\end{macrocode}
+This executes \fn{true} if \fn{key} is defined, reserved, or suspended with a prefix in \fn{prefixes} and family in \fn{families}; it returns \fn{false} otherwise. This is similar to
+the \sty{xkeyval} package's \fx{\key@ifundefined}, but, apart from reversing the logic of the test, \fx{\ifkeydefined} loops over prefixes (in addition to looping over families) to locate the key, and also considers reserved and suspended keys as defined. The lists \fn{prefixes} and \fn{families} may contain nil, one or more elements.
+
+\begin{macrocode}
+\ifkeyreserved[|fv(prefixes)]{|fv(families)}{|fv(key)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+This returns \fn{true} if \fn{key} is reserved with a prefix in \fn{prefixes} and family in \fn{families}; it returns \fn{false} otherwise. Reserved keys are introduced in \secref{sec:reserve-keys}.
+
+\begin{macrocode}
+\ifkeysuspended[|fv(prefixes)]{|fv(families)}{|fv(key)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+This executes \fn{true} if \fn{key} is suspended with a prefix in \fn{prefixes} and family in \fn{families}; it executes \fn{false} otherwise. Suspended keys are introduced in \secref{sec:suspend-keys}.
+
+\subsection[Redefining keys]{Unintentional redefinition of keys}
+
+The \sty{xkeyval} package, by default, permits the automatic redefining of keys of the same \fn{prefix} and \fn{family}: at the point of defining a new key, the package doesn't, by default, check whether or not the key had been previously defined with the same \fn{prefix} and \fn{family}. In some circumstances this can be undesirable, and even dangerous, especially if the same key (of the same \fn{prefix} and \fn{family}) is mistakenly redefined with different macros/functions in the same package or across packages. One way to solve this problem is to use \sty{xkeyval} package's \fx{\key@ifundefined} command (or the \sty{skeyval} package's \fx{\ifkeydefined}) to confirm the status of a key prior to its definition. However, using this command before defining every key can be laborious.
+
+Consider the following two scenarios:
+\begin{example}
+\define@key[KV]{fam}{keya}[$\star$]{\def\tempa##1{##1}}
+\define@boolkey[KV]{fam}{keya}[true]{%
+ \ifKV@fam@keya\def\tempb{#1}\fi}
+
+\setkeys[KV]{fam}{keya=$\textbullet$}
+\end{example}
+Obviously the two definitions of \fn{keya} are valid and will be implemented but the \fx{\setkeys} command will issue an unintelligible error message, like \LaTeX's ``You are in trouble here \textellipsis''. The key \fn{keya} has been defined twice and \fx{\setkeys} has sought to use its latest definition to set its value, which is incorrect. As mentioned in \secref{sec:toggle-keys}, the \fx{\setkeys} command (and friends) of the \sty{xkeyval} package doesn't know if a key has been redefined in the same \fn{family} and with the same \fn{prefix}. At the high level, it doesn't consider the key type: it uses the latest definition of the key to set its value using the key's macro. This is particularly worrisome in the case of toggle keys, since although toggle keys have their own separate namespace, they can easily be confusing (at least to \fx{\setkeys}) if they have names identical to other keys within the same family and with the same prefix.
+
+\subsubsection{Avoiding multiple definitions of same key}
+
+For the above reasons, the \sty{skeyval} package introduces the following commands, which have the same syntaxes as their counterparts from the \sty{xkeyval} and \sty{skeyval} packages but which bar the user from repeated definition of keys with identical names within the same \fn{family} and with the same \fn{prefix}:
+\begin{macrocode}
+% |color(brown) The following defines ``ordinary'' keys [the counterpart
+% |color(brown) of \define@key from the xkeyval package]:|color(verbcolor)
+\newordkey[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(default)]{|fv(funtion)}
+
+% |color(brown) Counterpart of \define@cmdkey:|color(verbcolor)
+\newcmdkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(funtion)}
+
+% |color(brown) Counterpart of \define@cmdkeys:|color(verbcolor)
+\newcmdkeys[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(keys)}[|fv(default)]
+
+% |color(brown) Counterparts of \define@boolkey:|color(verbcolor)
+\newboolkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(funtion)}
+\newboolkey|redplus[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(funtion1)}{|fv(funtion2)}
+
+% |color(brown) Counterpart of \define@compboolkeys:|color(verbcolor)
+\newcompboolkeys[|fv(prefix)]{|fv(family)}[|fv(mp)]
+ {|fv(primary boolean)}[|fv(default value for primary boolean)]
+ {|fv(secondary boolean)}{|fv(func for primary boolean)}
+ {|fv(func for secondary boolean)}
+
+% |color(brown) Counterparts of \define@togkey:|color(verbcolor)
+\newtogkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(funtion)}
+\newtogkey|redplus[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]%
+ {|fv(funtion1)}{|fv(funtion2)}
+
+% |color(brown) Counterpart of \define@comptogkeys:|color(verbcolor)
+\newcomptogkeys[|fv(prefix)]{|fv(family)}[|fv(mp)]
+ {|fv(primary toggle)}[|fv(default value for primary toggle)]
+ {|fv(secondary toggle)}{|fv(func for primary toggle)}
+ {|fv(func for secondary toggle)}
+
+% |color(brown) Counterparts of \define@choicekey:|color(verbcolor)
+\newchoicekey[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}%
+ [|fv(default)]{|fv(funtion)}
+\newchoicekey|redstar[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}%
+ [|fv(default)]{|fv(funtion)}
+\newchoicekey|redplus[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}%
+ [|fv(default)]{|fv(funtion1)}{|fv(funtion2)}
+\newchoicekey|redstar|redplus[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}%
+ [|fv(default)]{|fv(funtion1)}{|fv(funtion2)}
+
+% |color(brown) Counterpart of \define@keylist:|color(verbcolor)
+\newkeylist{|fv(key type/id), |fv(key), |fv(key default value),
+ |fv(key macro/function); |fv(another set of key specifiers); etc}.
+\end{macrocode}
+
+We could simply have redefined/modified the legacy key definition commands in the \sty{xkeyval} package to make it impossible to define keys of the same name in the same family and with the same prefix, but this approach would be unsafe since there are many packages using the \sty{xkeyval} package and those packages may well have redefined identical keys. Moreover, the legacy key definition commands from the \sty{xkeyval} package may be needed to redefine a disabled key (see \secref{sec:disabling-keys}).
+
+All the commands of the type \fx{\new}\unskip xxx\fx{key} are robust and may be used in expansion contexts without fear of premature expansion, although expandable tokens in the definition must be protected.\footnote{We shall refer to keys of the type \fx{\new}\unskip xxx\fx{key} as those of category \fy{\newkey}, and keys of the type \fx{\define@}\unskip xxx\fx{key} as those of category \fy{\definekey}.}
+
+With the above macros, the following will flag an understandable error message, namely that the key \fn{keya} is about being redefined in the same family \fn{fam} and with the same prefix \fn{KV}:
+\begin{example}
+\newordkey[KV]{fam}{keya}[$\star$]{\def\tempa##1{##1}}
+\newboolkey[KV]{fam}{keya}[true]{%
+ \ifKV@fam@keya\def\tempb{#1}\fi}
+\end{example}
+
+\section[Disabling, reserving, suspending keys, etc.]%
+ {Disabling, reserving, suspending, restoring, and removing keys}
+\label{sec:disabling-keys}
+
+Besides macros for defining keys, the \sty{skeyval} package also introduces mechanisms for disabling, reserving, suspending, restoring, and completely removing existing keys.
+
+\subsection{Disabling keys}
+
+The \sty{skeyval} package has modified the definition of \fx{\disable@keys} from the \sty{xkeyval} package to allow for looping over key prefixes and key families and for bespoke warnings and error messages, without engendering any potential conflict with the legacy \fx{\disable@keys}. The new command is still called \fx{\disable@keys} and has the same syntax as the native \fx{\disable@keys} of the \sty{xkeyval}package, except that the new command accepts key prefixes (instead of just one prefix) and key families (instead of just one family):
+\begin{macrocode}
+\disable@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}.
+\end{macrocode}
+Here \fn{prefixes}, \fn{families}, \fn{keys} are lists of comma-separated entries referring to the keys to be disabled. Each of the lists \fn{prefixes}, \fn{families}, \fn{keys} may contain nil, one or more elements. If any of the members in \fn{keys} can't be located in \fn{families} and within \fn{prefixes}, an informational (not error) message is logged in respect of this member.
+
+The legacy version of \fx{\disable@keys} (\ie, that of the \sty{xkeyval} package) is still available via the starred version:
+\begin{macrocode}
+\disable@keys|redstar[|fv(prefix)]{|fv(family)}{|fv(keys)}.
+\end{macrocode}
+Note that this doesn't accept key prefixes and families, but only one key prefix and only one key family: the \fx{\disable@keys} command from the \sty{xkeyval} package can only be used to disable keys with the same \fn{prefix} and from the same \fn{family}, but not across prefixes and families.
+
+Any attempt to subsequently set or use a disabled key will prompt the following error message. (The \sty{xkeyval} package issues a warning in this case.) The error message can be modified by the user, but the names of the controls \fx{\SKV@disabledkey@err} and \fx{\SKV@disabledkey} should be retained.
+\begin{macrocode}
+\def\SKV@disabledkey@err{%
+ \@latex@error{%
+ Key |fv(key) with prefix |fv(prefix) in family |fv(family)
+ was disabled on input line |fv(lineno)
+ }{%
+ You can't set or reset |fv(key) at this
+ late stage. Perhaps you're required to set it
+ earlier, in the document's preamble.
+ }%
+}
+\end{macrocode}
+If the user attempts to disable an undefined key, the \sty{xkeyval} package issues a fatal error; the \sty{skeyval} package, on the other hand, issues a warning in the transcript .log file, since the situation isn't fatal to the outcome.
+
+Disabled keys can be redefined with commands in the \fy{\definekey} category but not with commands in the \fy{\newkey} category, since a disabled key remains defined: only its macro has been replaced by an error message signifying the disabling of the key.
+
+\textbf{Note:} Reserved and suspended keys can't be disabled, until they are unreserved or restored (see Sections~\ref{sec:reserve-keys} and~\ref{sec:suspend-keys}).
+
+\subsection{Reserving and unreserving keys}
+\label{sec:reserve-keys}
+
+The \sty{xkeyval} package bars its users from defining new keys with \fx{XKV} as a prefix. The \sty{skeyval} package generalizes this concept via the following three developer macros:
+\begin{macrocode}
+\ReserveKeyPrefixNames{|fv(list)}
+\end{macrocode}
+This allows the package developer to bar the future use of names appearing in \fn{list} as key prefixes. The \fn{list}, whose members are comma-separated, can be populated by the package developer as required.
+
+\begin{macrocode}
+\ReserveMacroPrefixNames{|fv(list)}
+\end{macrocode}
+This has a similar functionality to \fx{\ReserveKeyPrefixNames}, but applies to macro prefixes instead of key prefixes.
+
+\begin{macrocode}
+\ReserveFamilyNames{|fv(list)}
+\end{macrocode}
+This applies to family names.
+
+\textbf{Note:} One potential difficulty with the use of these macros is the fact that keys already defined by packages the developer would want to use can't appear in these lists since the lists are scanned both when defining and setting keys.
+
+In addition to the above three commands, the \sty{skeyval} package also introduces the following command:
+\begin{macrocode}
+\reserve@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)},
+\end{macrocode}
+where the lists \fn{prefixes}, \fn{families}, \fn{keys} can contain nil, one or more elements. Defined, reserved and suspended keys can't be reserved.
+
+Reserved keys have to be unreserved with the following command before they can be defined and used:
+\begin{macrocode}
+\unreserve@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)},
+\end{macrocode}
+where, again, the lists \fn{prefixes}, \fn{families}, \fn{keys} can contain nil, one or more elements. If a key was not previously reserved, this command will simply issue an informational message in the log file and ignore that key. Incidentally, defined keys and suspended keys can also be unreserved, which is equivalent to removing the keys (see \secref{sec:remove-keys}).
+
+\subsection{Suspending and restoring keys}
+\label{sec:suspend-keys}
+
+For some keys, it might be preferable to temporarily suspend them from a family (rather than disable or remove them) and restore them later. In this way, a key's state and macro can be frozen while the key remains defined.
+
+The syntax for suspending keys is
+\begin{macrocode}
+\suspend@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)},
+\end{macrocode}
+where the lists \fn{prefixes}, \fn{families}, \fn{keys} can contain nil, one or more elements.
+A key of particular prefix not previously defined in a family can't be suspended from that family. Similarly, a key previously suspended from a family can't be suspended again (for the second time) from the same family without being first restored in that family.
+
+Suspended keys can be restored to their frozen states (\name{ex ante} suspension) by the following command:
+\begin{macrocode}
+\restore@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}.
+\end{macrocode}
+Only keys (with a given prefix) previously suspended from a family can be restored in that family: ``unsuspended'' keys can't be restored.
+
+\subsection{Removing keys}
+\label{sec:remove-keys}
+
+The \sty{skeyval} package provides for removing keys completely, such that any attempt to set or use a removed key will prompt the error message that the key is undefined in the given family and with the given prefix. The command \fx{\key@ifundefined} from the \sty{xkeyval} package and the macro \fx{\ifkeydefined} from the \sty{skeyval} package will both identify a removed key as undefined. The syntax for removing keys is:
+\begin{macrocode}
+\remove@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}.
+\end{macrocode}
+
+Removed keys can't be restored but can be redefined with the commands in both the \fy{\newkey} and \fy{\definekey} categories.
+
+\section{Setting keys: list normalization}
+
+We have redefined the \fx{\setkeys} command of the \sty{xkeyval} package in two respects: firstly to accommodate the use of the \fx{\fif} and \fx{\ffi} macros of \secref{sec:dirty-trick}, and secondly to automatically convert double (or even multiple) commas and equality signs inadvertently submitted by the user into single comma and single equality sign. The following exaggerated example depicts the difficulties that might arise:
+\begin{example}
+\define@key[KV]{fam}{width}[1cm]{}
+\define@key[KV]{fam}{color}[black]{}
+\setkeys[KV]{fam}{width= =2cm, ,,color, == = =,green}
+\end{example}
+Here, the legacy \fx{\setkeys} will give the value nil to the key \fx{width}, and the default value of the key \fx{color}, if it was specified at key definition time, will be given to the key \fx{color}. Some of the mistakes (especially spurious values without keys) can disrupt a compilation run, while some (multiple commas and equality signs) will not be fatal to compilation but may lead to bizarre results of subsequent calculations. Mistakes of this kind can, surprisingly, be difficult to trace. The extra spaces and multiple commas aren't as serious as the multiple equality signs and values without keys, but we have taken care of all peculiar situations in the new \fx{\setkeys}. Multiple commas, equality signs, and spaces are now detected and reduced appropriately: that is what we mean by key-value \emph{list normalization}. We have adopted the premise that ``\fx{,=}'' (comma followed by equal) and ``\fx{=,}'' (equal followed by comma) are both most likely to mean ``\fx{=}'' (equal). In the unlikely event that this premise fails, then the user may get tricky errors if he makes this type of mistake: there is perhaps no silver bullet in this regard!
+
+If, for any reason, the user needs to pass keys with ``\fx{,=}'' and/or ``\fx{=,}'', then he may separate the comma from the equality sign with \fx{{}}, \eg, as in
+\begin{example}
+\setkeys[KV]{fam}{width=2cm,head={},tail=not measured},
+\end{example}
+which shows that the value of the key \fx{head} is \fx{\empty}, a valid and better assignment.
+
+\section{Miscellaneous macros}
+\label{sec:misce-commands}
+
+This package is predominantly about \latex keys and their efficient management, but it also
+contains many commands for general use, such that a package author may not need to redefine most of them or load some other packages to access those commands. Some of the available commands are described in this section.
+
+\begin{macrocode}
+\in@tog{|fv(subtoken)}{|fv(token)}
+\end{macrocode}
+This is similar to the \latex kernel's \sz{\in@}{subtoken}{token} which tests if \fn{subtoken} is in \fn{token}, but this time the returned boolean is the toggle switch \fn{in@} instead of the kernel's \fn{in@} switch which is used as \fx{\ifin@}. The toggle \fn{in@} can be used in the following way and in other manners that toggles can be employed:
+\begin{example}
+\iftog{in@}{|fv(true)}{|fv(false)}.
+\end{example}
+The command \fx{\in@tog} is robust.
+
+\begin{macrocode}
+\in@tok{|fv(subtoken)}{|fv(token)}
+\end{macrocode}
+Sometimes you want to use the \latex kernel's \sz{\in@}{subtoken}{token} to test if \fn{subtoken} is in \fn{token} irrespective of their catcodes. The robust command \sz{\in@tok}{subtoken}{token} makes this possible, and eliminates the tokens that would have been necessary if the user was required to first detokenize the two arguments. It returns the same switch \fx{\ifin@} as the kernel's \sz{\in@}{subtoken}{token}.
+
+\begin{macrocode}
+\SKV@ifdefinable|fv(cs){|fv(function)}
+\SKV@for@ifdefinable|fv(listcmd){|fv(function)}
+\end{macrocode}
+\LaTeX kernel's \fx{\@ifdefinable} fills up the hash table and also considers commands that are \fx{\relax}'ed as defined. Moreover, if the command being tested (\fn{cs} in the above example) is definable, the \fx{\@ifdefinable} macro begins executing \fn{function} while still in the \fx{\if} \textellipsis \fx{\fi} conditional. The command \fx{\SKV@ifdefinable} seeks to avoid these problems.
+
+The macro \fx{\SKV@for@ifdefinable} accepts a comma-separated list \fn{listcmd} of control sequence names whose definability are to be tested. Both commands \fx{\SKV@ifdefinable} and \fx{\SKV@for@ifdefinable} are robust.
+
+\begin{macrocode}
+\SKV@expandargs|fv(n)|fv(function)|fv(arg1)|fv(arg2)\SKV@nil
+\end{macrocode}
+\LaTeX's \fx{\@expandtwoargs} is often used as a utility macro to expand two arguments \fn{arg1} and \fn{arg2} in order to execute \fn{function}. The command \fx{\SKV@expandargs} accepts up to four expansion types, signified by \fn{n}, which runs from 0 to 3:
+\begin{compactenum}
+\item If \fn{n} is 0, then \fn{arg2} is empty and only \fn{arg1} will be expanded before \fn{function} is executed.
+\item If \fn{n} is 1, then both \fn{arg1} and \fn{arg2} are nonempty but only \fn{arg2} will be expanded before \fn{function} is executed.
+\item When \fn{n} is 2, then both \fn{arg1} and \fn{arg2} are nonempty and both will be expanded before \fn{function} is executed. This is equivalent to \LaTeX's \fx{\@expandtwoargs}.
+\item If \fn{n} is 3, then both \fn{arg1} and \fn{arg2} are nonempty but only \fn{arg1} is expanded before \fn{function} is executed.
+\item If \fn{n} isn't in the list \sx{0,1,2,3}, then an error message is flagged.
+\end{compactenum}
+Because \fn{arg2} is delimited, it can be empty. The command \fx{\SKV@expandargs} can be used to save \fx{\expandafter}'s, but it isn't an all-purpose macro: for example, the \fx{\edef} it uses may expand too deeply in some cases. Also, care should be exercised when the expanded argument (\fn{arg1} and/or \fn{arg2}) involve the \tex primitive \fx{\if}.
+
+Some trivial examples follow:
+\begin{example}
+\SKV@expandargs{0}{\def\tempc#1#2}{\def\noexpand##1{##2}}%
+ \SKV@nil
+\tempc\tempa{aaa}
+\tempc\tempb{abcaaabbccbca}
+\SKV@expandargs{2}\in@\tempa\tempb\SKV@nil
+\show\ifin@
+\end{example}
+Compare these expressions with the chains of \fx{\expandafter}'s in \secref{sec:condit-in-macros}.
+
+\begin{macrocode}
+\SKV@checkchoice{|fv(keyvalue)}{|fv(altlist)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+This is the expandable form of \sty{xkeyval} package's \fx{\XKV@checkchoice}. It checks if the user-submitted value \fn{keyvalue} of a \fn{key} is in the list \fn{altlist}. It executes \fn{true} if \fn{keyvalue} is found in \fn{altlist} and \fn{false} otherwise. Additionally, it returns \fx{\val} for the expanded value of \fn{keyvalue} and \fx{\nr} for the numerical order of \fx{\val} in the list \fn{altlist}. If \fn{keyvalue} isn't found in \fn{altlist}, then \fx{\nr} will return $-1$. If \fn{keyvalue} and \fn{altlist} are buried in macros, the macros are fully expanded before the search for \fn{keyvalue} in the list \fn{altlist} is effected. In that case, \fx{\val} will hold the expanded form of \fn{keyvalue} and can be used in subsequent computations. Choice keys do accept macros as values, but such values aren't directly suitable for matching against the contents of \fn{altlist}. For example, \fn{altlist} may be the set \fx{{left,right,center}}, but given as a macro \fx{\altlist@}, while \fn{keyvalue} is given as \fx{\def\keyvalue@{center}}. Obviously, \fx{\keyvalue@} contains one of the elements of \fn{altlist}, but choice keys won't know this without the expansion of both \fx{\altlist@} and \fx{\keyvalue@}. This is \name{raison d'\^e tre} of the \fx{\SKV@checkchoice} macro.
+
+Moreover, \fx{\SKV@checkchoice} can be used in the definition of non-choice keys. An example follows:
+\begin{example}
+\def\altlist@{left,right,center}
+\newordkey[KV]{fam}{keya}[true]{%
+ \SKV@checkchoice{#1}{\altlist@}{%
+ \ifcase\nr\relax
+ \edef\tempa##1##2{##1===\val===##2}%
+ \or
+ \edef\tempa##1##2{##1***\val***##2}%
+ \or
+ \edef\tempa##1##2{##1+++\val+++##2}%
+ \fi
+ }{%
+ \@latex@error{Wrong value for `keya'}\@eha
+ }%
+}
+\def\keyvalue@{center}
+\setkeys[KV]{fam}{keya=\keyvalue@}
+\end{example}
+
+The reader may wish to do \fx{\show\tempa} to see what \fx{\tempa} gets upon setting the key \fx{keya}.
+
+\begin{macrocode}
+\requirecmd{|fv(cs)}[|fv(number of args)][|fv(default)]%
+ {|fv(replacement text)}
+\end{macrocode}
+This is explained in \secref{sec:toggle-switches}. If \fn{cs} is already defined, \fx{\requirecmd} checks if the new and old definitions are identical. If they aren't, a warning message is logged in the transcript file and the new definition is aborted.
+
+\begin{macrocode}
+\SKV@for@a{|fv(list)}|fv(cmd){|fv(function)}
+\SKV@for@b|fv(listcmd)|fv(cmd){|fv(function)}
+\end{macrocode}
+A fast for-loop adapted from the \sty{xkeyval} package to accept general list parsers. Elements of \fn{list} are stored in \fn{cmd}, and \fn{function} is executed for each element of \fn{list}. The \fn{list}, which is populated by comma-separated elements, is not expanded. This accepts a general list parser, dynamically declarable via
+\begin{macrocode}
+\SKV@CommandGenParser{|fv(parser)} |color(black) or |color(verbcolor)
+\skvoptions{genparser=|fv(parser)},
+\end{macrocode}
+instead of just one type of parser (``comma'' in the \sty{xkeyval} package). Also, this uses the more powerful \fx{\SKV@ifblank} to check whether or not \fn{list} is empty or blank. The command \fx{\SKV@for@a} is robust, but in expansion contexts, both \fn{cmd} and \fn{function} will need to be somehow protected. In the \fx{\SKV@for@b} command, \fn{listcmd} is expanded once before the iteration commences. One snag with \fx{\SKV@CommandGenParser} is that the user must always remember to call it and set the right parser before beginning an iteration, otherwise there might be unpleasant surprises, since a previous call to \fx{\SKV@CommandGenParser} might have set a parser that is no longer valid.
+
+\begin{macrocode}
+\SKV@tfor@a|fv(cmd){|fv(list)}{|fv(function)}
+\SKV@tfor@b|fv(cmd)|fv(listcmd){|fv(function)}
+\end{macrocode}
+The first of these (\ie, \fx{\SKV@tfor@a}) is equivalent to \latex kernel's \fx{\@tfor}, which loops over \fn{list} token-wise (character or control sequence token), but here we have removed the need for the usual delimitation tokens. Note that \fn{list} is not a comma-separated list! In \fx{\SKV@tfor@b}, \fn{listcmd} is expanded once before the commencement of the loop. The two commands \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} are both robust.
+
+\begin{macrocode}
+\SKV@ifstrequal{|fv(token1)}{|fv(token2)}{|fv(true)}{|fv(false)}
+\SKV@oifstrequal{|fv(token1)}{|fv(token2)}{|fv(true)}{|fv(false)}
+\SKV@xifstrequal{|fv(token1)}{|fv(token2)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+In order to properly test the equality of strings, it may be necessary to remove leading and trailing spaces before the test. Such spaces may have cropped into the strings from input or from pre-processing and may invalidate the test. The macro \fx{\SKV@ifstrequal} takes care of such situations. It executes \fn{true} if \fn{token1} is equal (character code wise) to \fn{token2}, and \fn{false} otherwise. Both \fn{token1} and \fn{token2} are detokenized before the test. The macro \fx{\SKV@oifstrequal} is similar to \fx{\SKV@ifstrequal} but first expands its arguments (the two token lists \fn{token1} and \fn{token2}) once before the test. The macro \fx{\SKV@xifstrequal} first expands its arguments fully before the test.
+
+\begin{macrocode}
+\SKV@ifblank{|fv(token)}{|fv(true)}{|fv(false)}
+\SKV@oifblank{|fv(token)}{|fv(true)}{|fv(false)}
+\SKV@xifblank{|fv(token)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+These macros test if the argument is blank or not. The first of these is from \sty{ifmtarg} package. \fx{\SKV@oifblank} expands its argument once before the test, while \fx{\SKV@xifblank} expands its argument fully before the test.
+
+\begin{macrocode}
+\SKV@ifstrempty{|fv(token)}{|fv(true)}{|fv(false)}
+\SKV@oifstrempty{|fv(token)}{|fv(true)}{|fv(false)}
+\SKV@xifstrempty{|fv(token)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+These yield \fn{true} if \fn{token} is empty, and \fn{false} otherwise. In the macro \fx{\SKV@ifstrempty}, \fn{token} isn't expanded before the test; in the command \fx{\SKV@oifstrempty}, \fn{token} is expanded once before the test; in the command \fx{\SKV@xifstrempty}, \fn{token} is fully expanded before the test.
+
+\begin{macrocode}
+\SKV@expandox{|fv(cs)}
+\end{macrocode}
+This expands its argument \fn{cs} once and forbids further expansion.
+
+\begin{macrocode}
+\SKV@expandnameox{|fv(name)}
+\end{macrocode}
+This is similar to \fx{\SKV@expandox} but accepts control sequence name \fn{name} instead of control sequence.
+
+\begin{macrocode}
+\SKV@expandtx{|fv(cs)}
+\end{macrocode}
+This expands its argument \fn{cs} twice and forbids further expansion.
+
+\begin{macrocode}
+\SKV@expandnametx{|fv(name)}
+\end{macrocode}
+This is similar to \fx{\SKV@expandtx} but accepts control sequence name instead of control sequence.
+
+\begin{macrocode}
+\@afterpackageloaded{|fv(package)}{|fv(code)}
+\end{macrocode}
+This executes \fn{code} only after the package \fn{package} has been loaded. This has been optimized from the \sty{afterpackage} package to avoid filling up the hash table with hooks that are \fx{relax}'ed or indeed undefined.
+
+\begin{macrocode}
+\SKV@newlet{|fv(cs1)}{|fv(cs2)}
+\end{macrocode}
+This assigns \fn{cs2} to \fn{cs1} if \fn{cs2} exists and if \fn{cs1} isn't already defined, otherwise an error is flagged.
+
+\begin{macrocode}
+\SKV@newtoks{|fv(toks)}
+\end{macrocode}
+This provides a new token register \fn{toks} if the register didn't already exist, otherwise an error is flagged.
+
+\begin{macrocode}
+\SKV@newcount{|fv(counter)}
+\end{macrocode}
+This provides a new counter register \fn{counter} if the register didn't already exist, otherwise an error is flagged.
+
+\begin{macrocode}
+\SKV@newdimen{|fv(dimen)}
+\end{macrocode}
+This provides a new dimension register \fn{dimen} if the register didn't already exist, otherwise an error is flagged.
+
+\begin{macrocode}
+\SKV@numdef{|fv(num)}{|fv(expression)}
+\SKV@numnamedef{|fv(num)}{|fv(expression)}
+\SKV@numgdef{|fv(num)}{|fv(expression)}
+\SKV@numnamegdef{|fv(num)}{|fv(expression)}
+\end{macrocode}
+\fx{\SKV@numdef} defines \fn{num} from \fn{expression} using \etex's \fx{\numexpr}. It is similar to \sty{etoolbox}'s \fx{\numdef} but is defined by a counter expression instead of \fx{\edef} (which \sty{etoolbox} uses). If \fn{num} is previously undefined, it is first initialized before the expression is built. The difference between \fx{\numdef} and \fx{\SKV@numdef} is that if you do \fx{\numdef\x{1+2+3}}, you can use \fx{\x} without, depending on context, prefixing it with \fx{\the} or \fx{\number}. \fx{\SKV@numdef}, on the other hand, will require \fx{\the} or \fx{\number}. Also, \fx{\SKV@numdef} includes two tests of its arguments.
+
+\fx{\SKV@numnamedef} is the same as \fx{\SKV@numdef} but takes a control sequence name instead of a control sequence.
+
+The macros \fx{\SKV@numgdef} and \fx{\SKV@numnamegdef}, unlike \fx{\SKV@numdef} and \fx{\SKV@numnamedef}, effect global assignments and thus can escape local groups.
+
+\begin{macrocode}
+\SKV@dimdef{|fv(dimen)}{|fv(expression)}
+\SKV@dimnamedef{|fv(dimen)}{|fv(expression)}
+\SKV@dimgdef{|fv(dimen)}{|fv(expression)}
+\SKV@dimnamegdef{|fv(dimen)}{|fv(expression)}
+\end{macrocode}
+\fx{\SKV@dimdef} defines \fn{dimen} from \fn{expression} using \etex's \fx{\dimexpr}. It is similar to \sty{etoolbox}'s \fx{\dimdef} but is defined by a dimension expression instead of \fx{\edef}. If \fn{dimen} is previously undefined, it is first initialized before the expression is built. The difference between \fx{\dimdef} and \fx{\SKV@dimdef} is that if you do \fx{\dimdef\x{1pt+2mm+3cm}}, you can use \fx{\x} without prefixing it with \fx{\the}. \fx{\SKV@dimdef}, on the other hand, will require \fx{\the}.
+
+The macros \fx{\SKV@dimgdef} and \fx{\SKV@dimnamegdef}, unlike \fx{\SKV@dimdef} and \fx{\SKV@dimnamedef}, effect global assignments.
+
+\begin{macrocode}
+\SKV@newnamedef{|fv(name)}{|fv(definition)}
+\SKV@newnamegdef{|fv(name)}{|fv(definition)}
+\SKV@newnameedef{|fv(name)}{|fv(definition)}
+\SKV@newnamexdef{|fv(name)}{|fv(definition)}
+\end{macrocode}
+These turn \fn{name} into a control sequence if it wasn't already defined. If it is already defined, an error message is flagged. These derive from a concept based on that of \fx{\newcommand}, but
+\begin{inparaenum}[(i)]
+\item \fx{\relax}\unskip 'ed commands are considered undefined in this regard, and
+\item these commands retain the powerful machinery of plain \tex.
+\end{inparaenum}
+
+\begin{macrocode}
+\SKV@namedef{|fv(name)}{|fv(definition)}
+\SKV@namegdef{|fv(name)}{|fv(definition)}
+\SKV@nameedef{|fv(name)}{|fv(definition)}
+\SKV@namexdef{|fv(name)}{|fv(definition)}
+\end{macrocode}
+These turn \fn{name} into a control sequence whether or not the control was already defined. No error or warning messages are issued.
+
+\begin{macrocode}
+\nameletcs{|fv(name)}{|fv(cs)}
+\csletname{|fv(cs)}{|fv(name)}
+\nameletname{|fv(name)}{|fv(name)}
+\end{macrocode}
+These perform \fx{\let} assignments if the second argument is defined, otherwise an error message is flagged. \fn{cs} means a control sequence.
+
+\begin{macrocode}
+\@nameletcs{|fv(name)}{|fv(cs)}
+\@csletname{|fv(cs)}{|fv(name)}
+\@nameletname{|fv(name)}{|fv(name)}
+\end{macrocode}
+These perform \fx{\let} assignments whether or not the second argument is defined. If the second argument is undefined, the hash table is not filled.
+
+\begin{macrocode}
+\SKV@nameuse{|fv(name)}
+\end{macrocode}
+This is similar to \LaTeX's \fx{\@nameuse} but returns \fx{\@empty} if \fn{name} is undefined. The idea derives from the \sty{etoolbox} package.
+
+\begin{macrocode}
+\SKV@ifdef{|fv(cs)}{|fv(true)}{|fv(false)}
+\SKV@ifnamedef{|fv(name)}{|fv(true)}{|fv(false)}
+\SKV@ifundef{|fv(cs)}{|fv(true)}{|fv(false)}
+\SKV@ifnameundef{|fv(name)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+These use \etex's facilities to test the existence of the control sequence \fn{cs} or \fn{name}. \fx{\relax}\unskip 'ed commands are considered undefined in this regard. These are based on similar concepts from the \sty{etoolbox} package.
+
+\begin{macrocode}
+\SKV@findescape{|fv(arg)}{|fv(true)}{|fv(false)}
+\end{macrocode}
+This returns \fn{true} if \fn{arg} starts with the \fx{\escapechar}, and \fn{false} otherwise. The \fx{\escapechar} is locally made equal to 92 before the test.
+
+\begin{macrocode}
+\SKV@undef{|fv(cs)}
+\SKV@gundef{|fv(cs)}
+\SKV@nameundef{|fv(name)}
+\SKV@namegundef{|fv(name)}
+\end{macrocode}
+These undefine the macro \fn{cs} or control sequence name \fn{name} such that \tex will subsequently consider them undefined. The macros \fn{\SKV@gundef} and \fn{\SKV@namegundef} undefine their argument globally.
+
+\begin{macrocode}
+\SKV@aftergroup{|fv(code)}
+\SKV@aftergroup|redstar{|fv(code)}
+\SKV@afterassignment{|fv(code)}
+\SKV@afterassignment|redstar{|fv(code)}
+\end{macrocode}
+These execute the arbitrary \fn{code} after a group or assignment. The starred versions fully expand \fn{code} before the assignment (or before exiting the group). These are similar to \fx{\AfterGroup} and \fx{\AfterAssignment} of \sty{etextools} package but they don't accumulate the group and assignment counters indefinitely: the counters are initialized after each group or each assignment.
+
+Some examples follow:
+\begin{example}
+\def\aa{aaa}\def\bb{bbb}\def\xx{xxx}\def\yy{yyy}
+\begingroup
+ \SKV@aftergroup{\par\aa***\bb}%
+ \SKV@aftergroup{\par\bb***\aa}%
+ \begingroup
+ \SKV@aftergroup{\par\xx+++\yy}%
+ \SKV@aftergroup{\par\yy+++\xx}%
+ \endgroup
+\endgroup
+
+\let\gobblex\@firstofone
+\def\protected@funnydef{%
+ \let\@@protect\protect
+ \let\protect\@unexpandable@protect
+ \SKV@afterassignment{\restore@protect\let\gobblex\@gobble}%
+ \edef
+}
+\end{example}
+
+\begin{macrocode}
+\SKV@apptomacro@a|fv(cs)|fv(content)
+\SKV@apptomacro@b|fv(cs)|fv(content)
+\SKV@gapptomacro@a|fv(cs)|fv(content)
+\SKV@gapptomacro@b|fv(cs)|fv(content)
+\end{macrocode}
+This appends \fn{content} to \fn{cs}. If \fn{cs} was previously undefined, it is initialized with \fn{content}. \fx{\SKV@apptomacro@a} doesn't expand \fn{content} before appending it to \fn{cs}, while \fx{\SKV@apptomacro@b} expands \fn{content} once before appending it's contents to \fn{cs}.
+The macros \fx{\SKV@gapptomacro@a} and \fx{\SKV@gapptomacro@b} have global effect, which can escape local groups. Except for the initialization of undefined \fn{cs}, \fx{\SKV@gapptomacro@a} is equivalent to \latex's \fx{\g@addto@macro}.
+
+\begin{macrocode}
+\SKV@preptomacro@a|fv(cs)|fv(content)
+\SKV@preptomacro@b|fv(cs)|fv(content)
+\SKV@gpreptomacro@a|fv(cs)|fv(content)
+\SKV@gpreptomacro@b|fv(cs)|fv(content)
+\end{macrocode}
+These perpend \fn{content} to \fn{cs}. If \fn{cs} was previously undefined, it is initialized with \fn{content}. \fx{\SKV@preptomacro@a} doesn't expand \fn{content} before prepending it to \fn{cs}, while \fx{\SKV@preptomacro@b} expands \fn{content} once before prepending it's contents to \fn{cs}. The macros \fx{\SKV@gapptomacro@a} and \fx{\SKV@gapptomacro@b} have global effect.
+
+\begin{macrocode}
+\InputFileOnce[|fv(path)]{|fv(filename)}
+\end{macrocode}
+This inputs \fn{filename} on \fn{path} but only once. The argument \fn{path} is optional and its default value is the current/document's directory. If \fn{filename} had previously been read, an error message is flagged and the input is aborted. If \fn{filename} doesn't exist on \fn{path}, an opportunity is given to the user to type in the correct file name on the screen, or continue with the \latex pass without inputting the file. If the user wants to input \fn{filename} more than once in one document, then he should set \fx{\SKV@inputonce} to \fn{false} before the call to \fx{\InputFileOnce}, either by simply issuing \fx{\SKV@inputoncefalse} or via \fx{\skvoptions}:
+\begin{example}
+\skvoptions{inputonce=false}.
+\end{example}
+\fx{\SKV@inputonce} can, of course, be toggled between \fn{false} and \fn{true}.
+
+\begin{macrocode}
+\AtStartOfDocument{|fv(code)}
+\end{macrocode}
+This is the expansion-context version of the hook \fx{\AtBeginDocument}. Sometimes you want to do something like
+\begin{macrocode}
+\edef\tempa{\AtBeginDocument{%
+ \def\noexpand\tempb{come with me}}},
+\end{macrocode}
+which is impossible without a \fx{\noexpand} before \fx{\AtBeginDocument}. With \fx{\AtStartOfDocument} the protection is not necessary.
+
+Two more expansion-context document hooks are provided below:
+\begin{macrocode}
+\BeforeStartOfDocument{|fv(code)}
+\AfterStartOfDocument{|fv(code)}.
+\end{macrocode}
+These mimic the \fx{\AtEndPreamble} and \fx{\AfterEndPreamble} hooks from the \sty{etoolbox} package.
+
+\section{Version history}
+
+This package was called the \sty{keyreader} package until version~0.5, when the name became a misnomer.
+
+\setdefaultleftmargins{0em}{3.0em}{1.87em}{1.7em}{1em}{1em}
+\begin{compactenum}
+\item Version 0.1 [01/01/2010]
+ \begin{compactenum}
+ \item Provided machinery for reading multiple keys of all kinds from just one command.
+ \item Introduced complementary boolean keys.
+ \end{compactenum}
+
+\item Version 0.2 [10/01/2010]
+ \begin{compactenum}
+ \item Corrected a bug.
+ \end{compactenum}
+
+\item Version 0.3 [20/01/2010]
+ \begin{compactenum}
+ \item Introduced toggles and toggle keys.
+ \end{compactenum}
+
+\item Version 0.4 [01/02/2010]
+ \begin{compactenum}
+ \item Introduced complementary toggle keys.
+ \end{compactenum}
+
+\item Version 0.5 [23/02/2010]
+ \begin{compactenum}
+ \item Provided facilities for avoiding repeated definition of same key (when desired).
+ \item Provided mechanisms for disabling, reserving, unreserving, suspending, restoring, and removing keys after they have been defined.
+ \item Redefined a few of \sty{xkeyval} package's macros.
+ \item Included some developer macros.
+ \end{compactenum}
+\end{compactenum}
+\restoredefaultleftmargins
+
+
+\end{document}
+
+%%% End of file skeyval-guide.tex %%% \ No newline at end of file
diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval.sty b/Master/texmf-dist/tex/latex/skeyval/skeyval.sty
new file mode 100644
index 00000000000..2f8ed0862be
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/skeyval/skeyval.sty
@@ -0,0 +1,1679 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% %
+% This is file 'skeyval.sty', version 0.5. %
+% %
+% Please see the package documentation for user guide. %
+% %
+% This package and accompanying files may be distributed and/or modified under %
+% the conditions of the LaTeX Project Public License, either version 1.3 of %
+% this license or any later version. The latest version of this license is in %
+% http://www.latex-project.org/lppl.txt and version 1.3 or later is part of all %
+% distributions of LaTeX version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, either %
+% expressed or implied, including, but not limited to, the implied warranties of %
+% merchantability and fitness for a particular purpose. %
+% %
+% Copyright (c) 2010 Ahmed Musa (a.musa@rocketmail.com). %
+% %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup
+\catcode064 11% @
+\catcode123 01% {
+\catcode125 02% }
+\def\SKV@tempa{\endgroup
+ \edef\SKV@restorecodes{%
+ \catcode035 \the\catcode035% #
+ \catcode064 \the\catcode064% @
+ \catcode123 \the\catcode123% {
+ \catcode125 \the\catcode125% }
+ \catcode061 \the\catcode061% =
+ }%
+}
+\SKV@tempa
+\catcode035 06% #
+\catcode064 11% @
+\catcode123 01% {
+\catcode125 02% }
+\def\SKV@ensurecode#1#2{%
+ \edef\SKV@restorecodes{%
+ \SKV@restorecodes
+ \catcode#1 \the\catcode#1\relax
+ }%
+ \catcode#1 #2\relax
+}
+\AtEndOfPackage{\SKV@restorecodes}
+\SKV@ensurecode{061}{12}% =
+\SKV@ensurecode{044}{12}% ,
+\SKV@ensurecode{058}{12}% :
+\SKV@ensurecode{059}{12}% ;
+\SKV@ensurecode{010}{12}% ^^J
+\SKV@ensurecode{126}{13}% ~
+\def\SKV@rcsid$#1: #2 #3 #4 #5${#4 v#3}
+\ProvidesPackage{skeyval}%
+ [\SKV@rcsid $Id: skeyval.sty,v 0.5 2010/02/26 09:00:00 Ahmed Musa $
+ Extensions to the xkeyval parser (AM)]
+\NeedsTeXFormat{LaTeX2e}[1996/12/01]
+\@ifpackageloaded{xkeyval}\relax{\RequirePackage{xkeyval}[2008/08/13]}
+\ifnum0=0%
+ \ifx\eTeXversion\SKV@undefined 1\else\ifnum\eTeXversion<\tw@ 1\fi\fi
+\else
+ \@latex@error{eTeX not loaded or old version}{%
+ This package requires eTeX version 2 or later.}%
+\fi
+\@ifdefinable\SKV@ifdefinable\relax
+\def\SKV@ifdefinable#1{%
+ \edef\reserved@a{\expandafter\@gobble\string#1}%
+ \ifdefined#1%
+ \ifx#1\relax
+ \expandafter\expandafter\expandafter\@firstofone
+ \else
+ \expandafter\expandafter\expandafter\@notdefinable
+ \fi
+ \else
+ \edef\reserved@b{\expandafter\@carcube\reserved@a xxx\@nil}%
+ \ifx\reserved@b\@qend
+ \expandafter\expandafter\expandafter\@notdefinable
+ \else
+ \ifx\reserved@a\@qrelax
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter\@notdefinable
+ \else
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter\@firstofone
+ \fi
+ \fi
+ \fi
+}
+\SKV@ifdefinable\SKV@def{\protected\def\SKV@def{\@star@or@long\SKV@aux@def}}
+\SKV@ifdefinable\SKV@aux@def{%
+ \def\SKV@aux@def#1{\SKV@ifdefinable#1{\l@ngrel@x\def#1}}}
+\SKV@ifdefinable\SKV@gdef{\protected\def\SKV@gdef{\@star@or@long\SKV@aux@gdef}}
+\SKV@ifdefinable\SKV@aux@gdef{%
+ \def\SKV@aux@gdef#1{\SKV@ifdefinable#1{\global\l@ngrel@x\def#1}}}
+\SKV@ifdefinable\SKV@edef{\protected\def\SKV@edef{\@star@or@long\SKV@aux@edef}}
+\SKV@ifdefinable\SKV@aux@edef{%
+ \def\SKV@aux@edef#1{\SKV@ifdefinable#1{\l@ngrel@x\edef#1}}}
+\SKV@ifdefinable\SKV@pdef{\protected\def\SKV@pdef{\@star@or@long\SKV@aux@pdef}}
+\SKV@ifdefinable\SKV@aux@pdef{%
+ \def\SKV@aux@pdef#1{\SKV@ifdefinable#1{\protected\l@ngrel@x\def#1}}}
+\SKV@ifdefinable\SKV@pedef{\protected\def\SKV@pedef{\@star@or@long\SKV@aux@pedef}}
+\SKV@ifdefinable\SKV@aux@pedef{%
+ \def\SKV@aux@pedef#1{\SKV@ifdefinable#1{\protected\l@ngrel@x\edef#1}}}
+\SKV@pdef\SKV@defined@err#1{\def\reserved@a{#1}\@notdefinable}
+\SKV@def\SKV@for@ifdefinable#1{%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b#1\SKV@tempa{%
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempa\SKV@tempa\SKV@nil
+ \if\expandafter\expandafter\expandafter\SKV@car\expandafter
+ \string\SKV@tempa\SKV@nil\@backslashchar
+ \SKV@err{Backslash not allowed}\@ehc
+ \fi
+ \SKV@ifnameundef\SKV@tempa{}{\SKV@defined@err\SKV@tempa}%
+ }%
+}
+\SKV@pdef\SKV@info#1{\PackageInfo{skeyval}{#1\@gobble}}
+\SKV@pdef\SKV@warn#1{\PackageWarningNoLine{skeyval}{#1}}
+\SKV@pdef\SKV@err#1#2{\PackageError{skeyval}{#1}{#2}}
+\SKV@def*\SKV@nil{\noexpand\SKV@nil}
+\SKV@def*\SKV@nnil{\SKV@nil}
+\SKV@def\SKV@car#1#2\SKV@nil{#1}
+\gdef\@notprerr{\SKV@err{You've issued a preamble command here}%
+ {Take command to preamble.}}
+\SKV@pdef\SKV@afterfi#1\fi{\fi#1}
+\SKV@pdef\SKV@afterelsefi#1\else#2\fi{\fi#1}
+\SKV@def\SKV@aftercsname#1#2{\expandafter#1\csname#2\endcsname}
+\SKV@def\SKV@findescape#1{%
+ \begingroup\escapechar92 \expandafter\endgroup
+ \if\expandafter\SKV@car\string#1\SKV@nil\@backslashchar
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\SKV@def*\SKV@expandox#1{\unexpanded\expandafter{#1}}
+\SKV@def*\SKV@expandnameox#1{\SKV@aftercsname\SKV@expandox{#1}}
+\SKV@def*\SKV@expandtx#1{\unexpanded\expandafter\expandafter\expandafter{#1}}
+\SKV@def*\SKV@expandnametx#1{\SKV@aftercsname\SKV@expandtx{#1}}
+\SKV@def*\SKV@noexpandcs#1{\SKV@aftercsname\noexpand{#1}}
+\SKV@pdef\SKV@undef#1{\let#1\SKV@undefined}
+\SKV@pdef\SKV@gundef#1{\global\let#1\SKV@undefined}
+\SKV@pdef\SKV@nameundef#1{\SKV@aftercsname\let{#1}\SKV@undefined}
+\SKV@pdef\SKV@namegundef#1{\global\SKV@aftercsname\let{#1}\SKV@undefined}
+\SKV@def\SKV@ifdef#1{%
+ \ifdefined#1%
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\SKV@def\SKV@ifundef#1{%
+ \ifdefined#1%
+ \ifx#1\relax
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \else
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \fi
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+\SKV@def*\SKV@ifnamedef#1{%
+ \ifcsname#1\endcsname
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\SKV@def*\SKV@ifnameundef#1{%
+ \ifcsname#1\endcsname
+ \expandafter\ifx\csname#1\endcsname\relax
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \else
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \fi
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+\SKV@def\SKV@remparser#1#2{%
+ \def\tok@i{#1}\edef\tok@ii{#1#2}%
+ \ifx#2\@empty\else
+ \def\SKV@remove#1##1\SKV@nil{\def\tok@ii{##1}}%
+ \SKV@r@move\let#2\tok@ii
+ \fi
+}
+\SKV@def*\SKV@r@move{\expandafter\SKV@rem@ve\tok@ii\SKV@nil}
+\SKV@def*\SKV@rem@ve{\futurelet\@temptoks\SKV@remo@e}
+\SKV@def*\SKV@remo@e#1\SKV@nil{%
+ \if\@temptoks\tok@i
+ \expandafter\SKV@remove\tok@ii\SKV@nil
+ \SKV@r@move
+ \fi
+}
+\SKV@def\SKV@apptomacro@a#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \edef#1{\unexpanded{#2}}%
+ }{%
+ \edef#1{\SKV@expandox#1\unexpanded{#2}}%
+ }%
+}
+\SKV@def\SKV@apptomacro@b#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \edef#1{\SKV@expandox{#2}}%
+ }{%
+ \xdef#1{\SKV@expandox#1\SKV@expandox{#2}}%
+ }%
+}
+\SKV@def\SKV@preptomacro@a#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \edef#1{\unexpanded{#2}}%
+ }{%
+ \edef#1{\unexpanded{#2}\SKV@expandox#1}%
+ }%
+}
+\SKV@def\SKV@preptomacro@b#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \edef#1{\SKV@expandox{#2}}%
+ }{%
+ \edef#1{\SKV@expandox{#2}\SKV@expandox#1}%
+ }%
+}
+\SKV@def\SKV@gapptomacro@a#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \xdef#1{\unexpanded{#2}}%
+ }{%
+ \xdef#1{\SKV@expandox#1\unexpanded{#2}}%
+ }%
+}
+\SKV@def\SKV@gapptomacro@b#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \xdef#1{\SKV@expandox{#2}}%
+ }{%
+ \xdef#1{\SKV@expandox#1\SKV@expandox{#2}}%
+ }%
+}
+\SKV@def\SKV@gpreptomacro@a#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \xdef#1{\unexpanded{#2}}%
+ }{%
+ \xdef#1{\unexpanded{#2}\SKV@expandox#1}%
+ }%
+}
+\SKV@def\SKV@gpreptomacro@b#1#2{%
+ \SKV@findescape{#1}{}{%
+ \SKV@err{Bad argument '\string#1'}{Backslash required in '\string#1'.}%
+ }%
+ \SKV@ifundef{#1}{%
+ \xdef#1{\SKV@expandox{#2}}%
+ }{%
+ \xdef#1{\SKV@expandox{#2}\SKV@expandox#1}%
+ }%
+}
+\SKV@def*\@afterpackageloaded#1{%
+ \SKV@ifnamedef{ver@#1.\@pkgextension}{%
+ \let\SKV@tempa\@firstofone
+ }{%
+ \def\SKV@tempa{\SKV@aftercsname\SKV@apptomacro@a{#1.\@pkgextension @afpl}}%
+ }%
+ \SKV@tempa
+}
+\SKV@preptomacro@a\@popfilename{%
+ \SKV@nameuse{\@currname.\@currext @afpl}%
+ \SKV@nameundef{\@currname.\@currext @afpl}%
+}
+\@onlypreamble\@afterpackageloaded
+\SKV@def\ReserveKeyPrefixNames#1{\SKV@apptomacro@a\SKV@rkpnames{,#1}}
+\SKV@def\ReserveMacroPrefixNames#1{\SKV@apptomacro@a\SKV@rmpnames{,#1}}
+\SKV@def\ReserveFamilyNames#1{\SKV@apptomacro@a\SKV@rfnames{,#1}}
+\SKV@def*\SKV@rkpnames{XKV}
+\SKV@def*\SKV@rmpnames{XKV}
+\SKV@def*\SKV@rfnames{XKV}
+\SKV@pdef*\SKV@CommandGenParser#1{%
+ \def\parser{#1}%
+ \protected\long\def\SKV@for@a##1##2##3{%
+ \edef##2{\unexpanded{##1}}%
+ \SKV@oifblank{##2}\SKV@fornoop\SKV@forloop
+ ##2{##3}##1#1\SKV@nil#1%
+ }%
+ \long\def\SKV@forloop##1##2##3#1{%
+ \edef##1{\unexpanded{##3}}%
+ \ifx##1\SKV@nnil
+ \expandafter\@gobbletwo
+ \else
+ ##2\expandafter\SKV@forloop
+ \fi
+ ##1{##2}%
+ }%
+ \long\def\SKV@fornoop##1\SKV@nil#1{}%
+}
+\SKV@pdef\SKV@for@b#1{\expandafter\SKV@for@a\expandafter{#1}}
+\SKV@pdef*\SKV@tfor@a#1#2#3{\SKV@ifblank{#2}{}{\@tf@r#1{#2}\do{#3}}}
+\SKV@pdef*\SKV@tfor@b#1#2#3{%
+ \SKV@expandargs{3}{\SKV@tfor@a#1}{{\SKV@expandox{#2}}}{{#3}}\SKV@nil
+}
+\SKV@def\SKV@checksanitizec#1#2{%
+ \XKV@ch@cksanitize{#1}#2;%
+ \ifin@\else\XKV@ch@cksanitize{#1}#2,\fi
+ \ifin@\@selective@sanitize[0]{,;}#2\fi
+}
+\SKV@def*\SKV@CommandKeyParser#1{%
+ \long\def\SKV@define@keylist##1{%
+ \ifXKV@st
+ \long\expandafter\def\expandafter\SKV@tempa\expandafter{##1}%
+ \else
+ \long\def\SKV@tempa{##1}%
+ \fi
+ \SKV@expandargs{3}\SKV@checksanitizec{{\SKV@expandox{\SKV@tempa}}}%
+ \SKV@tempa\SKV@nil
+ \def\SKV@nob{\z@}%
+ \expandafter\SKV@readkeylist\SKV@tempa#1\SKV@nil
+ }%
+ \long\def\SKV@readkeylist##1#1##2\SKV@nil{%
+ \SKV@ifblank{##1}\relax
+ {%
+ \SKV@ifstrequal{##1}{\stopread}{%
+ \def\SKV@nob{\@ne}%
+ \stopread##2\SKV@nil
+ }{%
+ \SKV@define@mult@keys##1\SKV@nil
+ }%
+ }%
+ \ifnum\SKV@nob=\z@
+ \SKV@ifblank{##2}\relax{\SKV@readkeylist##2\SKV@nil}%
+ \fi
+ }%
+}
+\SKV@def\SKV@expandargs#1#2#3#4\SKV@nil{%
+ \begingroup
+ \protected@edef\SKV@tempa{\endgroup
+ \ifcase#1\relax
+ \unexpanded{#2}{#3}%
+ \or
+ \unexpanded{#2#3}{#4}%
+ \or
+ \unexpanded{#2}{#3}{#4}%
+ \or
+ \unexpanded{#2}#3\unexpanded{#4}%
+ \else
+ \SKV@err{Unknown expansion type '#1' for \string\SKV@expandargs}%
+ {Use the right expansion identifier (0 - 3)}%
+ \fi
+ }%
+ \SKV@tempa
+}
+\SKV@pdef\SKV@checkchoice#1#2#3#4{%
+ \SKV@expandargs{3}{\XKV@cc*+[\val\nr]}{{#1}{#2}}{{#3}{#4}}\SKV@nil
+}
+\SKV@pdef*\SKV@inputerr#1#2{%
+ \SKV@err{Erroneous value '#1' for key '#2'}{%
+ Please use the correct value for key '#2'.}%
+}
+\SKV@def\SKV@ifblank#1{\SKV@ifbl@nk#1\SKV@nil\SKV@nil\@secondoftwo\@firstoftwo:}
+\SKV@def\SKV@ifbl@nk#1#2\SKV@nil#3#4#5:{#4}
+\SKV@def\SKV@oifblank#1{\SKV@expandargs{0}\SKV@ifblank{\SKV@expandox{#1}}\SKV@nil}
+\SKV@def\SKV@xifblank#1{\SKV@expandargs{0}\SKV@ifblank{#1}\SKV@nil}
+\SKV@def\SKV@ifstrequal#1#2{%
+ \begingroup
+ \edef\SKV@tempa{\detokenize{#1}}%
+ \edef\SKV@tempb{\detokenize{#2}}%
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempb\SKV@tempb\SKV@nil
+ \ifx\SKV@tempa\SKV@tempb
+ \aftergroup\@firstoftwo
+ \else
+ \aftergroup\@secondoftwo
+ \fi
+ \endgroup
+}
+\SKV@def\SKV@oifstrequal#1#2{%
+ \@expandtwoargs\SKV@ifstrequal{\SKV@expandox{#1}}{\SKV@expandox{#2}}%
+}
+\SKV@def\SKV@xifstrequal#1#2{\@expandtwoargs\SKV@ifstrequal{#1}{#2}}
+\SKV@def\SKV@ifstrempty#1{%
+ \romannumeral-`\@\csname @\if @\detokenize{#1}@first\else
+ second\fi oftwo\endcsname
+}
+\SKV@def\SKV@oifstrempty#1{%
+ \SKV@expandargs{0}\SKV@ifstrempty{\SKV@expandox{#1}}\SKV@nil}
+\SKV@def\SKV@xifstrempty#1{\SKV@expandargs{0}\SKV@ifstrempty{#1}\SKV@nil}
+\SKV@def*\SKV@keylistparser@err{%
+ \SKV@err{Key list parser '\SKV@keyparser' not allowed}%
+ {Use semicolon (preferable) or colon as parser.}%
+}
+\define@boolkey+[KV]{skeyval}[SKV@]{xchoicelist}[true]{}{%
+ \SKV@inputerr{#1}{xchoicelist}%
+}
+\define@boolkey+[KV]{skeyval}[SKV@]{inputonce}[true]{}{%
+ \SKV@inputerr{#1}{inputonce}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{genparser}[,]{%
+ \@onelevel@sanitize\SKV@genparser
+ \SKV@expandargs{1}\KV@@sp@def\SKV@genparser\SKV@genparser\SKV@nil
+ \SKV@expandargs{0}\SKV@CommandGenParser\SKV@genparser\SKV@nil
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{keyparser}[;]{%
+ \@onelevel@sanitize\SKV@keyparser
+ \SKV@xifblank\SKV@keyparser\SKV@keylistparser@err\relax
+ \SKV@expandargs{1}\KV@@sp@def\SKV@keyparser\SKV@keyparser\SKV@nil
+ \begingroup
+ \edef\SKV@tempa{\detokenize{,}}%
+ \ifx\SKV@keyparser\SKV@tempa
+ \aftergroup\SKV@keylistparser@err
+ \fi
+ \endgroup
+ \SKV@expandargs{0}\SKV@CommandKeyParser\SKV@keyparser\SKV@nil
+}
+\SKV@def*\SKV@keyprefix@err{%
+ \SKV@err{Key prefix '\SKV@keyprefix' is not allowed}%
+ {Use another prefix instead of '\SKV@keyprefix'.}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{keyprefix}[KV]{%
+ \SKV@xifblank\SKV@keyprefix\SKV@keyprefix@err\relax
+ \SKV@expandargs{1}\KV@@sp@def\SKV@keyprefix\SKV@keyprefix\SKV@nil
+ \SKV@expandargs{3}\XKV@checksanitizeb{{\SKV@rkpnames}}\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \ifx\SKV@keyprefix\SKV@tempa\SKV@afterfi\SKV@keyprefix@err\fi
+ }%
+}
+\SKV@def*\SKV@keyfamily@err{%
+ \SKV@err{Key family '\SKV@keyfamily' is not allowed}%
+ {Use another family name instead of '\SKV@keyfamily'.}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{keyfamily}[fam]{%
+ \SKV@xifblank\SKV@keyfamily\SKV@keyfamily@err\relax
+ \SKV@expandargs{1}\KV@@sp@def\SKV@keyfamily\SKV@keyfamily\SKV@nil
+ \SKV@expandargs{3}\XKV@checksanitizeb{{\SKV@rfnames}}\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \ifx\SKV@keyfamily\SKV@tempa\SKV@afterfi\SKV@keyfamily@err\fi
+ }%
+}
+\SKV@def*\SKV@macroprefix@err{%
+ \SKV@err{Macro prefix '\SKV@macroprefix' is not allowed}%
+ {Use another macro prefix.}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{macroprefix}[mp@]{%
+ \SKV@xifblank\SKV@macroprefix\SKV@macroprefix@err\relax
+ \SKV@expandargs{1}\KV@@sp@def\SKV@macroprefix\SKV@macroprefix\SKV@nil
+ \SKV@expandargs{3}\XKV@checksanitizeb{{\SKV@rmpnames}}\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \ifx\SKV@macroprefix\SKV@tempa\SKV@afterfi\SKV@macroprefix@err\fi
+ }%
+}
+\DeclareOptionX*{\SKV@warn{Unknown option '\CurrentOption' ignored}}
+\ExecuteOptionsX[KV]<skeyval>{genparser,keyparser,keyprefix,
+ keyfamily,macroprefix,inputonce}
+\ProcessOptionsX*[KV]<skeyval>\relax
+\SKV@pdef*\skvoptions#1{\setkeys[KV]{skeyval}{#1}}
+\SKV@def*\SKV@despacelist#1#2{%
+ \SKV@CommandGenParser{#1}%
+ \let\SKV@tempa#2%
+ \let#2\@empty
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@apptomacro@b#2{\expandafter#1\SKV@tempa}%
+ }%
+ \ifx#2\@empty\else
+ \SKV@remparser{#1}#2%
+ \fi
+}
+\SKV@def\SKV@named@f#1#2{%
+ \ifcsname#2\endcsname
+ \expandafter\ifx\csname#2\endcsname\relax\else
+ \def\reserved@a{#2}%
+ \expandafter\expandafter\expandafter\@notdefinable
+ \fi
+ \else
+ \expandafter#1\csname#2\expandafter\endcsname
+ \fi
+}
+\SKV@def*\SKV@newnamedef#1{\SKV@named@f\def{#1}}
+\SKV@def*\SKV@newnamegdef#1{\SKV@named@f\gdef{#1}}
+\SKV@def*\SKV@newnameedef#1{\SKV@named@f\edef{#1}}
+\SKV@def*\SKV@newnamexdef#1{\SKV@named@f\xdef{#1}}
+\SKV@def*\SKV@namedef#1{\SKV@aftercsname\def{#1}}
+\SKV@def*\SKV@namegdef#1{\SKV@aftercsname\gdef{#1}}
+\SKV@def*\SKV@nameedef#1{\SKV@aftercsname\edef{#1}}
+\SKV@def*\SKV@namexdef#1{\SKV@aftercsname\xdef{#1}}
+\SKV@def*\SKV@nameuse#1{%
+ \ifcsname#1\endcsname\csname#1\expandafter\endcsname\fi}
+\SKV@def\SKV@ifnextchar#1#2#3{%
+ \let\SKV@@tempc=#1\def\SKV@@tempa{#2}\def\SKV@@tempb{#3}%
+ \futurelet\@temptoks\SKV@ifnextch@r
+}
+\SKV@def\SKV@ifnextch@r{%
+ \ifx\@temptoks\SKV@@tempc\let\SKV@@tempb\SKV@@tempa\fi
+ \SKV@@tempb
+}
+\SKV@def\SKV@testopt#1#2{\SKV@ifnextchar[{#1}{#1[{#2}]}}
+\SKV@def\SKV@ifstar#1#2{%
+ \SKV@ifnextchar*{\begingroup
+ \def\SKV@tempa*{\endgroup #1}\SKV@tempa}{#2}%
+}
+\SKV@def*\SKV@newlet#1#2{%
+ \SKV@ifdef#1{%
+ \SKV@err{Command '\string#1' already defined}{%
+ I can't let '\string#1' to '\string#2'.}%
+ }{%
+ \SKV@ifdef#2{%
+ \let#1#2%
+ }{%
+ \SKV@err{Command '\string#2' undefined}{%
+ I can't let '\string#1' to '\string#2'.}%
+ }%
+ }%
+}
+\SKV@pdef*\SKV@newtoks#1{\SKV@ifdefinable#1{\@nameuse{newtoks}#1}}
+\SKV@pdef*\SKV@newcount#1{\SKV@ifdefinable#1{\@nameuse{newcount}#1}}
+\SKV@pdef*\SKV@newdimen#1{\SKV@ifdefinable#1{\@nameuse{newdimen}#1}}
+\SKV@def*\nameletcs#1#2{%
+ \SKV@ifdef{#2}{%
+ \SKV@aftercsname\let{#1}#2%
+ }{%
+ \SKV@err{Command '\string#2' undefined}\@ehc
+ }%
+}
+\SKV@def*\csletname#1#2{%
+ \SKV@ifnamedef{#2}{%
+ \expandafter\let\expandafter#1\csname#2\endcsname
+ }{%
+ \SKV@err{Command '\@backslashchar#2' undefined}\@ehc
+ }%
+}
+\SKV@def*\nameletname#1#2{%
+ \SKV@ifnamedef{#2}{%
+ %\expandafter\let\csname#1\expandafter\endcsname\csname#2\endcsname
+ \SKV@aftercsname\let{#1\SKV@aftercsname}{#2}%
+ }{%
+ \SKV@err{Command '\@backslashchar#2' undefined}\@ehc
+ }%
+}
+\SKV@def*\@nameletcs#1#2{\SKV@aftercsname\let{#1}#2}
+\SKV@def*\@csletname#1#2{%
+ \begingroup\expandafter\endgroup
+ \expandafter\let\expandafter#1\csname#2\endcsname
+}
+\SKV@def*\@nameletname#1#2{%
+ \begingroup\expandafter\endgroup
+ \expandafter\let\csname#1\SKV@aftercsname\endcsname{#2}%
+}
+\SKV@pdef*\SKV@numdef#1#2{%
+ \SKV@findescape{#1}{}{\SKV@err{Backslash required in '#1'}\@ehc}%
+ \SKV@ifstrempty{#2}{\SKV@err{Empty argument for counter '#1'}\@ehc}{}%
+ \SKV@ifundef{#1}{%
+ \newcount#1#1=\numexpr#2\relax
+ }{%
+ #1=\numexpr#2\relax
+ }%
+}
+\SKV@pdef*\SKV@numnamedef#1{\SKV@aftercsname\SKV@numdef{#1}}
+\SKV@pdef*\SKV@numgdef#1#2{%
+ \SKV@findescape{#1}{}{\SKV@err{Backslash required in '#1'}\@ehc}%
+ \SKV@ifstrempty{#2}{\SKV@err{Empty argument for counter '#1'}\@ehc}{}%
+ \SKV@ifundef{#1}{%
+ \newcount#1\global#1=\numexpr#2\relax
+ }{%
+ \global#1=\numexpr#2\relax
+ }%
+}
+\SKV@pdef*\SKV@numnamegdef#1{\SKV@aftercsname\SKV@numgdef{#1}}
+\SKV@pdef*\SKV@dimdef#1#2{%
+ \SKV@findescape{#1}{}{\SKV@err{Backslash required in '#1'}\@ehc}%
+ \SKV@ifstrempty{#2}{\SKV@err{Empty argument for dimension '#1'}\@ehc}{}%
+ \SKV@ifundef{#1}{%
+ \newdimen#1#1=\dimexpr#2\relax
+ }{%
+ #1=\dimexpr#2\relax
+ }%
+}
+\SKV@pdef*\SKV@dimnamedef#1{\SKV@aftercsname\SKV@dimdef{#1}}
+\SKV@pdef*\SKV@dimgdef#1#2{%
+ \SKV@findescape{#1}{}{\SKV@err{Backslash required in '#1'}\@ehc}%
+ \SKV@ifstrempty{#2}{\SKV@err{Empty argument for dimension '#1'}\@ehc}{}%
+ \SKV@ifundef{#1}{%
+ \newdimen#1\global#1=\dimexpr#2\relax
+ }{%
+ \global#1=\dimexpr#2\relax
+ }%
+}
+\SKV@pdef*\SKV@dimnamegdef#1{\SKV@aftercsname\SKV@dimgdef{#1}}
+\SKV@pdef*\define@compboolkeys{%
+ \let\SKV@def@boolkey\define@boolkey
+ \SKV@testopt{\SKV@compbool@opta}{KV}%
+}
+\SKV@pdef*\newcompboolkeys{%
+ \let\SKV@def@boolkey\newboolkey
+ \SKV@testopt{\SKV@compbool@opta}{KV}%
+}
+\SKV@def*\SKV@compbool@opta[#1]#2{%
+ \SKV@testopt{\SKV@define@compboolkeys[#1]{#2}}{mp@}}
+\SKV@def\SKV@define@compboolkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \SKV@namedef{#1@#2@#4@func}{%
+ #7\SKV@nameuse{if#3#4}\SKV@nameuse{#3#6false}\else
+ \SKV@nameuse{#3#6true}\fi}%
+ \SKV@namedef{#1@#2@#6@func}{%
+ #8\SKV@nameuse{if#3#6}\SKV@nameuse{#3#4false}\else
+ \SKV@nameuse{#3#4true}\fi}%
+ \begingroup\protected@edef\SKV@tempa{\endgroup
+ \unexpanded{%
+ \SKV@def@boolkey+[#1]{#2}[#3]{#4}[#5]{%
+ \SKV@nameuse{#1@#2@#4@func}%
+ }{%
+ \SKV@inputerr{##1}{#4}%
+ }%
+ \SKV@def@boolkey+[#1]{#2}[#3]{#6}[#5]{%
+ \SKV@nameuse{#1@#2@#6@func}%
+ }{%
+ \SKV@inputerr{##1}{#6}%
+ }%
+ }%
+ }%
+ \SKV@tempa
+}
+\SKV@def\SKV@star@or@long#1{%
+ \SKV@ifstar{%
+ \let\l@ngrel@x\relax
+ \def\SKV@star@or@none{*}#1%
+ }{%
+ \let\l@ngrel@x\long
+ \def\SKV@star@or@none{}#1%
+ }%
+}
+\SKV@pdef\requirecmd{\SKV@star@or@long\SKV@require@cmd}
+\SKV@def\SKV@require@cmd#1{%
+ \ifdefined#1%
+ \SKV@afterelsefi
+ \expandafter\CheckCommand\SKV@star@or@none
+ \else
+ \SKV@afterfi
+ \expandafter\newcommand\SKV@star@or@none
+ \fi
+ {#1}%
+}
+\def\@check@eq#1#2{%
+ \unless\ifx#1#2%
+ \SKV@warn{%
+ Previous definition of \string#1\MessageBreak
+ doesn't match your new definition.\MessageBreak
+ *** I haven't redefined \string#1\space ***
+ }%
+ \fi
+}
+\SKV@pdef*\SKV@undeftoggle@err#1{%
+ \SKV@err{Toggle '#1' undefined}%
+ {You need to first define '#1' before use.}%
+}
+\SKV@pdef*\deftog#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \SKV@warn{Toggle '#1' redefined\on@line}%
+ }{}%
+ \nameletcs{SKV@toggle@#1}\@secondoftwo
+}
+\SKV@pdef*\newtog#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \SKV@err{Toggle '#1' already defined}%
+ {Please provide a new toggle or redefine '#1'.}%
+ }{%
+ \nameletcs{SKV@toggle@#1}\@secondoftwo
+ }%
+}
+\SKV@pdef*\providetog#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \SKV@info{Toggle '#1' already defined.\MessageBreak
+ Not redefined\on@line}%
+ }{%
+ \nameletcs{SKV@toggle@#1}\@secondoftwo
+ }%
+}
+\SKV@pdef*\requiretog#1{%
+ \SKV@aftercsname\requirecmd{SKV@toggle@#1}[2]{##2}%
+}
+\SKV@pdef*\settog#1#2{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \SKV@ifnamedef{SKV@t@ggle#2}{%
+ \nameletname{SKV@toggle@#1}{SKV@t@ggle#2}%
+ }{%
+ \SKV@err{%
+ Inadmissible value '#2' for toggle '#1'
+ }{%
+ Valid values for toggles are 'true' and 'false'.
+ }%
+ }%
+ }{%
+ \SKV@undeftoggle@err{#1}%
+ }%
+}
+\SKV@pdef*\togtrue#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \nameletcs{SKV@toggle@#1}\SKV@t@ggletrue
+ }{%
+ \SKV@undeftoggle@err{#1}%
+ }%
+}
+\SKV@pdef*\togfalse#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \nameletcs{SKV@toggle@#1}\SKV@t@gglefalse
+ }{%
+ \SKV@undeftoggle@err{#1}%
+ }%
+}
+\SKV@newlet\SKV@t@ggletrue\@firstoftwo
+\SKV@newlet\SKV@t@gglefalse\@secondoftwo
+\SKV@pdef*\iftog#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \@nameuse{SKV@toggle@#1}%
+ }{%
+ \SKV@undeftoggle@err{#1}%
+ }%
+}
+\SKV@pdef*\ifnottog#1{%
+ \SKV@ifnamedef{SKV@toggle@#1}{%
+ \@nameuse{SKV@toggle@#1}\@secondoftwo\@firstoftwo
+ }{%
+ \SKV@undeftoggle@err{#1}\@gobbletwo
+ }%
+}
+\SKV@pdef*\SKV@definedkey@err#1{%
+ \SKV@ifnamedef{\XKV@header#1}{%
+ \SKV@err{%
+ Key '#1' already defined in family '\XKV@tfam'
+ }{%
+ Use another key name for '#1'.
+ }%
+ }{}%
+}
+\SKV@pdef*\define@togkey{\XKV@t@stopta{\XKV@testoptd\SKV@define@togkey{}}}
+\SKV@def*\SKV@define@togkey#1#2[#3]{%
+ \SKV@reservedkey@err{#2}%
+ \SKV@suspendedkey@err{#2}%
+ \ifXKV@pl
+ \SKV@afterelsefi
+ \expandafter\SKV@d@f@ne@togkey
+ \else
+ \SKV@afterfi
+ \expandafter\SKV@d@fine@togkey
+ \fi
+ \csname\XKV@header#2\endcsname{#2}{#1#2}{#3}%
+}
+\SKV@def*\SKV@d@fine@togkey#1#2#3#4#5{%
+ \SKV@d@f@ne@t@gkey#1{#2}{#3}{#4}%
+ {{\settog{#3}{\XKV@resa}#5}}%
+}
+\SKV@def*\SKV@d@f@ne@togkey#1#2#3#4#5#6{%
+ \SKV@d@f@ne@t@gkey#1{#2}{#3}{#4}%
+ {{\settog{#3}{\XKV@resa}#5}{#6}}%
+}
+\SKV@def*\SKV@d@f@ne@t@gkey#1#2#3#4#5{%
+ \deftog{#3}%
+ \ifXKV@st\XKV@define@default{#2}{#4}\fi
+ \ifXKV@pl
+ \def#1##1{\XKV@pltrue\XKV@sttrue
+ \XKV@checkchoice[\XKV@resa]{##1}{true,false}#5%
+ }%
+ \else
+ \def#1##1{\XKV@plfalse\XKV@sttrue
+ \XKV@checkchoice[\XKV@resa]{##1}{true,false}#5%
+ }%
+ \fi
+}
+\SKV@pdef*\define@togkeys{%
+ \XKV@plfalse\XKV@testoptd\SKV@define@togkeys{}}
+\SKV@def*\SKV@define@togkeys#1#2[#3]{%
+ \XKV@sp@deflist\SKV@tempa{#2}%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@expandargs{3}\SKV@d@fine@togkeys{{\SKV@tempa}}{{#1}{#3}}\SKV@nil
+ }%
+}
+\SKV@def*\SKV@d@fine@togkeys#1#2#3{%
+ \SKV@aftercsname\SKV@d@f@ne@t@gkey{\XKV@header#1}%
+ {#1}{#2#1}{#3}{{\settog{#2#1}{\XKV@resa}}}%
+}
+\SKV@pdef*\newordkey{\XKV@testoptb\SKV@newordkey}
+\SKV@def*\SKV@newordkey#1{%
+ \SKV@definedkey@err{#1}%
+ \SKV@ifnextchar[{\XKV@d@fine@k@y{#1}}%
+ {\SKV@namedef{\XKV@header#1}####1}%
+}
+\SKV@pdef*\newcmdkey{\XKV@testoptd\SKV@newcmdkey{cmd}}
+\SKV@def*\SKV@newcmdkey#1#2[#3]#4{%
+ \SKV@definedkey@err{#2}%
+ \ifXKV@st\XKV@define@default{#2}{#3}\fi
+ \edef\SKV@tempa{\noexpand\def\@nameuse{\XKV@header#2}####1}%
+ \edef\SKV@tempb{\noexpand\def\@nameuse{#1#2}\unexpanded{{##1}#4}}%
+ \expandafter\SKV@tempa\expandafter{\SKV@tempb}%
+ \SKV@undef\SKV@tempa\SKV@undef\SKV@tempb
+}
+\SKV@pdef*\newcmdkeys{\XKV@testoptd\SKV@newcmdkeys{cmd}}
+\SKV@def*\SKV@newcmdkeys#1#2[#3]{%
+ \XKV@sp@deflist\SKV@tempa{#2}%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \edef\SKV@tempa{\noexpand\SKV@newcmdkey{#1}{\SKV@tempa}}%
+ \SKV@tempa[#3]{}%
+ }%
+}
+\SKV@pdef*\newchoicekey{\XKV@testopta{\XKV@testoptb\SKV@newchoicekey}}
+\SKV@def*\SKV@newchoicekey#1{%
+ \SKV@definedkey@err{#1}%
+ \@testopt{\XKV@d@fine@choicekey{#1}}{}%
+}
+\SKV@pdef*\newboolkey{\XKV@t@stopta{\XKV@testoptd\SKV@newboolkey{}}}
+\SKV@def*\SKV@newboolkey#1#2[#3]{%
+ \SKV@definedkey@err{#2}%
+ \ifXKV@pl
+ \SKV@afterelsefi
+ \expandafter\XKV@d@f@ne@boolkey
+ \else
+ \SKV@afterfi
+ \expandafter\XKV@d@fine@boolkey
+ \fi
+ \csname\XKV@header#2\endcsname{#2}{#1#2}{#3}%
+}
+\SKV@pdef*\newboolkeys{\XKV@plfalse\XKV@testoptd\SKV@newboolkeys{}}
+\SKV@def*\SKV@newboolkeys#1#2[#3]{%
+ \XKV@sp@deflist\SKV@tempa{#2}%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@definedkey@err\SKV@tempa
+ \SKV@expandargs{3}\XKV@d@fine@boolkeys{{\SKV@tempa}}{{#1}{#3}}\SKV@nil
+ }%
+}
+\SKV@pdef*\newtogkey{\XKV@t@stopta{\XKV@testoptd\SKV@newtogkey{}}}
+\SKV@def*\SKV@newtogkey#1#2[#3]{%
+ \SKV@definedkey@err{#2}%
+ \ifXKV@pl
+ \SKV@afterelsefi
+ \expandafter\SKV@d@f@ne@togkey
+ \else
+ \SKV@afterfi
+ \expandafter\SKV@d@fine@togkey
+ \fi
+ \csname\XKV@header#2\endcsname{#2}{#1#2}{#3}%
+}
+\SKV@pdef*\newtogkeys{\XKV@plfalse\XKV@testoptd\SKV@newtogkeys{}}
+\SKV@def*\SKV@newtogkeys#1#2[#3]{%
+ \XKV@sp@deflist\SKV@tempa{#2}%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@definedkey@err\SKV@tempa
+ \SKV@expandargs{3}\SKV@d@fine@togkeys{{\SKV@tempa}}{{#1}{#3}}\SKV@nil
+ }%
+}
+\SKV@pdef*\define@comptogkeys{%
+ \let\SKV@def@togkey\define@togkey
+ \SKV@testopt{\SKV@comptog@opta}{KV}%
+}
+\SKV@pdef*\newcomptogkeys{%
+ \let\SKV@def@togkey\newtogkey
+ \SKV@testopt{\SKV@comptog@opta}{KV}%
+}
+\SKV@def*\SKV@comptog@opta[#1]#2{%
+ \SKV@testopt{\SKV@define@comptogkeys[#1]{#2}}{mp@}}
+\SKV@def\SKV@define@comptogkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \SKV@namedef{#1@#2@#4@func}{%
+ #7\iftog{#3#4}{\togfalse{#3#6}}{\togtrue{#3#6}}}%
+ \SKV@namedef{#1@#2@#6@func}{%
+ #8\iftog{#3#6}{\togfalse{#3#4}}{\togtrue{#3#4}}}%
+ \begingroup\protected@edef\SKV@tempa{\endgroup
+ \unexpanded{%
+ \SKV@def@togkey+[#1]{#2}[#3]{#4}[#5]{%
+ \SKV@nameuse{#1@#2@#4@func}%
+ }{%
+ \SKV@inputerr{##1}{#4}%
+ }%
+ \SKV@def@togkey+[#1]{#2}[#3]{#6}[#5]{%
+ \SKV@nameuse{#1@#2@#6@func}%
+ }{%
+ \SKV@inputerr{##1}{#6}%
+ }%
+ }%
+ }%
+ \SKV@tempa
+}
+\SKV@pdef*\stopread#1\SKV@nil{\long\edef\SKV@remainder{\unexpanded{#1}}}
+\def\SKV@noa{\z@}\def\SKV@nob{\z@}\def\SKV@noc{\z@}
+\SKV@pdef*\define@keylist{%
+ \let\SKV@def@key\define@key
+ \let\SKV@def@cmdkey\define@cmdkey
+ \let\SKV@def@boolkey\define@boolkey
+ \let\SKV@def@togkey\define@togkey
+ \let\SKV@def@choicekey\define@choicekey
+ \SKV@ifstar{\XKV@sttrue\SKV@define@keylist}%
+ {\XKV@stfalse\SKV@define@keylist}%
+}
+\SKV@pdef*\newkeylist{%
+ \let\SKV@def@key\newordkey
+ \let\SKV@def@cmdkey\newcmdkey
+ \let\SKV@def@boolkey\newboolkey
+ \let\SKV@def@togkey\newtogkey
+ \let\SKV@def@choicekey\newchoicekey
+ \SKV@ifstar{\XKV@sttrue\SKV@define@keylist}%
+ {\XKV@stfalse\SKV@define@keylist}%
+}
+\SKV@def\ChoiceKeyValues#1#2{%
+ \ifSKV@xchoicelist
+ \SKV@nameedef{\SKV@keyprefix @\SKV@keyfamily @#1@altlist}{#2}%
+ \else
+ \SKV@ifnameundef{\SKV@keyprefix @\SKV@keyfamily @#1@altlist}{%
+ \SKV@newnameedef{\SKV@keyprefix @\SKV@keyfamily @#1@altlist}{#2}%
+ }{%
+ \SKV@err{%
+ You have attempted to set two \MessageBreak
+ \string\ChoiceKeyValues\space for the choice\MessageBreak
+ key '#1' in the same family '\SKV@keyfamily'
+ }{%
+ You can only do that if you set 'xchoicelist'=true.
+ }%
+ }%
+ \fi
+}
+\SKV@newlet\CKVS\ChoiceKeyValues
+\SKV@def*\SKV@detok@z@p#1{%
+ \edef#1{\expandafter\detokenize\expandafter{#1}\space}%
+ \edef#1{\expandafter\zap@space#1\@empty}%
+}
+\SKV@def*\SKV@detok@zsp#1{%
+ \begingroup
+ \def\SKV@no{\z@}%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b#1\SKV@tempa{%
+ \edef\SKV@no{\the\numexpr\SKV@no+\@ne}%
+ \edef\SKV@tempa{\expandafter\detokenize\expandafter{\SKV@tempa}\space}%
+ \edef\SKV@tempa{\expandafter\zap@space\SKV@tempa\@empty}%
+ \SKV@namexdef{SKV@zsp\SKV@no}{\SKV@expandox{\SKV@tempa}}%
+ }%
+ \endgroup
+}
+\SKV@def*\SKV@detok@dsp#1{%
+ \begingroup
+ \def\SKV@no{\z@}%
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b#1\SKV@tempa{%
+ \edef\SKV@no{\the\numexpr\SKV@no+\@ne}%
+ \edef\SKV@tempa{\expandafter\detokenize\expandafter{\SKV@tempa}}%
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@namexdef{SKV@dsp\SKV@no}{\SKV@expandox{\SKV@tempa}}%
+ }%
+ \endgroup
+}
+\SKV@def*\SKV@if@err{%
+ \SKV@err{You can't use '\protect\if' and '\protect\fi' in key macro}%
+ {Use '\protect\fif' and '\protect\ffi' instead.}%
+}
+\SKV@def\SKV@define@mult@keys#1,#2,#3,#4\SKV@nil{%
+ \begingroup
+ \SKV@ifblank{#4}{}{%
+ \def\SKV@tempa{\if,\fi,\fif}%
+ \SKV@detok@dsp\SKV@tempa
+ \def\SKV@tempb{#4}\SKV@detok@z@p\SKV@tempb
+ \@expandtwoargs\in@{\@nameuse{SKV@dsp1}}\SKV@tempb
+ \ifin@\SKV@afterfi\SKV@if@err\fi
+ \@expandtwoargs\in@{\@nameuse{SKV@dsp3}}\SKV@tempb
+ \ifin@
+ \SKV@afterelsefi
+ \SKV@namegdef{\SKV@keyprefix @\SKV@keyfamily @#2@func}{#4}%
+ \else
+ \SKV@afterfi
+ \SKV@namexdef{\SKV@keyprefix @\SKV@keyfamily @#2@func}{\SKV@expandox{#4}}%
+ \fi
+ }%
+ \protected@edef\SKV@tempa{\endgroup
+ \ifcase#1\relax
+ \def\SKV@noc{\@ne}%
+ \or
+ \noexpand\SKV@def@key[\SKV@keyprefix]{\SKV@keyfamily}%
+ {#2}[#3]{%
+ \noexpand\SKV@nameuse{\SKV@keyprefix @\SKV@keyfamily @#2@func}%
+ }%
+ \or
+ \noexpand\SKV@def@cmdkey[\SKV@keyprefix]{\SKV@keyfamily}%
+ [\SKV@macroprefix]{#2}[#3]{%
+ \noexpand\SKV@nameuse{\SKV@keyprefix @\SKV@keyfamily @#2@func}%
+ }%
+ \or
+ \noexpand\SKV@def@boolkey+[\SKV@keyprefix]{\SKV@keyfamily}%
+ [\SKV@macroprefix]{#2}[#3]{%
+ \noexpand\SKV@nameuse{\SKV@keyprefix @\SKV@keyfamily @#2@func}%
+ }{%
+ \unexpanded{\SKV@inputerr{##1}{#2}}%
+ }%
+ \or
+ \noexpand\SKV@def@togkey+[\SKV@keyprefix]{\SKV@keyfamily}%
+ [\SKV@macroprefix]{#2}[#3]{%
+ \noexpand\SKV@nameuse{\SKV@keyprefix @\SKV@keyfamily @#2@func}%
+ }{%
+ \unexpanded{\SKV@inputerr{##1}{#2}}%
+ }%
+ \or
+ \SKV@ifnameundef{\SKV@keyprefix @\SKV@keyfamily @#2@altlist}{%
+ \def\SKV@noa{\@ne}%
+ }{}%
+ \noexpand\SKV@def@choicekey*+[\SKV@keyprefix]{\SKV@keyfamily}{#2}%
+ [\unexpanded{\val\nr}]{%
+ \SKV@nameuse{\SKV@keyprefix @\SKV@keyfamily @#2@altlist}%
+ }[#3]{%
+ \noexpand\SKV@nameuse{\SKV@keyprefix @\SKV@keyfamily @#2@func}%
+ }{%
+ \unexpanded{\SKV@inputerr{##1}{#2}}%
+ }%
+ \else
+ \def\SKV@noc{\@ne}%
+ \fi
+ }%
+ \SKV@tempa
+ \ifnum\SKV@noa=\@ne
+ \SKV@afterfi
+ \SKV@err{%
+ Choice key '#2' can't be defined.\MessageBreak
+ Alternate key values list for '#2' is empty
+ }{%
+ You need to first define admissible\MessageBreak
+ key values through '\string\ChoiceKeyValues'\MessageBreak
+ for choice key '#2'.
+ }%
+ \fi
+ \ifnum\SKV@noc=\@ne
+ \SKV@afterfi
+ \SKV@err{Unknown key type/identifier '#1'}%
+ {You can only use key types 1 to 5.}%
+ \fi
+}
+\SKV@pdef*\in@tog#1#2{%
+ \def\in@@##1#1##2##3\in@@{%
+ \ifx\in@##2\togfalse{in@}\else\togtrue{in@}\fi
+ }%
+ \in@@#2#1\in@\in@@
+}
+\newtog{in@}
+\SKV@pdef*\in@tok#1#2{%
+ \begingroup
+ \edef\SKV@tempa{\detokenize{#1}}%
+ \edef\SKV@tempb{\detokenize{#2}}%
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempb\SKV@tempb\SKV@nil
+ \SKV@expandargs{3}{\def\in@@##1}\SKV@tempa{%
+ ##2##3\in@@{\global\ifx\in@##2\in@false\else\in@true\fi}%
+ }\SKV@nil
+ \SKV@expandargs{3}\in@@{\SKV@tempb\SKV@tempa}{\in@\in@@}\SKV@nil
+ \endgroup
+}
+\def\XKV@makepf#1{%
+ \KV@@sp@def\XKV@prefix{#1}%
+ \SKV@expandargs{3}\XKV@checksanitizeb{{\SKV@rkpnames}}\SKV@tempa\SKV@nil
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \XKV@knftrue
+ \XKV@whilist\SKV@tempa\SKV@tempa\ifXKV@knf\fi{%
+ \ifx\XKV@prefix\SKV@tempa\XKV@knffalse\fi
+ }%
+ \unless\ifXKV@knf
+ \SKV@afterfi
+ \SKV@err{Prefix '\SKV@tempa' is not allowed}%
+ {Use another prefix instead of '\SKV@tempa'}%
+ \fi
+ \edef\SKV@pref{\ifx\XKV@prefix\@empty\else\XKV@prefix\fi}%
+ \edef\XKV@prefix{\ifx\XKV@prefix\@empty\else\XKV@prefix @\fi}%
+}
+\def\XKV@makehd#1{%
+ \SKV@expandargs{1}\KV@@sp@def\XKV@header{#1}\SKV@nil
+ \SKV@expandargs{3}\XKV@checksanitizeb{{\SKV@rfnames}}\SKV@tempa\SKV@nil
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \XKV@knftrue
+ \XKV@whilist\SKV@tempa\SKV@tempa\ifXKV@knf\fi{%
+ \ifx\XKV@header\SKV@tempa\XKV@knffalse\fi
+ }%
+ \unless\ifXKV@knf
+ \SKV@afterfi
+ \SKV@err{Family '\SKV@tempa' is not allowed}%
+ {Use another family instead of '\SKV@tempa'}%
+ \fi
+ \edef\XKV@header{%
+ \XKV@prefix\ifx\XKV@header\@empty\else\XKV@header @\fi}%
+}
+\def\XKV@define@key#1{%
+ \SKV@reservedkey@err{#1}%
+ \SKV@suspendedkey@err{#1}%
+ \SKV@ifnextchar[{\XKV@d@fine@k@y{#1}}{\SKV@d@fine@k@y{#1}}%
+}
+\def\XKV@d@fine@k@y#1[#2]#3{%!
+ \XKV@define@default{#1}{#2}%
+ \SKV@namedef{\XKV@header#1}##1{#3}%
+}
+\def\SKV@d@fine@k@y#1#2{\SKV@namedef{\XKV@header#1}##1{#2}}
+\def\XKV@define@cmdkey#1#2[#3]#4{%
+ \SKV@reservedkey@err{#2}%
+ \SKV@suspendedkey@err{#2}%
+ \ifXKV@st\XKV@define@default{#2}{#3}\fi
+ \edef\SKV@tempa{\noexpand\def\@nameuse{\XKV@header#2}####1}%
+ \edef\SKV@tempb{\noexpand\def\@nameuse{#1#2}\unexpanded{{##1}#4}}%
+ \expandafter\SKV@tempa\expandafter{\SKV@tempb}%
+ \SKV@undef\SKV@tempa\SKV@undef\SKV@tempb
+}
+\def\XKV@define@choicekey#1{%
+ \SKV@reservedkey@err{#1}%
+ \SKV@suspendedkey@err{#1}%
+ \@testopt{\XKV@d@fine@choicekey{#1}}{}%
+}
+\def\XKV@define@boolkey#1#2[#3]{%
+ \SKV@reservedkey@err{#2}%
+ \SKV@suspendedkey@err{#2}%
+ \ifXKV@pl
+ \SKV@afterelsefi\expandafter\XKV@d@f@ne@boolkey
+ \else
+ \SKV@afterfi\expandafter\XKV@d@fine@boolkey
+ \fi
+ \csname\XKV@header#2\endcsname{#2}{#1#2}{#3}%
+}
+\SKV@pdef*\reserve@keys{\@testopt\SKV@reserve@keys{KV}}
+\SKV@def*\SKV@reserve@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@res@rve@keys\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@res@rve@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@res@rve@k@ys{#3}%
+ }%
+}
+\SKV@def*\SKV@res@rve@k@ys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifnamedef{\XKV@header\SKV@tempa}{%
+ \SKV@err{%
+ Key '\SKV@tempa' with prefix '\SKV@pref' in family
+ \MessageBreak '\XKV@tfam' is already defined
+ }{%
+ Key '\SKV@tempa' in family '\XKV@tfam' can't be reserved.
+ \MessageBreak You may wish to remove it before reserving it.
+ \MessageBreak In that case, you can use '\string\remove@keys'.
+ }%
+ }{%
+ \SKV@nameedef{\XKV@header\SKV@tempa}{%
+ \SKV@err{%
+ Key '\SKV@tempa' with prefix '\SKV@pref' in family '\XKV@tfam'
+ \MessageBreak was reserved\on@line
+ }{%
+ Unreserve '\SKV@tempa' before use.
+ }%
+ }%
+ \SKV@namedef{\XKV@header\SKV@tempa @reser}{}%
+ }%
+ }%
+}
+\let\SKV@no\@empty
+\SKV@pdef\SKV@aftergroup{%
+ \SKV@ifstar{\SKV@aft@rgroup\@firstofone}{\SKV@aft@rgroup\unexpanded}%
+}
+\SKV@def\SKV@aft@rgroup#1#2{%
+ \edef\SKV@no{\the\numexpr\SKV@no+1}%
+ \SKV@namexdef{SKV@aft@rgr@up\SKV@no}{%
+ \SKV@namegundef{SKV@aft@rgr@up\SKV@no}%
+ #1{#2}%
+ }%
+ \SKV@aftercsname\aftergroup{SKV@aft@rgr@up\SKV@no}%
+}
+\SKV@pdef\SKV@afterassignment{%
+ \SKV@ifstar{\SKV@aft@rassignment\@firstofone}%
+ {\SKV@aft@rassignment\unexpanded}%
+}
+\SKV@def\SKV@aft@rassignment#1#2{%
+ \begingroup
+ \edef\SKV@no{\the\numexpr\SKV@no+1}%
+ \SKV@namexdef{SKV@aft@rassignm@nt\SKV@no}{%
+ \SKV@namegundef{SKV@aft@rassignm@nt\SKV@no}%
+ #1{#2}%
+ }%
+ \expandafter\endgroup\expandafter\afterassignment
+ \csname SKV@aft@rassignm@nt\SKV@no\endcsname
+}
+\SKV@def*\SKV@reservedkey@err#1{%
+ \SKV@ifnamedef{\XKV@header#1@reser}{%
+ \let\next\SKV@err
+ }{%
+ \let\next\@gobbletwo
+ }%
+ \next{%
+ Key '#1' with prefix '\SKV@pref'\MessageBreak
+ is reserved in family '\XKV@tfam'
+ }{%
+ Unreserve '#1' before use.
+ }%
+}
+\SKV@def*\ifkeyreserved{\@testopt\SKV@ifkeyreserved{KV}}
+\SKV@def*\SKV@ifkeyreserved[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \XKV@knftrue
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@ifkey@reserved\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+ \ifXKV@knf
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+\SKV@def*\SKV@ifkey@reserved#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \KV@@sp@def\XKV@tkey{#3}%
+ \XKV@whilist\XKV@fams\XKV@tfam\ifXKV@knf\fi{%
+ \XKV@makehd\XKV@tfam
+ \SKV@ifnamedef{\XKV@header\XKV@tkey @reser}{\XKV@knffalse}{}%
+ }%
+}
+\SKV@def*\ifkeysuspended{\@testopt\SKV@ifkeysuspended{KV}}
+\SKV@def*\SKV@ifkeysuspended[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \XKV@knftrue
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@ifkey@suspended\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+ \ifXKV@knf
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+\SKV@def*\SKV@ifkey@suspended#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \KV@@sp@def\XKV@tkey{#3}%
+ \XKV@whilist\XKV@fams\XKV@tfam\ifXKV@knf\fi{%
+ \XKV@makehd\XKV@tfam
+ \SKV@ifnamedef{\XKV@header\XKV@tkey @sus}{\XKV@knffalse}{}%
+ }%
+}
+\SKV@def*\ifkeydefined{\@testopt\SKV@ifkeydefined{KV}}
+\SKV@def*\SKV@ifkeydefined[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \XKV@knftrue
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@ifk@ydefined\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+ \ifXKV@knf
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+\SKV@def*\SKV@ifk@ydefined#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \KV@@sp@def\XKV@tkey{#3}%
+ \XKV@whilist\XKV@fams\XKV@tfam\ifXKV@knf\fi{%
+ \XKV@makehd\XKV@tfam
+ \SKV@ifnamedef{\XKV@header\XKV@tkey}{\XKV@knffalse}{}%
+ }%
+}
+\SKV@def*\SKV@disabledkey@err{%
+ \SKV@err{%
+ Key '\SKV@disabledkey' with prefix '\SKV@pref' in family
+ \MessageBreak '\XKV@tfam' was disabled\on@line
+ }{%
+ You can't set or reset '\SKV@disabledkey' at this\MessageBreak
+ late stage. Perhaps you're required to set it \MessageBreak
+ earlier, in the document's preamble.
+ }%
+}
+\protected\def\disable@keys{%
+ \SKV@ifstar{\@testopt\XKV@disable@keys{KV}}%
+ {\@testopt\SKV@disable@keys{KV}}%
+}
+\SKV@def*\SKV@disable@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@dis@ble@keys\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@dis@ble@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@dis@ble@k@ys{#3}%
+ }%
+}
+\SKV@def*\SKV@dis@ble@k@ys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifnameundef{\XKV@header\SKV@tempa}{%
+ \SKV@warn{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \MessageBreak is undefined in family '\XKV@tfam':
+ \MessageBreak can't be disabled\on@line}%
+ }{%
+ \SKV@dis@ble@k@y@\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@dis@ble@k@y@#1{%
+ \edef\SKV@disabledkey{#1}%
+ \SKV@ifnameundef{\XKV@header#1@default}{%
+ \edef#1{\noexpand\XKV@define@key{#1}}%
+ }{%
+ \edef#1{\noexpand\XKV@define@key{#1}[]}%
+ }%
+ \SKV@expandargs{0}#1\SKV@disabledkey@err\SKV@nil
+ \SKV@info{Key '\SKV@disabledkey' with prefix '\SKV@pref' in family '\XKV@tfam'
+ \MessageBreak was disabled\on@line}%
+}
+\SKV@def*\SKV@suspendedkey@err#1{%
+ \SKV@ifnamedef{\XKV@header#1@sus}{%
+ \SKV@err{%
+ Key '#1' was suspended from family '\XKV@tfam'
+ }{%
+ You can use \string\restore@key\space to restore '#1'.
+ }%
+ }{}%
+}
+\SKV@def*\SKV@suspendedkey@e@r{%
+ \SKV@err{%
+ Key '\SKV@suspendedkey' in family '\XKV@tfam' was
+ \MessageBreak suspended\on@line
+ }{%
+ You can use \string\restore@key\space to restore '\SKV@suspendedkey'.
+ }%
+}
+\SKV@pdef*\suspend@keys{\@testopt\SKV@suspend@keys{KV}}
+\SKV@def*\SKV@suspend@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@s@spend@keys\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@s@spend@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@s@sp@nd@keys{#3}%
+ }%
+}
+\SKV@def*\SKV@s@sp@nd@keys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifnameundef{\XKV@header\SKV@tempa}{%
+ \SKV@warn{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \MessageBreak is undefined in family '\XKV@tfam':
+ \MessageBreak can't be suspended\on@line}%
+ }{%
+ \SKV@s@sp@nd@k@ys\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@s@sp@nd@k@ys#1{%
+ \SKV@ifnamedef{\XKV@header#1@sus}{%
+ \SKV@err{%
+ Key '#1' with prefix '\SKV@pref' was suspended from family '\XKV@tfam'
+ }{%
+ You can use \string\restore@key\space to restore '#1'.
+ }%
+ }{%
+ \edef\SKV@suspendedkey{#1}%
+ \global\nameletname{\XKV@header#1@sus}{\XKV@header#1}%
+ \SKV@nameedef{\XKV@header#1}{\SKV@suspendedkey@e@r}%
+ \SKV@info{Key '\SKV@suspendedkey' with prefix '\SKV@pref' in
+ \MessageBreak family '\XKV@tfam' was suspended\on@line}%
+ }%
+}
+\SKV@pdef*\restore@keys{\@testopt\SKV@restore@keys{KV}}
+\SKV@def*\SKV@restore@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@r@store@keys\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@r@store@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@r@st@re@keys{#3}%
+ }%
+}
+\SKV@def*\SKV@r@st@re@keys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifnameundef{\XKV@header\SKV@tempa}{%
+ \SKV@warn{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \MessageBreak is undefined in family '\XKV@tfam':
+ \MessageBreak can't be restored\on@line}%
+ }{%
+ \SKV@r@st@re@k@ys\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@r@st@re@k@ys#1{%
+ \SKV@ifnameundef{\XKV@header#1@sus}{%
+ \SKV@err{Key '#1' wasn't suspended from family
+ \MessageBreak '\XKV@tfam': can't be restored\on@line}\@ehc
+ }{%
+ \edef\SKV@restoredkey{#1}%
+ \nameletname{\XKV@header#1}{\XKV@header#1@sus}%
+ \SKV@nameundef{\XKV@header#1@sus}%
+ \SKV@info{Key '\SKV@restoredkey' with prefix '\SKV@pref' in family
+ \MessageBreak '\XKV@tfam' restored\on@line}%
+ }%
+}
+\SKV@pdef*\remove@keys{\@testopt\SKV@remove@keys{KV}}
+\SKV@def*\SKV@remove@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@CommandGenParser{,}%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \expandafter\SKV@r@move@keys\expandafter{\SKV@tempa}{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@r@move@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@expandargs{1}\XKV@sp@deflist\XKV@fams\XKV@fams\SKV@nil
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@r@m@ve@keys{#3}%
+ }%
+}
+\SKV@def*\SKV@r@m@ve@keys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@expandargs{1}\XKV@sp@deflist\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifnameundef{\XKV@header\SKV@tempa}{%
+ \SKV@warn{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \MessageBreak is undefined in family '\XKV@tfam':
+ \MessageBreak I can't remove or unreserve it\on@line}%
+ }{%
+ \SKV@r@m@ve@k@ys\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@r@m@ve@k@ys#1{%
+ \begingroup
+ \edef\SKV@tempa{\XKV@header#1,\XKV@header#1@default,
+ \XKV@header#1@func,%\XKV@header#1@value,
+ \XKV@header#1@altlist,\XKV@header#1@reser
+ }%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@expandargs{1}\KV@@sp@def\SKV@tempa\SKV@tempa\SKV@nil
+ \SKV@namegundef{\SKV@tempa}%
+ }%
+ \endgroup
+ \SKV@info{Key '#1' with prefix '\SKV@pref' in family '\XKV@tfam'
+ \MessageBreak was removed\on@line}%
+}
+\SKV@newlet\unreserve@keys\remove@keys
+\def\setkeys{%
+ \def\fif##1{%
+ \SKV@findescape{##1}{%
+ \SKV@err{Bad argument '\string##1'}%
+ {Backslash in '\string##1' not allowed.}%
+ }{}%
+ \csname if##1\endcsname
+ }%
+ \let\ffi\fi
+ \XKV@testopta{\XKV@testoptc\XKV@setkeys}%
+}
+\def\XKV@setkeys[#1]#2{%
+ \XKV@checksanitizea{#2}\XKV@resb
+ \SKV@normalizea\XKV@resb
+ \let\XKV@naa\@empty
+ \XKV@for@o\XKV@resb\XKV@tempa{%
+ \expandafter\XKV@g@tkeyname\XKV@tempa=\@nil\XKV@tempa
+ \XKV@addtolist@x\XKV@naa\XKV@tempa
+ }%
+ \ifnum\XKV@depth=\z@\let\XKV@rm\@empty\fi
+ \XKV@usepresetkeys{#1}{preseth}%
+ \expandafter\XKV@s@tkeys\expandafter{\XKV@resb}{#1}%
+ \XKV@usepresetkeys{#1}{presett}%
+ \let\CurrentOption\@empty
+}
+\SKV@def*\SKV@remspaceletter#1#2{%
+ \begingroup
+ \XKV@toks\expandafter{#2 #1}%
+ \def\SKV@tempa##1 #1##2\SKV@nil{%
+ \SKV@ifblank{##2}{%
+ \XKV@toks{##1}%
+ }{%
+ \XKV@toks{##1#1##2}%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ }%
+ }%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ \xdef#2{\the\XKV@toks}%
+ \endgroup
+}
+\SKV@def*\SKV@remletterspace#1#2{%
+ \begingroup
+ \XKV@toks\expandafter{#2#1 }%
+ \def\SKV@tempa##1#1 ##2\SKV@nil{%
+ \SKV@ifblank{##2}{%
+ \XKV@toks{##1}%
+ }{%
+ \XKV@toks{##1#1##2}%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ }%
+ }%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ \xdef#2{\the\XKV@toks}%
+ \endgroup
+}
+\SKV@def*\SKV@remletterletter#1#2{%
+ \begingroup
+ \XKV@toks\expandafter{#2#1#1}%
+ \def\SKV@tempa##1#1#1##2\SKV@nil{%
+ \XKV@toks{##1#1##2}%
+ \SKV@ifblank{##2}{}{\expandafter\SKV@tempa\the\XKV@toks\SKV@nil}%
+ }%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ \def\SKV@tempa##1#1#1\SKV@nil{\gdef#2{##1}}%
+ \expandafter\SKV@tempa\the\XKV@toks#1\SKV@nil
+ \endgroup
+}
+\def\SKV@remcommaequal#1#2{%
+ \begingroup
+ \XKV@toks\expandafter{#2#1}%
+ \def\SKV@tempa##1#1##2\SKV@nil{%
+ \SKV@ifblank{##2}{%
+ \XKV@toks{##1}%
+ }{%
+ \XKV@toks{##1=##2}%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ }%
+ }%
+ \expandafter\SKV@tempa\the\XKV@toks\SKV@nil
+ \xdef#2{\the\XKV@toks}%
+ \endgroup
+}
+\SKV@def*\SKV@normalizea#1{%
+ \@expandtwoargs\in@{ ,}{\SKV@expandox{#1}}%
+ \ifin@\SKV@remspaceletter{,}#1\fi
+ \@expandtwoargs\in@{, }{\SKV@expandox{#1}}%
+ \ifin@\SKV@remletterspace{,}#1\fi
+ \@expandtwoargs\in@{,,}{\SKV@expandox{#1}}%
+ \ifin@\SKV@remletterletter{,}#1\fi
+ \@expandtwoargs\in@{ =}{\SKV@expandox{#1}}%
+ \ifin@\SKV@remspaceletter{=}#1\fi
+ \@expandtwoargs\in@{= }{\SKV@expandox{#1}}%
+ \ifin@\SKV@remletterspace{=}#1\fi
+ \@expandtwoargs\in@{==}{\SKV@expandox{#1}}%
+ \ifin@\SKV@remletterletter{=}#1\fi
+ \@expandtwoargs\in@{,=}{\SKV@expandox{#1}}%
+ \ifin@\SKV@remcommaequal{,=}#1\fi
+ \@expandtwoargs\in@{=,}{\SKV@expandox{#1}}%
+ \ifin@\SKV@remcommaequal{=,}#1\fi
+}
+\SKV@pdef\AtStartOfDocument{\AtBeginDocument}
+\SKV@pdef\BeforeStartOfDocument{\SKV@gapptomacro@a\SKV@beforestartdocument}
+\SKV@def*\SKV@beforestartdocument{}
+\SKV@preptomacro@a\document{%
+ \endgroup
+ \let\BeforeStartOfDocument\@firstofone
+ \SKV@beforestartdocument
+ \protected\long\def\BeforeStartOfDocument{\expandafter\@notprerr\@gobble}%
+ \SKV@undef\SKV@beforestartdocument
+ \begingroup
+}
+\SKV@pdef\AfterStartOfDocument{\SKV@gapptomacro@a\SKV@afterstartdocument}
+\SKV@def*\SKV@afterstartdocument{}
+\SKV@apptomacro@a\document{%
+ \let\AfterStartOfDocument\@firstofone
+ \SKV@afterstartdocument
+ \protected\long\def\AfterStartOfDocument{\expandafter\@notprerr\@gobble}%
+ \SKV@undef\SKV@afterstartdocument\ignorespaces
+}
+\SKV@def*\SKV@gobblescape{%
+ \ifnum\escapechar>255\else
+ \ifnum\escapechar<0\else
+ \expandafter\expandafter\csname @gobble\ifnum\escapechar=32 space\fi
+ \expandafter\expandafter\expandafter\endcsname
+ \fi\fi
+ \string
+}
+\SKV@def*\SKV@save#1{%
+ \SKV@findescape{#1}{}{\SKV@err{'#1' not a control sequence}\@ehc}
+ \SKV@ifnamedef{Saved\SKV@gobblescape#1}{%
+ \SKV@err{%
+ \string#1\space already saved. You've to restore\MessageBreak
+ it or undefine \SKV@noexpandcs{Saved\SKV@gobblescape#1}%
+ before\MessageBreak you can save \string#1\space again
+ }\@ehc
+ }{%
+ \nameletcs{Saved\SKV@gobblescape#1}{#1}%
+ }%
+}
+\SKV@def*\SKV@restore#1{%
+ \SKV@findescape{#1}{}{\SKV@err{'#1' not a control sequence}\@ehc}
+ \SKV@ifnamedef{Saved\SKV@gobblescape#1}{%
+ \csletname{#1}{Saved\SKV@gobblescape#1}%
+ \SKV@nameundef{Saved\SKV@gobblescape#1}%
+ }{%
+ \SKV@warn{%
+ \@nameuse{Saved\SKV@gobblescape#1} undefined: can't be restored\on@line.
+ \MessageBreak Note that each call of \string\SKV@restore\space undefines
+ \MessageBreak the saved command
+ }%
+ }%
+}
+\providecommand*\input@path{}
+\SKV@pdef*\InputFileOnce{%
+ \edef\SKV@no{\z@}\SKV@save\input@path
+ \SKV@testopt\SKV@InputFileOnce{.}%
+}
+\SKV@def*\SKV@InputFileOnce[#1]#2{%
+ \SKV@gapptomacro@a\input@path{{#1/}}%
+ \if X\SKV@nameuse{#2@read}\relax
+ \ifSKV@inputonce
+ \SKV@afterelsefi
+ \SKV@err{! File '#2' already read}{File '#2' can't be read again.}%
+ \fi
+ \else
+ \SKV@namegdef{#2@read}{X}%
+ \InputIfFileExists{#2}{}{%
+ \typein[\Answer]{^^J! File '\string#2' does not exist.^^J
+ Enter filename or 'n' and <return> to continue.}%
+ \if n\Answer\relax\else
+ \SKV@expandargs{0}{\SKV@InputFileOnce[#1]}\Answer\SKV@nil
+ \fi
+ }%
+ \fi
+ \ifnum\SKV@no=\z@\SKV@restore\input@path\fi
+ \edef\SKV@no{\@ne}%
+}
+
+\endinput
+
+%%% End of file skeyval.sty %%% \ No newline at end of file
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index d91c5ecba17..ebe818a38d8 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -256,7 +256,7 @@ my @TLP_working = qw(
shipunov shorttoc show2e showdim showexpl showlabels shuffle
SIstyle SIunits
sidecap sides siggraph silence simplecv simplewick siunitx
- skak skaknew slantsc slideshow smalltableof smartref
+ skak skaknew skeyval slantsc slideshow smalltableof smartref
snapshot songbook sort-by-letters soton soul
spanish spanish-mx sparklines spie
splines splitbib splitindex spotcolor spreadtab sprite spverbatim
diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
index 0e3df60ee1f..e95a8a15985 100644
--- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
@@ -529,6 +529,7 @@ depend sidecap
depend silence
depend simplecv
depend simplewick
+depend skeyval
depend slantsc
depend slashbox
depend smalltableof
diff --git a/Master/tlpkg/tlpsrc/skeyval.tlpsrc b/Master/tlpkg/tlpsrc/skeyval.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/skeyval.tlpsrc