Mike Gerwitz

Activist for User Freedom

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gerwitz <gerwitzm@lovullo.com>2014-05-08 12:08:01 -0400
committerMike Gerwitz <gerwitzm@lovullo.com>2014-05-08 12:08:01 -0400
commitcd285a2c4c890c978956731413233e6cd60ceca9 (patch)
tree359ca03a443b222eeadadbaa0ff5222c9c5e503c
parentd57cfeff8611f0001c9148033c90dd0b78d1f377 (diff)
downloadlvspec-cd285a2c4c890c978956731413233e6cd60ceca9.tar.gz
lvspec-cd285a2c4c890c978956731413233e6cd60ceca9.tar.bz2
lvspec-cd285a2c4c890c978956731413233e6cd60ceca9.zip
Extrated a number of rater-general specification logic from dwelling
-rw-r--r--raterspec.cls126
-rw-r--r--raterspec/c1import.sty32
-rw-r--r--raterspec/class.sty355
-rw-r--r--raterspec/form.sty53
-rw-r--r--raterspec/isoclass.sty26
-rw-r--r--raterspec/isoterr.sty16
-rw-r--r--raterspec/param.sty269
-rw-r--r--raterspec/question.sty62
-rw-r--r--raterspec/rates.sty44
9 files changed, 983 insertions, 0 deletions
diff --git a/raterspec.cls b/raterspec.cls
new file mode 100644
index 0000000..31292c2
--- /dev/null
+++ b/raterspec.cls
@@ -0,0 +1,126 @@
+% LoVullo rater specification class
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec}
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{lvspec}}
+\ProcessOptions\relax
+
+% we're an extension of the base lvspec
+\LoadClass[insuranceterms]{lvspec}
+
+%%
+% Default package includes
+%
+% Note that these are not all the packages that are available; see the
+% raterspec/ directory in the lvspec repo
+%
+\RequirePackage{raterspec/param}
+\RequirePackage{raterspec/class}
+\RequirePackage{raterspec/question}
+\RequirePackage{raterspec/rates}
+\RequirePackage{raterspec/form}
+\RequirePackage{raterspec/c1import}
+\RequirePackage{lvflow}
+%\RequirePackage{premcalc}
+
+
+%%
+% Formatting
+%
+
+% we gots some big section numbers
+\renewcommand\l@subsubsection{\@dottedtocline{3}{7em}{4.6em}}
+
+
+%%
+% Rater-specific specification additions
+%
+% This should be called before beginning the documet environment
+%
+\def\@RaterProgramName#1{
+ \gdef\@lvspec@pretitle{%
+ #1 Supplier\\Specifications:\\
+ \vspace{0.5em}%
+ }
+ \gdef\@lvspec@premarktitle{#1:\space}
+
+ \abstract{%
+ This document is a formal specification for the integration of
+ \@title@short{} with the Dwelling Program of the Quote Server, Program
+ UI and~ConceptOne. This document should contain all information
+ necessary to complete a conforming implementation with minimal
+ clarification and will serve as a reference for future development,
+ including bug fixes and feature requests.
+ }
+}
+
+\terminology{%
+ \subsection{Rater Terminology}
+ \input{dfn/rater}
+}
+
+
+
+%%
+% Code generation
+%
+% Right now the code generation is tightly coupled with the packages that it
+% is applicable to; they need to be refactored and hooks added
+\newwrite\@@codegen
+\immediate\openout\@@codegen=gen.xml
+
+\def\@codegen{%
+ \begingroup
+ % prepare common cases for plain-text output
+ \def\sref##1{the specification}%
+ \def~{ }%
+ \def\emph{}%
+ \def\nobreakspace{ }%
+ \def\${}%
+ \@do@codegen
+}
+\def\@do@codegen#1{%
+ \immediate\write\@@codegen{#1}%
+ \endgroup
+}
+
+
+%%
+% Misc
+%
+
+\def\@firstchar #1#2||{#1}
+\def\@secondchar #1#2#3||{#2}
+\def\@ifnumeric#1{{%
+ \edef\@@chk{\@firstchar#1||}%
+ % determine if this is a number
+ \def\@@result{0}%
+ % strip any negative sign
+ \ifnum\expandafter`\@@chk=`-
+ \edef\@@chk{\@secondchar#1--||}%
+ \fi
+ % perform number check
+ \ifnum\expandafter`\@@chk<`0\else
+ \ifnum\expandafter`\@@chk>`9\else
+ % is a number
+ \def\@@result{1}%
+ \fi
+ \fi
+ % use the result to output a conditional that will match a closing \fi
+ \aftergroup\ifnum
+ \expandafter\aftergroup\@@result
+ \aftergroup=%
+ \aftergroup1%
+ \aftergroup\relax
+}}
+
+
+\def\beginundersletter{%
+ \begingroup% ended by \@dotypedef
+ \catcode`\_=11\relax
+}
+\def\endundersletter{%
+ \endgroup
+}
+
diff --git a/raterspec/c1import.sty b/raterspec/c1import.sty
new file mode 100644
index 0000000..24d7c71
--- /dev/null
+++ b/raterspec/c1import.sty
@@ -0,0 +1,32 @@
+% LoVullo rater specification c1 import
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/c1import}
+\ProcessOptions\relax
+
+
+\newenvironment{c1glclass}[1]%
+ {%
+ \sigkeep
+ \def\@@class{#1}%
+ \let\basis\@coglclass@basis
+ \let\prem\@coglclass@prem
+ }%
+ {%
+ \par This class \shall only be applicable when each of the following is
+ true:
+ \begin{enumerate}
+ \@cmatch@enable
+ \matchin{class}{\@@class}%
+ \end{enumerate}
+ \sigunkeep
+ }
+
+\def\@coglclass@basis#1{%
+ \par The premium basis \shall be the~\paramrefd{#1}~(\paramref{#1}).
+}
+\def\@coglclass@prem#1{%
+ \par The premium and~rate \shall be derived from~\sref{#1}.
+}
+
diff --git a/raterspec/class.sty b/raterspec/class.sty
new file mode 100644
index 0000000..91b96e1
--- /dev/null
+++ b/raterspec/class.sty
@@ -0,0 +1,355 @@
+% LoVullo rater specification classification
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/class}
+\ProcessOptions\relax
+
+% the first argument (optionally) provides a unique id for this classification
+% (see further information on this below)
+\newenvironment{classification}[1][]%
+ {%
+ \def\@cid{#1}%
+ \leavevmode
+ \label{@classify:#1}%
+ % if a classification id was provided, output it in the left margin (this
+ % allows us to eyeball summaries or common classifications across
+ % specifications, as well as match it up to the code)
+ \if\@cid\empty\else
+ % typeset id
+ \llap{{\scriptsize\bf\@cid\hskip4ex\relax}}%
+ \fi%
+ % enable rule definitions
+ \@cmatch@enable
+ % the first paragraph will constitute the description (and will contain a
+ % signature line)
+ \@margin@sig\@class@mkdesc\@cid
+ }
+ {%
+ % this is opened by \@class@mkdesc
+ \@codegen{</lv:classify>}%
+ \end{@classification@rules}%
+ }
+
+\newenvironment{@classification@rules}
+ {%
+ {\bf Rules:}%
+ \penalty1000\relax
+ \begin{enumerate}
+ }
+ {%
+ \end{enumerate}
+ }
+
+\def\@match@formal#1{{%
+ \\\footnotesize{\bf Formally:}%
+ \space#1%
+}}
+
+\def\@matchany #1 {%
+ \@codegen{ <lv:any>}%
+ \item Any one of the following \must be true:
+ \begin{enumerate}
+ #1
+ \end{enumerate}
+ \@codegen{ </lv:any>}%
+}
+
+\def\@matchall #1 {%
+ \@codegen{ <lv:all>}%
+ \item Each of the following \must be true:
+ \begin{enumerate}
+ #1
+ \end{enumerate}
+ \@codegen{ </lv:all>}%
+}
+
+\def\@matchtodo#1{\item\todo{#1}}
+
+% determine what ref is appropriate
+\def\@magicref#1{{%
+ % param?
+ \expandafter\let\expandafter\@@chk\csname param@#1\endcsname
+ \ifx\@@chk\relax
+ \expandafter\let\expandafter\@@chk\csname classify@#1\endcsname
+ \ifx\@@chk\relax
+ % no known custom type (may be a normal ref)
+ \PackageWarning{dwspec}{unknown magic ref `#1'}%
+ \else
+ \classifyref{#1}%
+ \fi
+ \else
+ \paramref{#1}%
+ \fi
+}}
+
+\def\@cmatcheq{%
+ \begingroup
+ \catcode`\_=11\relax
+ \@docmatcheq
+}
+\def\@docmatcheq#1#2{%
+ \@codegen{ <lv:match on="#1" value="#2" />}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \must be a(n)\space
+ % ensure that the constant exists
+ \@const@exists@err{#2}%
+ % typeset
+ \csname const@#2\endcsname.
+ \@match@formal{\@magicref{#1} $=$ \constref{#2}}%
+ \endgroup
+}
+
+\def\@cmatchneq{%
+ \begingroup
+ \catcode`\_=11\relax
+ \@docmatchneq
+}
+\def\@docmatchneq#1#2{%
+ \@codegen{ <lv:match on="#1">}%
+ \@codegen{ <c:ne>}%
+ \@codegen{ <c:value-of name="#2" />}%
+ \@codegen{ </c:ne>}%
+ \@codegen{ </lv:match>}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \mustnot be a(n)\space
+ % ensure that the constant exists
+ \@const@exists@err{#2}%
+ % typeset
+ \csname const@#2\endcsname.
+ \@match@formal{\@magicref{#1} $\neq$ \constref{#2}}%
+ \endgroup
+}
+
+\def\@cmatchlt{%
+ \begingroup
+ \catcode`\_=11\relax
+ \@docmatchlt
+}
+\def\@docmatchlt#1#2{%
+ \@codegen{ <lv:match on="#1">}%
+ \@codegen{ <c:lt>}%
+ \@codegen{ <c:value-of name="#2" />}%
+ \@codegen{ </c:lt>}%
+ \@codegen{ </lv:match>}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \must be less than\nobreakspace
+ % ensure that the constant exists
+ \@const@exists@err{#2}%
+ % typeset
+ \@const@desc{#2}.%
+ \@match@formal{\@magicref{#1} $<$ \constref{#2}}%
+ \endgroup
+}
+
+\def\@cmatchleq{%
+ \begingroup
+ \catcode`\_=11\relax
+ \@docmatchleq
+}
+\def\@docmatchleq#1#2{%
+ \@codegen{ <lv:match on="#1">}%
+ \@codegen{ <c:leq>}%
+ \@codegen{ <c:value-of name="#2" />}%
+ \@codegen{ </c:leq>}%
+ \@codegen{ </lv:match>}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \must be less than or equal to%
+ % ensure that the constant exists
+ \@const@exists@err{#2}%
+ % typeset
+ \nobreakspace\@const@desc{#2}.%
+ \@match@formal{\@magicref{#1} $\leq$ \constref{#2}}%
+ \endgroup
+}
+
+
+\def\@cmatchgt{%
+ \begingroup
+ \catcode`\_=11\relax
+ \@docmatchgt
+}
+\def\@docmatchgt#1#2{%
+ \@codegen{ <lv:match on="#1">}%
+ \@codegen{ <c:gt>}%
+ \@codegen{ <c:value-of name="#2" />}%
+ \@codegen{ </c:gt>}%
+ \@codegen{ </lv:match>}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \must be greater than\nobreakspace
+ % ensure that the constant exists
+ \@const@exists@err{#2}%
+ % typeset
+ \@const@desc{#2}.%
+ \@match@formal{\@magicref{#1} $>$ \constref{#2}}%
+ \endgroup
+}
+
+
+\def\@cmatchgeq#1#2{%
+ \@codegen{ <lv:match on="#1">}%
+ \@codegen{ <c:gte>}%
+ \@codegen{ <c:value-of name="#2" />}%
+ \@codegen{ </c:gte>}%
+ \@codegen{ </lv:match>}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \must be greater than or equal to\nobreakspace
+ % ensure that the constant exists
+ \@const@exists@err{#2}%
+ % typeset
+ \@const@desc{#2}.%
+ \@match@formal{\@magicref{#1} $\geq$ \constref{#2}}%
+}
+
+\def\@cmatchin#1#2{%
+ \@codegen{ <lv:match on="#1" anyOf="#2" />}%
+ % whatever we are matching on must exist as either a classification or an
+ % input field (param)
+ \item\@cmatch@desc@or@fail{#1}%
+ \space \must be a defined\space
+ % ensure that the param type exists
+ \@type@exists@err{#2}%
+ % output the param type description
+ \csname ptype@#2\endcsname.
+ \@match@formal{\@magicref{#1} $\in$ \typeref{#2}}%
+}
+
+\def\@match#1{%
+ \@codegen{ <!-- TODO: custom match; see specs -->}%
+ \item#1.%
+}
+
+\def\@matchtrue#1{%
+ \@codegen{ <lv:match on="#1" value="TRUE" />}%
+ \item\@cmatch@desc@or@fail{#1}.%
+ \@match@formal{\@magicref{#1} $=\top$}%
+}
+\def\@matchfalse#1{%
+ \@codegen{ <lv:match on="#1" value="FALSE" />}%
+ \item It is not true that: \@cmatch@desc@or@fail{#1}.%
+ \@match@formal{\@magicref{#1} $=\bot$}%
+}
+
+\def\@cmatch@enable{%
+ % we're being lazy with this cat code so that it applies to all \match
+ % invocations grouped between this enable cmd and the disable one; this will
+ % cause problems if we need math mode, so it may need to be revisited in the
+ % future
+ \catcode`_=11\relax
+ \let\matchany\@matchany
+ \let\matchall\@matchall
+ \let\matcheq\@cmatcheq
+ \let\matchneq\@cmatchneq
+ \let\matchgt\@cmatchgt
+ \let\matchgeq\@cmatchgeq
+ \let\matchlt\@cmatchlt
+ \let\matchleq\@cmatchleq
+ \let\matchin\@cmatchin
+ \let\matchtrue\@matchtrue
+ \let\matchfalse\@matchfalse
+ \let\matchtodo\@matchtodo
+ \let\match\@match
+}
+
+\def\@class@mkdesc#1 #2 \par{%
+ \@codegen{<lv:classify as="#1" desc="#2">}%
+ {\bf Description:}\space#2\par
+ % record this definition
+ \index{classification!#1@\texttt{#1}}%
+ \expandafter\gdef\csname classify@#1\endcsname{#2}%
+ % place definition into aux file; will be available next pass
+ \protected@write\@auxout{}{%
+ \string\expandafter\string\gdef
+ \string\csname\space classify@#1\string\endcsname{#2}%
+ }%
+ % immediately following the description are the rules
+ \begin{@classification@rules}
+}
+
+\def\@class@desc#1{{%
+ \expandafter\let\expandafter\@@chk\csname classify@#1\endcsname
+ \ifx\@@chk\relax
+ \PackageWarning{dwspec}{unknown classification `#1'}%
+ \else
+ \@@chk
+ \fi
+}}
+
+\def\@cmatch@desc@or@fail#1{{%
+ % grab tokens to check against for param and class definitions
+ \expandafter\let\expandafter\@@pchk\csname param@#1\endcsname
+ \expandafter\let\expandafter\@@cchk\csname classify@#1\endcsname
+ % fail if neither exists
+ \ifx\@@pchk\relax
+ \ifx\@@cchk\relax
+ \PackageWarning{dwspec}{unknown identifier for classification match: #1}
+ \else
+ % output
+ \@@cchk
+ \fi
+ \else
+ % output
+ \@@pchk
+ \fi
+}}
+
+\def\classifyref#1{%
+ \index{classification!#1@\texttt{#1}}%
+ \hyperref[@classify:#1]{%
+ \tt#1%
+ }%
+}
+\def\classifyrefd#1{%
+ \index{classification!#1@\texttt{#1}}%
+ \hyperref[@classify:#1]{%
+ \csname classify@#1\endcsname
+ }%
+}
+\def\classifyrefalt#1#2{%
+ \index{classification!#1@\texttt{#1}}%
+ \hyperref[@classify:#1]{#2}%
+}
+
+
+\def\assign#1#2{$#1$ $=$ #2}%
+\def\loc{\ifmmode\ell\else$\ell$\fi}%
+\def\y{yield}%
+\def\prem{{\tt premium}}%
+
+\newcommand\rate[1][]{%
+ \begingroup
+ \ifmmode\aftergroup\mathop\fi
+ \endgroup
+ {\tt #1rate}%
+}
+
+
+\newenvironment{submission}[2]%
+ {%
+ \begin{classification}[submit-#1-#2]%
+ }%
+ {%
+ \end{classification}
+ }
+
+\def\when#1{%
+ \Shall be applicable only when each of the following is true:%
+ \begin{enumerate}
+ \@cmatch@enable
+ \scantokens{#1}
+ \end{enumerate}%
+}
+\let\When\when
+
diff --git a/raterspec/form.sty b/raterspec/form.sty
new file mode 100644
index 0000000..0a9bc5e
--- /dev/null
+++ b/raterspec/form.sty
@@ -0,0 +1,53 @@
+% LoVullo rater specification forms
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/form}
+\ProcessOptions\relax
+
+
+\newenvironment{forms}[2]%
+ {%
+ \let\mandatory\@form@mandatory
+ \sigkeep
+ Applicable form code(s): \@formfmt#1,||.
+ \par The form description \shall read:
+ \begin{quote}
+ \sf\hskip-0.52em``#2''
+ \end{quote}
+ % TODO: remove once we're using sPxTeX
+ \pnumon
+ The form(s) \shall be applicable only when each of the following conditions
+ is met:%
+ \begin{enumerate}
+ \@cmatch@enable
+ \ignorespaces
+ }%
+ {%
+ \end{enumerate}
+ \sigunkeep
+ }
+
+\def\@form@mandatory{%
+ \item Form is mandatory and \shall always be applicable.%
+}
+
+\newcount\@formprev
+\def\@formfmt#1,#2||{%
+ \index{forms!codes!#1}%
+ \def\@@chk{#2}%
+ \ifnum\@formprev>0\relax
+ \ifx\@@chk\empty
+ \space and~%
+ \else
+ ,\space
+ \fi
+ \fi
+ {\sf#1}%
+ % recurse
+ \ifx\@@chk\empty\else
+ \advance\@formprev by 1\relax
+ \@formfmt#2||%
+ \fi
+}
+
diff --git a/raterspec/isoclass.sty b/raterspec/isoclass.sty
new file mode 100644
index 0000000..b0386b9
--- /dev/null
+++ b/raterspec/isoclass.sty
@@ -0,0 +1,26 @@
+% LoVullo rater specification iso class abstraction
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/isoclass}
+\ProcessOptions\relax
+
+
+\def\isoclassdef#1 #2\par{%
+ \index{ISO!class code!#1|(}%
+ % indicate that this has been defined (semantic checking)
+ \expandafter\gdef\csname isoclass@code@#1\endcsname{}%
+ % typeset and provide hyperlink (intended for a description env)
+ \item[\hypertarget{@isoclass:#1}{#1}] #2\par%
+ \index{ISO!class code!#1|)}%
+}
+\def\isoclassref#1{%
+ % ensure that the iso class exists
+ \expandafter\ifx\csname isoclass@code@#1\endcsname\relax%
+ \errmessage{unknown ISO class code `#1'}
+ \fi
+ \index{ISO!class code!#1}%
+ \hyperlink{@isoclass:#1}{#1}%
+}
+\let\isoclass\isoclassref
+
diff --git a/raterspec/isoterr.sty b/raterspec/isoterr.sty
new file mode 100644
index 0000000..01fb8c6
--- /dev/null
+++ b/raterspec/isoterr.sty
@@ -0,0 +1,16 @@
+% LoVullo rater specification iso territory abstraction
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/isoterr}
+\ProcessOptions\relax
+
+%
+% N.B. Expects s:isoterr-zips to be a defined reference
+%
+
+
+\def\isoterr#1{%
+ \hyperref[s:isoterr-zips]{ISO Territory #1}%
+}
+
diff --git a/raterspec/param.sty b/raterspec/param.sty
new file mode 100644
index 0000000..7065cd4
--- /dev/null
+++ b/raterspec/param.sty
@@ -0,0 +1,269 @@
+% LoVullo rater specification params
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/param}
+\ProcessOptions\relax
+
+
+% special keywords for base param types
+\def\@coreptype{core}
+\def\@enumptype{enum}
+\def\@unionptype{union}
+
+\def\typedef{%
+ \begingroup% ended by \@dotypedef
+ \catcode`\_=11\relax
+ \@dotypedef
+}
+\def\@dotypedef#1 #2: #3 \par{%
+ \goodbreak%
+ \index{parameter type!#2@\texttt{#2}|(}%
+ \begingroup%
+ % given foo<bar>, get foo and bar separately
+ \edef\@root{\@ptype@root#1<||}%
+ \edef\@type{\@ptype@type#1<#1>||}%
+ \expandafter\gdef\csname ptype@#2\endcsname{#3}%
+ % typeset definition with link
+ \item[%
+ \hypertarget{@ptype:#2}{#2}%
+ \ifx\@root\@coreptype\else%
+ \ $\in\textrm{\rm\@type}$%
+ \fi%
+ ]\hfill\\%
+ \@margin@sig%
+ % ensure that the parent type actually exists
+ \ifx\@root\@coreptype\else%
+ \expandafter\ifx\csname ptype@\@type\endcsname\relax%
+ \errmessage{unknown parent param type `\@type' for `#2'}
+ \fi%
+ \fi%
+ % process any keywords
+ \ifx\@root\@enumptype
+ \aftergroup\@typedef@enum
+ \else\ifx\@root\@unionptype
+ \aftergroup\@typedef@union
+ \fi\fi
+ \index{parameter type!#2@\texttt{#2}|)}%
+ #3\par
+ \endgroup
+ \endgroup% from \typedef
+}
+
+% given a type foo<bar>, returns foo
+\def\@ptype@root#1<#2||{#1}
+% given a type foo<bar>, returns bar
+\def\@ptype@type#1<#2>#3||{#2}
+
+% strips the description and then puts all enums in an aligned environment
+\def\@typedef@enum#1\enumv#2\par{%
+ #1%
+ \vskip0em\relax
+ \begingroup
+ \small
+ % provide some extra give to prevent this from appearing on its own line
+ \vspace{0em plus 0.5\parskip}%
+ \goodbreak
+ {\bf Defined values:}\\
+ \vspace{0.5\parskip}%
+ \begin{tabular}{lc|l}
+ % restore the enumv that we gobbled up
+ \enumv#2
+ \end{tabular}
+ \endgroup
+}
+\def\enumv[#1]#2#3{%
+ % define constant
+ \expandafter\gdef\csname const@#2\endcsname{#1}%
+ \expandafter\gdef\csname const@value@#2\endcsname{#3}%
+ % typeset
+ \index{constant!{\tt#2}}%
+ {\tt\hypertarget{@const:#2}{#2}} & $#3$ & #1 \\
+}
+
+% strips the description and then puts all enums in an aligned environment
+\def\@typedef@union#1\unionv#2\par{%
+ #1%
+ \vskip0em\relax
+ \begingroup
+ \small
+ {\bf Any defined value of:}%
+ \vspace{-\parskip}%
+ \begin{itemize}
+ \setlength{\itemsep}{-\parskip}%
+ % restore the unionv that we gobbled up
+ \unionv#2
+ \end{itemize}
+ \endgroup
+}
+\def\unionv#1{%
+ % does this type exist?
+ \expandafter\ifx\csname ptype@#1\endcsname\relax%
+ \errmessage{unknown param type `#1' for union}
+ \fi%
+ \item{\typeref{#1}}
+}
+
+\def\typeref#1{%
+ \index{parameter type!#1@\texttt{#1}}%
+ \hyperlink{@ptype:#1}{\tt#1}%
+}
+\let\type\typeref
+
+\def\constref #1{%
+ \@ifnumeric{#1}%
+ % numeric constants are simply output with no hyperlink
+ $#1$%
+ \else
+ \index{constant!{\tt#1}}\hyperlink{@const:#1}{\tt#1}%
+ \fi
+}
+\let\const\constref
+
+% constant reference, show description
+\def\constrefd#1{%
+ \@ifnumeric{#1}%
+ % numeric constants are simply output with no hyperlink
+ $#1$%
+ \else
+ \index{constant!{\tt#1}}%
+ \hyperlink{@const:#1}%
+ {\csname const@#1\endcsname}%
+ \fi
+}
+\def\constrefdd#1{\constrefd{#1}\dotfill}
+% constant reference, show value
+\def\constrefv#1{%
+ \@ifnumeric{#1}%
+ % numeric constants are simply output with no hyperlink
+ $#1$%
+ \else
+ \index{constant!{\tt#1}}%
+ \hyperlink{@const:#1}%
+ {\csname const@value@#1\endcsname}%
+ \fi
+}
+% link to constant with alternate text
+\def\constrefalt#1#2{%
+ \index{constant!{\tt#1}}%
+ \hyperlink{@const:#1}{#2}%
+}
+
+\def\@type@exists@err#1{{%
+ \expandafter\let\expandafter\@chk\csname ptype@#1\endcsname
+ \ifx\@chk\relax
+ \errmessage{parameter `#1' is undefined}%
+ \fi
+}}
+\def\@const@exists@err#1{{%
+ % ignore numeric constants (lazy check; anything that begins with a number)
+ \@ifnumeric{#1}\else
+ \expandafter\let\expandafter\@chk\csname const@#1\endcsname
+ \ifx\@chk\relax
+ \errmessage{constant `#1' is undefined}%
+ \fi
+ \fi
+}}
+
+\def\@const@desc#1{{%
+ \@ifnumeric{#1}%
+ % just output the text
+ $#1$%
+ \else
+ % output desc
+ \csname const@#1\endcsname
+ \fi
+}}
+
+
+% denotes a param that will likely be calculated
+\def\metaparamdef{\paramdef}
+
+
+% param definition
+% note that the description is included in this input as well; this allows us to
+% use this information for code generation/etc
+\def\paramdef{%
+ \begingroup
+ \catcode`_=11\relax
+ \@doparamdef
+}
+\def\@doparamdef#1 #2: #3 \par{%
+ \goodbreak%
+ \index{parameter!#2@\texttt{#2}|(}%
+ \begingroup%
+ \def\@given{#1}%
+ % given foo<bar>, get foo and bar separately
+ \edef\@root{\@ptype@root#1<||}%
+ \edef\@type{\@ptype@type#1<#1>||}%
+ \expandafter\gdef\csname param@#2\endcsname{#3}%
+ % does the given type exist (note that this check assumes that the typedef
+ % appears before the param in the specs, as is currently the case)
+ \expandafter\ifx\csname ptype@\@type\endcsname\relax%
+ \errmessage{unknown param type: \@type}
+ \fi%
+ % typeset definition with link
+ \item[%
+ \hypertarget{@param:#2}{{\tt#2}}%
+ \ $\in\textrm{%
+ \rm\typeref{\@type}%
+ % output root only if provided (if not, then because of how \@type
+ % called \@ptype@type, it will be equal to #1)
+ \ifx\@root\@given\else%
+ \ $\langle$\@root$\rangle$
+ \fi
+ }$%
+ ]\hfill\\%
+ \@margin@sig%
+ % remove mysterious space from margin sig
+ \hskip-1ex\relax%
+ #3%
+ \ifx\@root\@given
+ \@codegen{<lv:param name="#2" type="\@type" desc="#3"/>}%
+ \else
+ \@codegen{<lv:param name="#2" type="\@type" set="\@root"%
+ \space desc="#3"/>%
+ }%
+ \fi
+ \endgroup%
+ \index{parameter!#2@\texttt{#2}|)}%
+ \endgroup
+}
+
+\def\paramref{%
+ \begingroup% ended by \@dotypedef
+ \catcode`\_=11\relax
+ \@doparamref
+}
+\def\@doparamref#1{%
+ % prevent scantokens from adding a space at the end
+ \endlinechar-1\relax
+ \expandafter\let\expandafter\@@chk\csname param@#1\endcsname
+ \ifx\@@chk\relax
+ \PackageError{dwspec}{unknown param: #1}
+ \fi
+ \index{parameter!#1@\texttt{#1}}%
+ \hyperlink{@param:#1}%
+ {\tt\scantokens{#1}}%
+ \endgroup
+}
+\let\param\paramref
+
+\def\paramrefd#1{%
+ \expandafter\let\expandafter\@@pchk\csname param@#1\endcsname
+ \ifx\@@pchk\empty
+ \PackageError{dwspec}{Unknown parameter: #1}%
+ \else
+ % output
+ \@@pchk
+ \fi
+}
+
+\def\locparam#1{%
+ \ifmmode
+ \mathop{\paramref{#1}_\loc}
+ \else
+ $\locparam{#1}$%
+ \fi
+}
+
diff --git a/raterspec/question.sty b/raterspec/question.sty
new file mode 100644
index 0000000..263c93e
--- /dev/null
+++ b/raterspec/question.sty
@@ -0,0 +1,62 @@
+% LoVullo rater specification questions
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/question}
+\ProcessOptions\relax
+
+
+\newlength\questionparsep
+\questionparsep\the\marginparsep
+\newenvironment{qgroup}[1]%
+ {%
+ \subsubsection{#1}%
+ \begin{description}%
+ }%
+ {%
+ \end{description}%
+ }
+
+\newenvironment{subquestions}%
+ {%
+ \begin{description}%
+ \advance\questionparsep by \leftmargin\relax
+ }
+ {%
+ \end{description}%
+ }
+
+
+\def\@qtypedesc@text{any string of characters.}
+\def\@qtypedesc@number{any whole number.}
+\def\@qtypedesc@float{any floating point value.}
+\def\@qtypedesc@noyes{one of either {\sl No\/} or~{\sl Yes}.}
+\def\@qtypedesc@select{one of the options enumerated below:}
+\newcommand\question[5][]{%
+ \item[%
+ \beginundersletter
+ \llap{%
+ \tt\scriptsize\raisebox{-1em}[0em][0em]{%
+ \shortstack[r]{%
+ \scantokens{#2}\\
+ {\tiny \scantokens{#4}}%
+ }%
+ }%
+ \hspace{\the\questionparsep}%
+ }%
+ \endundersletter
+ \ignorespaces#5\unskip
+ ]\hfill\\
+ \@margin@sig
+ \begingroup
+ \def\@mapsto{#3}%
+ \ifx\@mapsto\empty
+ \May not map to any rater input parameter.%
+ \else
+ \Shall map to rater input parameter \paramref{#3}.%
+ \fi
+ \endgroup
+ \space Input value \shall be \csname @qtypedesc@#4\endcsname\space
+ \ignorespaces
+}
+
diff --git a/raterspec/rates.sty b/raterspec/rates.sty
new file mode 100644
index 0000000..1ed00ec
--- /dev/null
+++ b/raterspec/rates.sty
@@ -0,0 +1,44 @@
+% LoVullo rater specification rate tables
+%%
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{raterspec/rates}
+\ProcessOptions\relax
+
+
+\newenvironment{ratetable*}[5][]%
+ {%
+ \def\@@lotcaption{#1}
+ \def\@@label{#2}
+ \def\@@caption{#3}
+ \ifx\@@lotcaption\empty
+ \let\@@lotcaption\@@caption
+ \fi
+ \begin{table}[#5]
+ \caption[\@@lotcaption]{\@@caption}
+ \label{t:\@@label}
+ \centering\footnotesize\sf
+ \hspace*{-\marginparwidth}%
+ \begin{tabular}{#4}
+ \toprule
+ }
+ {%
+ \bottomrule
+ \end{tabular}
+ \hspace*{-\marginparwidth}%
+ \medskip
+ \end{table}
+ }
+
+
+% simplified syntax where a rate table should always appear on a page of floats
+% (which is often the case, since many rate tables tend to be within close
+% proximity to one-another)
+\newenvironment{ratetable}[4][]%
+ {%
+ \begin{ratetable*}[#1]{#2}{#3}{#4}{p}%
+ }%
+ {%
+ \end{ratetable*}%
+ }
+