summaryrefslogtreecommitdiff
path: root/macros/plain/contrib/zztex/tex
diff options
context:
space:
mode:
Diffstat (limited to 'macros/plain/contrib/zztex/tex')
-rw-r--r--macros/plain/contrib/zztex/tex/zzart.tex611
-rw-r--r--macros/plain/contrib/zztex/tex/zzbiblio.tex427
-rw-r--r--macros/plain/contrib/zztex/tex/zzbibtex.tex290
-rw-r--r--macros/plain/contrib/zztex/tex/zzblock.tex327
-rw-r--r--macros/plain/contrib/zztex/tex/zzcmmath.tex15
-rw-r--r--macros/plain/contrib/zztex/tex/zzcomenc.tex153
-rw-r--r--macros/plain/contrib/zztex/tex/zzdiv.tex128
-rw-r--r--macros/plain/contrib/zztex/tex/zzdoc.tex500
-rw-r--r--macros/plain/contrib/zztex/tex/zzerror.tex123
-rw-r--r--macros/plain/contrib/zztex/tex/zzfloat.tex1164
-rw-r--r--macros/plain/contrib/zztex/tex/zzfont.tex453
-rw-r--r--macros/plain/contrib/zztex/tex/zzfront.tex247
-rw-r--r--macros/plain/contrib/zztex/tex/zzhelp.tex359
-rw-r--r--macros/plain/contrib/zztex/tex/zzhmode.tex924
-rw-r--r--macros/plain/contrib/zztex/tex/zzhmodeb.tex239
-rw-r--r--macros/plain/contrib/zztex/tex/zzhyper.tex185
-rw-r--r--macros/plain/contrib/zztex/tex/zzhyph.tex128
-rw-r--r--macros/plain/contrib/zztex/tex/zzindexv1.tex379
-rw-r--r--macros/plain/contrib/zztex/tex/zzindexv2.tex448
-rw-r--r--macros/plain/contrib/zztex/tex/zzio.tex84
-rw-r--r--macros/plain/contrib/zztex/tex/zzlist.tex163
-rw-r--r--macros/plain/contrib/zztex/tex/zzltrspc.tex111
-rw-r--r--macros/plain/contrib/zztex/tex/zzlucida.tex140
-rw-r--r--macros/plain/contrib/zztex/tex/zzmath.tex1919
-rw-r--r--macros/plain/contrib/zztex/tex/zzmathv3.tex123
-rw-r--r--macros/plain/contrib/zztex/tex/zzmathv4.tex129
-rw-r--r--macros/plain/contrib/zztex/tex/zzmathv5.tex129
-rw-r--r--macros/plain/contrib/zztex/tex/zzmathv6.tex180
-rw-r--r--macros/plain/contrib/zztex/tex/zzmerge.tex70
-rw-r--r--macros/plain/contrib/zztex/tex/zzmisc.tex292
-rw-r--r--macros/plain/contrib/zztex/tex/zzmtime.tex89
-rw-r--r--macros/plain/contrib/zztex/tex/zznewmath.tex93
-rw-r--r--macros/plain/contrib/zztex/tex/zznote.tex522
-rw-r--r--macros/plain/contrib/zztex/tex/zzoverlay.tex100
-rw-r--r--macros/plain/contrib/zztex/tex/zzpage.tex908
-rw-r--r--macros/plain/contrib/zztex/tex/zzplain.tex71
-rw-r--r--macros/plain/contrib/zztex/tex/zzprog.tex228
-rw-r--r--macros/plain/contrib/zztex/tex/zzps.tex251
-rw-r--r--macros/plain/contrib/zztex/tex/zzreg.tex437
-rw-r--r--macros/plain/contrib/zztex/tex/zzrunner.tex98
-rw-r--r--macros/plain/contrib/zztex/tex/zzsect.tex806
-rw-r--r--macros/plain/contrib/zztex/tex/zztabbing.tex266
-rw-r--r--macros/plain/contrib/zztex/tex/zztabularv1.tex465
-rw-r--r--macros/plain/contrib/zztex/tex/zztabularv2.tex512
-rw-r--r--macros/plain/contrib/zztex/tex/zztabularv3.tex771
-rw-r--r--macros/plain/contrib/zztex/tex/zztag.tex269
-rw-r--r--macros/plain/contrib/zztex/tex/zztex.tex196
-rw-r--r--macros/plain/contrib/zztex/tex/zztext.tex935
-rw-r--r--macros/plain/contrib/zztex/tex/zzttladj.tex78
-rw-r--r--macros/plain/contrib/zztex/tex/zztures.tex24
-rw-r--r--macros/plain/contrib/zztex/tex/zzver.tex1
-rw-r--r--macros/plain/contrib/zztex/tex/zzvmode.tex380
-rw-r--r--macros/plain/contrib/zztex/tex/zzxref.tex245
53 files changed, 18185 insertions, 0 deletions
diff --git a/macros/plain/contrib/zztex/tex/zzart.tex b/macros/plain/contrib/zztex/tex/zzart.tex
new file mode 100644
index 0000000000..52b4081426
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzart.tex
@@ -0,0 +1,611 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Art Facilities
+%
+% Synopsis: This module provides facilities to deal with external art.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 7 June 1991
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Art File Root & Placing Control
+% --- ---- ---- - ------- -------
+
+
+\def \zartroot {}
+\setflag \zplaceart = \true
+
+
+\def \setartroot #1{% {root/}
+ \gdef \zartroot {#1}}
+
+\def \zprependartroot #1#2{% {\name}{filespec}
+ \edef #1{\zartroot#2}}
+
+\def \placeart #1{%
+ \setflag \zplaceart = #1}
+
+% Imported Art
+% -------- ---
+
+
+\defineblock{\art}{\endart}{\false}{}
+
+%~block art Type
+% \abovepenalty = integer % Penalty above block.
+% \aboveskip = glue % Space b/b above block.
+% \belowpenalty = integer % Penalty below block.
+% \belowskip = glue % Space b/b below block.
+% \setflag \cliptobb = flag % Clip art to its bounding box?
+% \hfuzz = dimen % Horizontal fuzz.
+% \hscale = dimen % Horizontal scale (in points).
+% \leftindent = glue % Left indentation.
+% \rightindent = glue % Right indentation.
+% \vscale = dimen % Vertical scale (in points).
+% \vshift = dimen % Vertical shift.
+%~end
+
+\definedimen{\artwidth}{0pt}
+\definedimen{\artheight}{0pt}
+\definedimen{\hscale}{0pt}
+\definedimen{\vscale}{0pt}
+
+
+%~ The format of the *file-info* argument is:
+%~ *file*,*width*,*height*,*scale*[,*gutter*,*file*,...]&/
+%~ The *file* is a file name preceded by |!| or |=|.
+
+\def \art #1#2{% {type}{file-info}
+ \beginblockscope{art}%
+ \global\increment \artdepth
+ \abovepenalty = \breakgood %~default hard
+ \belowpenalty = \breakgood %~default hard
+ \setflag \cliptobb = \false %~default soft
+ \hfuzz = 1pt %~default soft
+ \hscale = 1.0pt %~default hard
+ \vscale = 1.0pt %~default hard
+ \vshift = \mindimen %~default soft
+ \processdesign{\art}{#1}%
+ \global\increment \artnumber
+ \global\artwidth = 0pt
+ \global\artheight = 0pt
+ \artformat{#2}%
+ \endart}
+
+\def \endart {%
+ \global\decrement \artdepth
+ \endblockscope{art}}
+
+\def \artformat #1{% {info}
+ \endgraf
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}%
+ \noindent \zbldartline 0pt,#1,\zmark \endgraf
+ \prevdepth = 0pt % Nothing better to do.
+ \bbskipbelow{\belowpenalty}{\belowskip}}
+
+\def \zbldartline #1,#2,#3,#4,#5,#6\zmark{% gutter,file,width,height,scale,...,\zmark
+ \zbuildartlineb{#1}{#2}{#3}{#4}{#5}%
+ \zwriteartinfo{#2}{#3}{#4}{#5}%
+ \if \notp{\emptyargp{#6}}\zbldartline #6\zmark \fi}
+
+% Place Art File
+% ----- --- ----
+
+
+\definedimen{\zleftslop}{0pt}
+\definedimen{\zrightslop}{0pt}
+\definedimen{\ztopslop}{0pt}
+\definedimen{\zbottomslop}{0pt}
+\definedimen{\zartwidth}{0pt}
+\definedimen{\zartheight}{0pt}
+\definedimen{\zartscale}{0pt}
+
+
+\def \zbuildartlineb #1#2#3#4#5{% {gutter}{file}{width}{height}{scale}
+ \kern #1\relax
+ \zparseartfile #2,0pt,0pt,0pt,0pt,\zmark
+ \zchkartfile{\zgotart}%
+ \zcalcartdimens{#3}{#4}{#5}%
+ \zbuildartlinec{\zartfile}%
+ \gcalculate \artwidth = {\artwidth,+,#1,+,\zartwidth}%
+ \if \dimgtrp{\zartheight}{\artheight}\global\artheight = \zartheight \fi}
+
+\def \zparseartfile #1,#2,#3,#4,#5,#6\zmark{% spec,left,right,top,bottom\zmark
+ \zparseartspec #1.eps.\zmark
+ \zleftslop = #2%
+ \zrightslop = #3%
+ \ztopslop = #4%
+ \zbottomslop = #5\relax}
+
+\def \zcalcartdimens #1#2#3{% {width}{height}{scale}
+ \if \orp{\andp{\dimzerop{#1}}{\dimzerop{#2}}}
+ {\forceepsbb}%
+ \if \zgotart
+ \zreadepsbb{\zartwidth}{\zartheight}{\zartfile}%
+ \else
+ \zartwidth = 20pc \zartheight = 10pc
+ \fi
+ \else
+ \calculate \zartwidth = {#1,-,\zleftslop,-,\zrightslop}%
+ \calculate \zartheight = {#2,-,\ztopslop,-,\zbottomslop}%
+ \fi
+ \zcalcartscale #3\zmark
+ \calculate \zartwidth = {\zartwidth,S,\zartscale,S,\hscale}%
+ \calculate \zartheight = {\zartheight,S,\zartscale,S,\vscale}%
+ \calculate \zleftslop = {\zleftslop,S,\zartscale,S,\hscale}%
+ \calculate \zbottomslop = {\zbottomslop,S,\zartscale,S,\vscale}%
+ \if \forceepsbb
+ \advance \zleftslop by \zbbxorigin
+ \advance \zbottomslop by \zbbyorigin
+ \fi}
+
+\def \zcalcartscale #1#2\zmark{% scale\zmark
+ \if \codeeqlp{#1}{=}%
+ \if \emptyargp{#2}%
+ \calculate \zartscale = {\hsize,R,\zartwidth}%
+ \else
+ \calculate \zartscale = {#2,R,\zartwidth}%
+ \fi
+ \else
+ \calculate \zartscale = {#1#2pt,/,100}%
+ \fi}
+
+\def \zbuildartlinec #1{% {title}
+ \if \dimeqlp{\vshift}{\mindimen}%
+ \measureascenderheight{\vshift}%
+ \fi
+ \vtop {% % Place art in a vbox.
+ \offinterlineskip
+ \rule{height \vshift width 0pt}% % Force the height of the
+ \kern -\vshift % box to match ascenders.
+ \rule{height 0pt width \zartwidth}% % Force the width of the box.
+ \if \andp{\zplaceart}{\zgotart}%
+ \rule{height 0pt depth \zartheight width 0pt}% % Force its depth.
+ \zplaceartfile
+ \vss
+ \else
+ \vbox to \zartheight{% % Force its depth.
+ \topcornermarks{\zartwidth}{.5pc}{.25pt}%
+ \vss
+ \hbox to \zartwidth {\hss \zannofont #1\hss}%
+ \hbox to \zartwidth {\hss \zannofont
+ \if \notp{\zplaceart}[not placing]\fi
+ \if \notp{\zgotart}[to come]\fi
+ \hss}%
+ \vss
+ \bottomcornermarks{\zartwidth}{.5pc}{.25pt}}%
+ \fi}}
+
+\def \zplaceartfile {%
+ \kern \zbottomslop
+ \moveleft \zleftslop \vbox{%
+ \special{CTM: push}%
+ \special{CTM: scale \thefactor\hscale \space \thefactor\vscale}%
+ \specialplaceepsfile{\zartfile}{\zartscale}{\cliptobb}%
+ \special{CTM: pop}}%
+ \kern -\zbottomslop}
+
+% Duplicates and Missing Art
+% ---------- --- ------- ---
+
+
+% Write an art entry into the cross-reference file.
+
+\def \zwriteartinfo #1#2#3#4{% {file}{width}{height}{scale}
+ \zbeginhidewrite
+ \edef \znext {\noexpand\xref{art}{\noexpand\folio}%
+ {#1}%
+ {#2,#3}
+ {#4}}%
+ \znext
+ \zendhidewrite}
+
+% This macro is invoked by \xref. In copy mode, it checks to make sure
+% that no art file is used twice.
+
+\def \xrefart #1#2#3#4{% {page}{number}{title}{tag}
+ \ifnum \xrefmode=\xrefcopymode
+ \zxrefarta #2,\zmark
+ \fi}
+
+\def \zxrefarta #1#2,#3\zmark{%
+ \if \notp{\orp{\codeeqlp{#1}{!}}{\codeeqlp{#1}{=}}}%
+ \if \definedp{\zart:#1#2}%
+ \warning{dupart}{Art file `#1#2' is used more than once in the book}%
+ \fi
+ \withname\gdef{\zart:#1#2}{}%
+ \fi}
+
+% This macro is invoked at the end of the run.
+
+\def \zmissingartmsg {%
+ \if \posp{\zmissingart}%
+ \remark{Number of missing art files in this run: \number\zmissingart.}%
+ \fi}
+
+% Built-In Art Blocks
+% -------- --- ------
+
+\def \fullpagegraphic #1{% {art-spec}
+ \vsinkfromtrim{-\standardbleed}
+ \smashbox{%
+ \with{\hfuzz=99pc%
+ \leftindent=\if \evenpagep \evenbleedshift \else \oddbleedshift \fi}
+ \art{graphic}{#1}}}
+
+\def \artgraphicdesign {%
+ \aboveskip = \noskip
+ \belowskip = \noskip
+ \setflag \cliptobb = \false
+ \hfuzz = 1pt
+ \leftindent = 0pt
+ \rightindent = 0pt
+ \vshift = 0pt}
+
+% Glyph Definitions
+% ----- -----------
+
+
+% This macro allows the user to define a "glyph," which is an EPS file
+% that is treated like a fancy character. The bounding box must be
+% perfect.
+
+\def \defineglyph #1#2#3{% {\name}{spec,width,height,scale}{raise}
+ \gdef #1{\zglyph #2,#3\zmark}}
+
+\def \zglyph #1,#2,#3,#4,#5\zmark{% spec,width,height,scale,raise\zmark
+ {\zparseartspec #1.eps.\zmark
+ \zchkartfile{\zgotart}%
+ \zartwidth = #2%
+ \zartheight = #3%
+ \tdimena = #4\typesize % \tdimena = final scale in points.
+ \divide \tdimena by 10
+ \calculate \zartwidth = {\zartwidth,P,\thefactor\tdimena}%
+ \calculate \zartheight = {\zartheight,P,\thefactor\tdimena}%
+ \raise #5 \hbox to \zartwidth{%
+ \rule{height \zartheight depth 0pt width 0pt}%
+ \if \zgotart
+ \specialplaceglyph{\zartfile}{\tdimena}{\false}%
+ \fi
+ \hfil}}}
+
+\defineglyph{\acidfree}{!acidfree,2pc,2pc,35}{-1.5pt}
+
+% Panel Label Block
+% ----- ----- -----
+
+
+\defineblock{\panellabel}{\endpanellabel}{\false}{}
+
+%~block panellabel Type
+% \aboveskip = glue % Space b/b above block.
+% \belowskip = glue % Space b/b below block.
+% \bodyfont = {...} % Font for text.
+% \style = {...} % Label style.
+% \vshift = dimen % Vertical shift.
+%~end
+
+\def \panellabel #1#2{% {type}{label-list}
+ \beginblockscope{panellabel}%
+ \global\increment \panellabeldepth
+ \style = {letter in parens}% %~default soft
+ \vshift = 0pt %~default soft
+ \processdesign{\panellabel}{#1}%
+ \global\increment \panellabelnumber
+ \panellabelformat{#2}%
+ \endpanellabel}
+
+\def \endpanellabel {%
+ \global\decrement \panellabeldepth
+ \endblockscope{panellabel}}
+
+\def \panellabelformat #1{% {panel-list}
+ \endgraf
+ \bbskipabove{\breaknever}{\aboveskip}%
+ \the\bodyfont
+ \noindent
+ \zdolabel #1,\zmark
+ \endgraf
+ \bbskipbelow{\breakallowed}{\belowskip}}
+
+\def \zdolabel #1,#2,#3\zmark{% shift,label,...
+ \rlap{%
+ \hspace{#1}%
+ \smash{\lower \vshift \hbox{#2}}}%
+ \if \notp{\emptyargp{#3}}\zdolabel #3\zmark \fi}
+
+% Frames
+% ------
+
+
+\defineblock{\frame}{\endframe}{\false}{}
+
+%~block frame Type
+% \abovepenalty = integer % Penalty above block.
+% \aboveskip = glue % Space b/b above block.
+% \def \backgroundformat ##1{...} % Background formatter.
+% \belowpenalty = integer % Penalty below block.
+% \belowskip = glue % Space b/b below block.
+% \deferredparams = {...} % Deferred parameter calculations.
+% \framecolor = {color} % Color of frame.
+% \framewidths = {left,right,top,bot} % Widths of frame segments.
+% \framegaps = {left,right,top,bot} % Gaps between frame and material.
+% \leftindent = glue % Left indentation of enclosed material.
+% \screencolor = {color} % Background screen color.
+% \width = dimen % Width of enclosed material.
+%~end
+
+% Together, \leftindent and \width specify the position of the enclosed
+% text within the text box, not of the frame itself.
+
+
+\definetoks{\deferredparams}
+\definetoks{\framecolor}
+\definetoks{\framewidths}
+\definetoks{\framegaps}
+\definetoks{\screencolor}
+
+\definecount{\framepage}{0}
+
+\definecount{\zdivframecounter}{0}
+
+\def \frame #1{% {type}
+ \beginblockscope{frame}%
+ \global\increment \framedepth
+ \global\increment \zdivframecounter
+ \whichpage{\framepage}{zE:\the\divisionname-\the\zdivframecounter}%
+ \abovepenalty = \breakgood %~default hard
+ \def \backgroundformat ##1{}% %~default soft
+ \belowpenalty = \breakgood %~default hard
+ \deferredparams = {}% %~default soft
+ \framecolor = {black}% %~default soft
+ \leftindent = 0pt %~default soft
+ \screencolor = {}% %~default soft
+ \width = \naturalwidth %~default soft
+ \processdesign{\frame}{#1}%
+ \global\increment \framenumber
+ \setbox\zboxa = \vtop \bgroup
+ \zpushvcontext}
+
+\def \endframe {%
+ \endgraf
+ \unskip
+ \zpopvcontext
+ \egroup % \vtop
+ \the\deferredparams
+ \setbox\zboxb = \hbox to \width{%
+ \hspace{-\leftindent}\box\zboxa \hss}%
+ \edef \zcolorrule {\noexpand\colorrule{\the\framecolor}}%
+ \def \zarga ##1,##2,##3,##4\zmark{##1\relax}%
+ \def \zargb ##1,##2,##3,##4\zmark{##2\relax}%
+ \def \zargc ##1,##2,##3,##4\zmark{##3\relax}%
+ \def \zargd ##1,##2,##3,##4\zmark{##4\relax}%
+ \tdimenc = \expandafter\zargc\the\framegaps\zmark
+ \advance \tdimenc by \ht\zboxb
+ \advance \tdimenc by \dp\zboxb
+ \advance \tdimenc by \expandafter\zargd\the\framegaps\zmark
+ \setbox\zboxa = \vtop {%
+ \offinterlineskip
+ \measureascenderheight{\tdimena}% % Force the height of the
+ \rule{width 0pt height \tdimena}% % box to match ascenders.
+ \kern -\tdimena
+ \smashbox{\backgroundformat{\tdimenc}}%
+ \if \notp{\emptytoksp{\screencolor}}%
+ \tdimend = \expandafter\zarga\the\framegaps\zmark
+ \advance \tdimend by \wd\zboxb
+ \advance \tdimend by \expandafter\zargb\the\framegaps\zmark
+ \smashbox{%
+%%% \moveright \expandafter\zarga\the\framewidths\zmark \smashbox{%
+ \colorrule{\the\screencolor}{width \tdimend height \tdimenc}}%
+ \fi
+ \zcolorrule{height \expandafter\zargc\the\framewidths\zmark}%
+ \kern -\expandafter\zargc\the\framewidths\zmark
+ \hbox {%
+ \rlap{\zcolorrule{height \tdimenc
+ width \expandafter\zarga\the\framewidths\zmark}}%
+ \hskip \expandafter\zarga\the\framegaps\zmark
+ \vbox {%
+ \vskip \expandafter\zargc\the\framegaps\zmark
+ \box\zboxb
+ \vskip \expandafter\zargd\the\framegaps\zmark}%
+ \hskip \expandafter\zargb\the\framegaps\zmark
+ \llap{\zcolorrule{height \tdimenc
+ width \expandafter\zargb\the\framewidths\zmark}}}%
+ \kern -\expandafter\zargd\the\framewidths\zmark
+ \zcolorrule{height \expandafter\zargd\the\framewidths\zmark}%
+ \tagpageonly{\uniquetag{zE}{\the\zdivframecounter}}}%
+ \advance \leftindent by -\expandafter\zarga\the\framewidths\zmark
+ \advance \leftindent by -\expandafter\zarga\the\framegaps\zmark
+ \frameformat
+ \global\decrement \framedepth
+ \endblockscope{frame}}
+
+\def \frameformat {%
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \hindent{\leftindent} \rlap{\box\zboxa}\par
+ \prevdepth = 0pt % Last thing in box is rule.
+ \bbskipbelow{\belowpenalty}{\belowskip}}
+
+% This macro is invoked at the beginning of each division.
+
+\def \zframedivinit {%
+ \global\zdivframecounter = 0\relax}
+
+% Margin Rules
+% ------ -----
+
+
+\defineblock{\marginrule}{\endmarginrule}{\false}{}
+
+%~block marginrule Type
+% \artspec = {...} % Art spec for graphic above rule.
+% \leftshift = dimen % Horizontal shift for rule in left margin.
+% \position = {...} % Position options.
+% \rightshift = dimen % Horizonal shift for rule in right margin.
+% \rulecolor = {...} % Color of rule.
+% \rulewidth = dimen % Width of rule.
+% \vshift = dimen % Vertical shift for note.
+%~end
+
+\definetoks{\artspec}
+\definedimen{\leftshift}{0pt}
+\definedimen{\rightshift}{0pt}
+
+\definecount{\marginrulepage}{0}
+
+\definecount{\zdivmrcounter}{0}
+\definedimen{\zmrshift}{0pt}
+\definedimen{\zmrprevdepth}{0pt}
+
+\def \marginrule #1#2{% {type}{height,depth}
+ \blockcantbein{\marginrule}{\marginrule}%
+ \beginblockscope{marginrule}%
+ \global\increment \marginruledepth
+ \global\increment \zdivmrcounter
+ \whichpage{\marginrulepage}{zR:\the\divisionname-\the\zdivmrcounter}%
+ \rulecolor = {black} %~default soft
+ \vshift = 0pt %~default soft
+ \processdesign{\marginrule}{#1}%
+ \zparsemrpos{\the\position}%
+ \marginruleformat{#2}%
+ \endmarginrule}
+
+\def \endmarginrule {%
+ \global\decrement \marginruledepth
+ \endblockscope{marginrule}}
+
+\def \marginruleformat #1{% {height,depth}
+ \if \vmodep
+ \zmrprevdepth = \prevdepth
+ \nointerlineskip
+ \else
+ \vadjust
+ \fi
+ \bgroup
+ \topskip = 0pt
+ \moveright \zmrshift \vtop to 0pt{%
+ \vskip \vshift
+ \zmrgraphic
+ \zmrrule #1\zmark
+ \vss
+ \tagpageonly{\uniquetag{zR}{\the\zdivmrcounter}}}%
+ \egroup
+ \if \vmodep \prevdepth = \zmrprevdepth \fi}
+
+% This macro sets up variables that specify the position of a margin rule
+% according to the \position design parameter:
+%
+% \ifevenpage Use next position only on even page.
+% \ifoddpage Use next position only on odd page.
+% \leftmargin Shift note to left margin.
+% \outsidemargin Shift note to outside margin.
+% \rightmargin Shift note to right margin.
+
+\definecount{\zmrhpos}{0}
+
+\def \zparsemrpos #1{% {options...}
+ \global\zmrhpos = 0
+ {\def \ifevenpage ##1{\if \evenp{\marginrulepage}##1\fi}%
+ \def \ifoddpage ##1{\if \oddp{\marginrulepage}##1\fi}%
+ \def \leftmargin {\global\zmrhpos=1\relax}%
+ \def \outsidemargin{\ifevenpage{\leftmargin}\ifoddpage{\rightmargin}}%
+ \def \rightmargin {\global\zmrhpos=2\relax}%
+ #1\relax}%
+ \ifcase \zmrhpos
+ \error{nomrpos}
+ {No horizontal position has been specified for a margin rule}%
+ \or
+ \if \negp{\leftshift}%
+ \zmrshift = \leftshift
+ \else
+ \if \evenp{\marginrulepage}%
+ \calculate \zmrshift = {-\evenlefttextmargin,+,\leftshift}%
+ \else
+ \calculate \zmrshift = {-\oddlefttextmargin,+,\leftshift}%
+ \fi
+ \fi
+ \or
+ \calculate \zmrshift = {\textmeasure,+,\rightshift}%
+ \fi}
+
+\def \zmrgraphic {%
+ \if \emptytoksp{\artspec}%
+ \artheight = 0pt
+ \else
+ \xdef \znext {\noexpand\art{zmarginrule}{\the\artspec}}%
+ \znext
+ \kern -1pt
+ \fi}
+
+\definedimen{\zmrdepth}{0pt}
+
+\def \zmrrule #1,#2\zmark{% height,depth\zmark
+ \calculate \zmrdepth = {#2,-,\artheight}%
+ \setbox \zboxa = \hbox{\vrule width 0pt height #1 depth \zmrdepth}%
+ \vskip -\ht\zboxa
+ \colorrule{\the\rulecolor}{width \rulewidth height #1 depth \zmrdepth}}
+
+\def \artzmarginruledesign {%
+ \aboveskip = \noskip
+ \belowskip = \noskip
+ \setflag \cliptobb = \false
+ \hfuzz = 999pc
+ \leftindent = 0pt
+ \rightindent = 0pt
+ \vshift = \mindimen}
+
+% This macro is invoked at the beginning of each division.
+
+\def \zmrdivinit {%
+ \global\zdivmrcounter = 0\relax}
+
+% Corner Marks
+% ------ -----
+
+
+\def \topcornermarks #1#2#3{% {box-width}{length}{thickness}
+ \hbox to #1{\vrule height #3 depth 0pt width #2 \hss
+ \vrule height #3 depth 0pt width #2}%
+ \nointerlineskip
+ \hbox to #1{\vrule height #2 depth 0pt width #3 \hss
+ \vrule height #2 depth 0pt width #3}}
+
+\def \bottomcornermarks #1#2#3{% {box-width}{length}{thickness}
+ \hbox to #1{\vrule height #2 depth 0pt width #3 \hss
+ \vrule height #2 depth 0pt width #3}%
+ \nointerlineskip
+ \hbox to #1{\vrule height #3 depth 0pt width #2 \hss
+ \vrule height #3 depth 0pt width #2}}
+
+% Utilities
+% ---------
+
+
+\definecount{\zmissingart}{0} % Count of missing art files.
+
+
+% Check that the art file exists and issue remark if not.
+
+\def \zchkartfile #1{% {\flag}
+ \setflag #1= \true
+ \checkfile{\znext}{\zartfile}%
+ \if \notp{\znext}%
+ \remark{Art file `\zartfile' is missing; ignored for now}%
+ \global\increment \zmissingart
+ \setflag #1= \false
+ \fi}
+
+\def \zparseartspec #1#2.#3.#4\zmark{% name.ext.\zmark
+ \def \zartfile {???}% % Why do this?
+ \if \codeeqlp{#1}{!}%
+ \def \zartfile{#2.#3}%
+ \else\if \codeeqlp{#1}{=}%
+ \zprependartroot{\zartfile}{#2.#3}%
+ \else
+ \zprependartroot{\zartfile}{#1#2.#3}%
+ \fi\fi}
diff --git a/macros/plain/contrib/zztex/tex/zzbiblio.tex b/macros/plain/contrib/zztex/tex/zzbiblio.tex
new file mode 100644
index 0000000000..cc834e4109
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzbiblio.tex
@@ -0,0 +1,427 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Bibliography Facility
+%
+% Synopsis: This module provides a new bibliography facility to replace
+% zzbibtex. It is more flexible so that it can handle numeric,
+% key, and author/year citations.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 1 December 2016
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Initialization
+% --------------
+
+
+\def \zbiblioinit {%
+ \if \definedp{\bibliodesign}%
+ \begingroup
+ \bibliodesign
+ \globaldefs = 1
+ \citestyle = \citestyle
+ \endgroup
+ \fi}
+
+% Bibliography Cross-Reference
+% ------------ ---------------
+
+
+% When tags are loaded, define the name \=zB:tag to contain the
+% bibliographic info in this format:
+% folio\zmark key\zmark {author}{year}{full-author}
+
+\def \xrefbib #1#2#3#4{% {folio}{key}{{author}{year}{full-author}}{tag}
+ \ifnum \xrefmode=\xrefloadtagmode
+ \if \definedp{\=zB:#4}\zduptag{#4}\fi
+ \withname\gdef{\=zB:#4}{#1\zmark#2\zmark#3}%
+ \fi}
+
+% This macro loads the cite cross-reference entries and invokes the
+% specified macro for each one.
+
+\def \mapxrefcites #1{% {\macro}
+ {\let \zmapcitemacro = #1\relax
+ \zxloadcomp{\xrefloadcitemode}}}
+
+\def \xrefcite #1#2#3#4{% {page}{}{}{tag}
+ \ifnum \xrefmode=\xrefloadcitemode
+ \zmapcitemacro{#1}{#4}%
+ \fi}
+
+% Biblio Block
+% ------ -----
+
+
+\defineblock{\biblio}{\endbiblio}{\false}{}
+
+%~block biblio
+% \citestyle = integer % Citation style.
+% \setflag \indexcites = boolean % If true, index each cite (not implemented).
+% \setflag \citeself = boolean % If true, \bibitem cites itself (not implemented).
+%~end
+
+\definecount{\citestyle}{-1}
+
+\chardef \citebynumber = 0
+\chardef \citebykey = 1
+\chardef \citebyauthoryear = 2
+
+
+\def \biblio {%
+ \blockcantbein{\biblio}{\biblio}%
+ \blockmustbein{\biblio}{\list}%
+ \beginblockscope{biblio}%
+ \global\increment \bibliodepth
+ \setflag \citeself = \false %~default soft
+ \processdesign{\biblio}{}%
+ \global\increment \biblionumber}
+
+\def \endbiblio {%
+ \endgraf
+ \fakepar % In case biblio is empty.
+ \global\decrement \bibliodepth
+ \endblockscope{biblio}}
+
+% Bibliography Items
+% ------------ -----
+
+
+\definecount{\zbibitemnumber}{0}
+\definetoks{\zbibauthor}
+\definetoks{\zbibyear}
+\definetoks{\zbibfullauthor}
+\definetoks{\bibitemtag} % Tag of current \bibitem.
+
+
+%~ The |\bibitem| command is used in a |\biblio| block to start
+%~ each entry in the bibliography. It takes two arguments; the
+%~ format of the first argument depends on the citation style.
+%~ * Cited by number: |\bibitem{}{*tag*}|
+%~ * Cited by key: |\bibitem{*key*}{*tag*}|
+%~ * Cited by author/year: |\bibitem{*author*;*year*;*full-author*}{*tag*}|
+%~ *.
+%~ In the author/year format, the second semicolon and *full-author* are
+%~ optional.
+
+\def \bibitem #1#2{% {[info]}{tag}
+ \blockmustbein{\bibitem}{\biblio}%
+ \zbibitemnumber = \itemnumber
+ \increment \zbibitemnumber
+ \ifcase \citestyle
+ \edef \zbibkey {\the\zbibitemnumber}%
+ \zbibauthor = {}%
+ \zbibyear = {}%
+ \zbibfullauthor = {}%
+ \or
+ \def \zbibkey {#1}%
+ \zbibauthor = {}%
+ \zbibyear = {}%
+ \zbibfullauthor = {}%
+ \or
+ \def \zbibkey {}%
+ \zparseauthoryear #1;;;\zmark
+ \else
+ \error{invalidcitestyle}{The \string\citestyle parameter is invalid: \the\citestyle}%
+ \fi
+ \bibitemtag = {#2}%
+ \item{\zbibkey}%
+ \if \PDFhyperlinks \PDFmark{T:#2}\fi
+ \if \notp{\emptyargp{#2}}%
+ \edef \znext {%
+ \noexpand\xref{bib}{\noexpand\folio}
+ {\zbibkey}
+ {{\the\zbibauthor}{\the\zbibyear}{\the\zbibfullauthor}}
+ {#2}}%
+ \znext
+ \fi
+%%% \if \indexcites
+%%% \edef \znext {\noexpand\xbiblio1{\the\zbibauthor}}%
+%%% \znext
+%%% \fi
+ \ignorespaces}
+
+\def \zparseauthoryear #1;#2;#3;#4\zmark{%
+ \if \orp{\emptyargp{#1}}{\emptyargp{#2}}%
+ \error{nocitetags}{The author and/or year are missing}%
+ \fi
+ \zbibauthor = {#1}%
+ \zbibyear = {#2}%
+ \zbibfullauthor = {#3}}
+
+% Bibliography Citation Page List
+% ------------ -------- ---- ----
+
+
+\setflag \zcitexrefsloaded = \false
+
+
+%~ If this macro is specified as the |\endpartext| of a bibliography
+%~ |\list|, then each entry in the bibliography will include a list
+%~ of the pages citing that entry. The argument determines whether
+%~ each page is made into a hyperlinked PDF button.
+%~
+%~ In order for the citation information to be available, the
+%~ |\xrefcites| document parameter must be set to 1.
+
+\def \citepagelist #1{% {button?}
+ \if \notp{\zcitexrefsloaded}%
+ \mapxrefcites{\zbibcitelist}%
+ \global\setflag \zcitexrefsloaded = \true
+ \fi
+ \setflag \zbibfirstpage = \true
+ \def \zbibprevpage {}%
+ \withname\maplistlf {\=citetag:\the\bibitemtag}
+ {\zbibcitepage{##1}{#1}}}
+
+\def \zbibcitelist #1#2{% {page}{tag}
+ \if \withname\undefinedp {\=citetag:#2}%
+ \withname\setlist {\=citetag:#2}={}%
+ \fi
+ \withname\appendlf {\=citetag:#2}{#1}}
+
+\def \zbibcitepage #1#2{% {page}{button?}
+ \stringeql{\zsamepage}{#1}{\zbibprevpage}%
+ \if \notp{\zsamepage}%
+ \if \notp{\emptydefp{\zbibprevpage}},\space \fi
+ \if #2%
+ \pagebutton{#1}{#1}%
+ \else
+ #1%
+ \fi
+ \def \zbibprevpage {#1}%
+ \fi}
+
+% Low-Level Citation Commands
+% --------- -------- --------
+
+
+%~ This command produces the key of the bibliography entry specified
+%~ by the *tag*. The command makes sense only for the numbered or
+%~ keyed citation styles.
+
+\def \citekey #1{% {tag} %^citation
+ \if \eqlp{\citestyle}{\citebyauthoryear}%
+ \warning{badcitekey}{The \noexpand\citekey command doesn't make sense
+ when citing by author/year}%
+ \fi
+ \zcitetaginfo{#1}%
+ \zcitetext{#1}{\zcitekey}%
+ \zxrefcite{\true}{#1}}
+%%% \if \indexcites \zciteindex{\zcitekey}\fi}
+
+%~ This command produces the author of the bibliography entry specified
+%~ by the *tag*. The command makes sense only for the author/year
+%~ citation style.
+
+\def \citeauthor #1{% {tag} %^citation
+ \if \neqlp{\citestyle}{\citebyauthoryear}%
+ \warning{badciteauthor}{The \noexpand\citeauthor command only makes sense
+ when citing by author/year}%
+ \fi
+ \zcitetaginfo{#1}%
+ \zcitetext{#1}{\zciteauthor}%
+ \zxrefcite{\true}{#1}}
+
+%~ This command produces the year of the bibliography entry specified
+%~ by the *tag*. The command makes sense only for the author/year
+%~ citation style.
+
+\def \citeyear #1{% {tag} %^citation
+ \if \neqlp{\citestyle}{\citebyauthoryear}%
+ \warning{badciteyear}{The \noexpand\citeyear command only makes sense
+ when citing by author/year}%
+ \fi
+ \zcitetaginfo{#1}%
+ \zcitetext{#1}{\zciteyear}%
+ \zxrefcite{\true}{#1}}
+
+%~ This command produces the full author of the bibliography entry specified
+%~ by the *tag*. The command makes sense only for the author/year
+%~ citation style.
+
+\def \citefullauthor #1{% {tag} %^citation
+ \if \neqlp{\citestyle}{\citebyauthoryear}%
+ \warning{badcitefullauthor}{The \noexpand\citefullauthor command only makes sense
+ when citing by author/year}%
+ \fi
+ \zcitetaginfo{#1}%
+ \zcitetext{#1}{\zcitefullauthor}%
+ \zxrefcite{\true}{#1}}
+
+\def \zcitetaginfo #1{% {tag}
+ \zcitenoinfo
+ \if \definedp{\=zB:#1}%
+ \expandafterthrice\zcitetaginfoa \name{\=zB:#1}%
+ \else
+ \writelog{ZzTeX citation: undefined tag `#1'.}%
+ \zxwriteinfo{\false}{undef-tag}{#1}{}%
+ \global\increment \zuntagrefs
+ \fi}
+
+\def \zcitetaginfoa #1\zmark#2\zmark#3#4#5{% folio\zmark key\zmark
+ % {author}{year}{full-author}
+ \if \eqlp{\citestyle}{\citebyauthoryear}%
+ \def \zciteauthor {#3}%
+ \def \zciteyear {#4}%
+ \def \zcitefullauthor {#5}%
+ \else
+ \def \zcitekey {#2}%
+ \fi}
+
+\def \zcitenoinfo {%
+ \def \zcitekey {???}%
+ \def \zciteauthor {???author???}%
+ \def \zciteyear {???}%
+ \def \zcitefullauthor {???full-author???}}
+
+\def \zcitetext #1#2{% {tag}{text}
+ \if \DVIWindoinuse \colorspecial{ifview color push rgb .5 .22 .24}\fi
+ \if \PDFhyperlinks
+ \tagbutton{#1}{#2}%
+ \else
+ #2%
+ \fi
+ \if \DVIWindoinuse \colorspecial{ifview color pop}\fi}
+
+\def \zxrefcite #1#2{% {defined?}{tag}
+ \ifcase \xrefcites
+ \relax
+ \or
+ \xref{cite}{\folio}{}{}{#2}%
+ \else
+ \customcitexref{#1}{#2}% {boolean}{tag}
+ \fi}
+
+%%%\def \zciteindex #1{% {\zcitemacro}
+%%% \expandafter\xcite\expandafter1\expandafter{#1}}
+
+% High-Level Citation Commands
+% ---------- -------- --------
+
+
+%~ This high-level citation command produces the key or author/year
+%~ of the bibliography entry specified by the *tag*. The text
+%~ is formatted in the style appropriate for a noun in a sentence.
+%~ There are two formats for the command:
+%~ * |\citenoun{*tag*}| accepts a tag and produces the key or author/year.
+%~ * |\citenoun{*tag*;*info*}| accepts a tag and additional
+%~ information such as a page number or section reference.
+%~ *.
+%~ The format of the text produced is controlled by the |\citenounformat|,
+%~ |\citenouninfoformat|, and |\citepunct| macros in the design file.
+
+\def \citenoun #1{% {tag[;info]} %^citation
+ \expandafter\zsetcitepunc \citepunct
+ \zcitetagsinfo #1;;\zmark
+ \def \zcitenounsep {}%
+ \expandafter\zcitenoun \zcitetags,\zmark}
+
+\def \zcitenoun #1,#2\zmark {% tag,other-tags\zmark
+ \zcitenounsep
+ \edef \zcitenounsep {\zcitesep}%
+ \if \eqlp{\citestyle}{\citebyauthoryear}%
+ \if \emptydefp{\zciteinfo}%
+ \zciteonetag{\citenounformat}#1!!\zmark
+ \else
+ \citenouninfoformat{\citeauthor{#1}}{\citeyear{#1}}{\zciteinfo}%
+ \fi
+ \else
+ \if \emptydefp{\zciteinfo}%
+ \citenounformat{\citekey{#1}}%
+ \else
+ \citenouninfoformat{\citekey{#1}}{\zciteinfo}%
+ \fi
+ \fi
+ \if \notp{\emptyargp{#2}}\zcitenoun #2\zmark \fi}
+
+%~ This high-level citation command produces the key or author/year
+%~ of the bibliography entry specified by the *tag*. The text
+%~ is formatted in the style appropriate for a parenthetical
+%~ citation list. There are two formats for the command:
+%~ * |\citeparen{*tag-list*}| accepts one or more tags separated
+%~ by commas and produces a parenthetical list of keys or author/years.
+%~ * |\citeparen{*tag*;*info*}| accepts a tag and additional
+%~ information such as a page number or section reference.
+%~ *.
+%~ The format of the text produced is controlled by the |\citeparenformat|,
+%~ |\citepareninfoformat|, and |\citepunct| macros in the design file.
+
+\def \citeparen #1{% {tags[;info]} %^citation
+ \expandafter\zsetcitepunc \citepunct
+ \zcitetagsinfo #1;;\zmark
+ \expandafter\zciteparen \zcitetags,\zmark
+ \zcitecfence}
+
+\def \zciteparen #1,#2\zmark {% tag,other-tags\zmark
+ \zciteofence
+ \edef \zciteofence {\zcitesep}%
+ \if \eqlp{\citestyle}{\citebyauthoryear}%
+ \if \emptydefp{\zciteinfo}%
+ \zciteonetag{\citeparenformat}#1!!\zmark
+ \else
+ \citepareninfoformat{\citeauthor{#1}}{\citeyear{#1}}{\zciteinfo}%
+ \fi
+ \else
+ \if \emptydefp{\zciteinfo}%
+ \citeparenformat{\citekey{#1}}%
+ \else
+ \citepareninfoformat{\citekey{#1}}{\zciteinfo}%
+ \fi
+ \fi
+ \if \notp{\emptyargp{#2}}\zciteparen #2\zmark \fi}
+
+%~ This high-level citation command produces the key or author/year
+%~ of the bibliography entry specified by the *tag*. The text
+%~ is formatted in the style appropriate for a citation that is part
+%~ of a surrounding parenthetical sentence.
+%~ There are two formats for the command:
+%~ * |\citeplain{*tag*}| accepts a tag and produces the key or author/year.
+%~ * |\citeplain{*tag*;*info*}| accepts a tag and additional
+%~ information such as a page number or section reference.
+%~ *.
+%~ The format of the text produced is controlled by the |\citeplainformat|
+%~ and |\citeplaininfoformat| macros in the design file.
+
+\def \citeplain #1{% {tag[;info]} %^citation
+ \zcitetagsinfo #1;;\zmark
+ \expandafter\zciteplain \zcitetags,\zmark}
+
+\def \zciteplain #1,#2\zmark {% tag,other-tags\zmark
+ \if \eqlp{\citestyle}{\citebyauthoryear}%
+ \if \emptydefp{\zciteinfo}%
+ \zciteonetag{\citeparenformat}#1!!\zmark
+ \else
+ \citepareninfoformat{\citeauthor{#1}}{\citeyear{#1}}{\zciteinfo}%
+ \fi
+ \else
+ \if \emptydefp{\zciteinfo}%
+ \citeparenformat{\citekey{#1}}%
+ \else
+ \citepareninfoformat{\citekey{#1}}{\zciteinfo}%
+ \fi
+ \fi
+ \if \notp{\emptyargp{#2}}\zciteplain #2\zmark \fi}
+
+\def \zsetcitepunc #1#2#3{%
+ \def \zciteofence {#1}%
+ \def \zcitecfence {#2}%
+ \def \zcitesep {#3}}
+
+\def \zcitetagsinfo #1;#2;#3\zmark {% {tags[;info]}
+ \if \emptyargp{#1}%
+ \warning{nocitetags}{No bibliography entry tags were specified}%
+ \fi
+ \def \zcitetags {#1}%
+ \def \zciteinfo {#2}}
+
+\def \zciteonetag #1#2!#3!#4\zmark {%
+ \if \emptyargp{#2}%
+ \citeyear{#3}%
+ \else
+ #1{\citeauthor{#2}}{\citeyear{#2}}%
+ \fi} \ No newline at end of file
diff --git a/macros/plain/contrib/zztex/tex/zzbibtex.tex b/macros/plain/contrib/zztex/tex/zzbibtex.tex
new file mode 100644
index 0000000000..a6179133f8
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzbibtex.tex
@@ -0,0 +1,290 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Interface to BibTeX
+%
+% Synopsis: This module provides the definitions necessary for ZzTeX to
+% interface to BibTeX.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 21 July 1992
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Bibliography Preparation
+% ------------ -----------
+
+
+\def \zbiblioinit {}
+
+\ignore
+\setflag \zbiblioing = \false
+
+\def \preparebiblio {%
+ \setflag \zbiblioing = \true}
+
+\def \zbibfinal {%
+ \if \zbiblioing
+ \remark{[Generating auxiliary file for BibTeX.}%
+ {\immediate\openout \zwritea = \jobname.aux\relax
+ \immediate\write \zwritea
+ {\zcomment BibTeX auxiliary file for book `\jobname'.}%
+ \processdesign{\biblio}{}%
+ \immediate\write \zwritea {\string\bibstyle{\the\bibliostyle}}%
+ \immediate\write \zwritea {\string\bibdata{\the\bibliofiles}}%
+ \let \zxmodesave = \xrefmode
+ \let \xrefmode = \xrefloadauxmode
+ \input \jobname.zzc\relax
+ \let \xrefmode = \zxmodesave
+ \immediate\write \zwritea {\zcomment [end]}%
+ \immediate\closeout \zwritea}
+ \remark{Auxiliary file complete.]}%
+ \fi}
+
+\endignore
+
+% Citations
+% ---------
+
+
+%~ This citation command produces the key associated with
+%~ the specified tag. The key is usually the bibliography
+%~ entry number or the author/year combination.&/
+%~ *Note:* Some books do not allow this command to be used.
+
+\def \cite #1{% {tag} %^citation
+ \ensurepar
+ \if \definedp{\=zB:#1}%
+ \zcitetext{#1}{\expandafterthrice\zbibdata \name{\=zB:#1}0}%
+ \else
+ \zuncite{#1}%
+ \fi
+ \zxrefcite{\true}{#1}}
+
+%~ This citation command produces the author associated with
+%~ the specified tag.
+
+\def \citeauthor #1{% {tag} %^citation
+ \ensurepar
+ \if \definedp{\=zB:#1}%
+ \zcitetext{#1}{\expandafterthrice\zbibdata \name{\=zB:#1}1}%
+ \else
+ \zuncite{#1}%
+ \fi
+ \zxrefcite{\true}{#1}}
+
+%~ This citation command produces the year associated with
+%~ the specified tag.
+
+\def \citeyear #1{% {tag} %^citation
+ \ensurepar
+ \if \definedp{\=zB:#1}%
+ \zcitetext{#1}{\expandafterthrice\zbibdata \name{\=zB:#1}2}%
+ \else
+ \zuncite{#1}%
+ \fi
+ \zxrefcite{\true}{#1}}
+
+\def \nocite #1{% {tag}
+ \zxrefcite{\false}{#1}}
+
+\def \zcitetext #1#2{% {tag}{text}
+ \if \PDFhyperlinks
+ \tagbutton{#1}{#2}%
+ \else
+ #2%
+ \fi}
+
+\def \zxrefcite #1#2{%
+ \ifcase \xrefcites
+ \relax
+ \or
+ \xref{cite}{\folio}{}{}{#2}%
+ \else
+ \customcitexref{#1}{#2}% {boolean}{tag}
+ \fi}
+
+\def \zbibdata #1\zmark#2\zmark#3#4#5#6{% folio\zmark xxx\zmark
+ % {label}{author}{year}n
+ \if \DVIWindoinuse \colorspecial{ifview color push rgb .75 .35 0}\fi
+ \ifcase #6 #3\or #4\or #5\fi
+ \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
+ \if \indexcites \xcite1{#4}\fi}
+
+\def \zuncite #1{%
+ \writelog{ZzTeX citation: undefined tag `#1'.}%
+ \zxwriteinfo{\false}{undef-tag}{#1}{}%
+ \global\increment \zuntagrefs
+ \zbibdata -\zmark-\zmark{???}--0}
+
+% Bibliography Cross-Reference
+% ------------ ---------------
+
+
+% When tags are loaded, define the name \=zB:tag to contain the
+% bibliographic info.
+
+\def \xrefbib #1#2#3#4{% {page}{???}{{label}{author}{year}}{tag}
+ \ifnum \xrefmode=\xrefloadtagmode
+ \if \definedp{\=zB:#4}\zduptag{#4}\fi
+ \withname\gdef{\=zB:#4}{#1\zmark#2\zmark#3}%
+ \fi}
+
+% This macro loads the cite cross-reference entries and invokes the
+% specified macro for each one.
+
+\def \mapxrefcites #1{% {\macro}
+ {\let \zmapcitemacro = #1\relax
+ \zxloadcomp{\xrefloadcitemode}}}
+
+\def \xrefcite #1#2#3#4{% {page}{}{}{tag}
+ \ifnum \xrefmode=\xrefloadcitemode
+ \zmapcitemacro{#1}{#4}%
+ \fi}
+
+% Biblio Block
+% ------ -----
+
+
+\defineblock{\biblio}{\endbiblio}{\false}{}
+
+%~block biblio
+% \bibliofiles = {file,...} % List of biblio database files.
+% \bibliostyle = {name} % Name of biblio style.
+% \setflag \citeself = boolean % If true, \bibitem cites itself.
+%~end
+
+\definetoks{\bibliofiles}
+\definetoks{\bibliostyle}
+
+\definecount{\zbiblionum}{0}
+
+
+\def \biblio {%
+ \blockcantbein{\biblio}{\biblio}%
+ \blockmustbein{\biblio}{\list}%
+ \beginblockscope{biblio}%
+ \global\increment \bibliodepth
+ \setflag \citeself = \false %~default soft
+ \processdesign{\biblio}{}%
+ \global\increment \biblionumber
+ \def \begin ##1##2{}%
+ \def \end ##1{}%
+ \let \bibitem = \zbibitem
+ \let \newblock = \relax
+ \let \em = \it
+ \zbiblionum = 0\relax}
+
+\def \endbiblio {%
+ \endgraf
+ \fakepar % In case biblio is empty.
+ \global\decrement \bibliodepth
+ \endblockscope{biblio}}
+
+% Bibliography Item
+% ------------ ----
+
+
+\definetoks{\zbibtoksa}
+\definetoks{\zbibtoksb}
+\definetoks{\zbibtoksc}
+\definetoks{\bibitemtag} % Tag of current \bibitem.
+
+
+% This supports items of the form `\bibitem[label][author][year]{tag}'.
+
+\def \zbibitem {%
+ \futurelet\znext \zbibitema}
+
+\def \zbibitema {%
+ \ifx \znext[%
+ \let \znext = \zbibitemb
+ \else
+ \increment \zbiblionum
+ % Expand \number\zbiblionum by hand.
+ \edef \znext {\noexpand\zbibitemb[\number\zbiblionum]}%
+ \fi
+ \znext}
+
+\def \zbibitemb[#1]{% [label]
+ \zbibtoksa = {#1}%
+ \futurelet\znext \zbibitemc}
+
+\def \zbibitemc {%
+ \if \tokeqlp{\znext}{[}%
+ \let \znext = \zbibitemd
+ \else
+ \def \znext {\zbibitemd[???]}%
+ \fi
+ \znext}
+
+\def \zbibitemd[#1]{% [author]
+ \zbibtoksb = {#1}%
+ \futurelet\znext \zbibiteme}
+
+\def \zbibiteme {%
+ \if \tokeqlp{\znext}{[}%
+ \let \znext = \zbibitemf
+ \else
+ \def \znext {\zbibitemf[???]}%
+ \fi
+ \znext}
+
+\def \zbibitemf[#1]#2{% [year]{tag}
+ \zbibtoksc = {#1}%
+ \bibitemtag = {#2}%
+ \item{\the\zbibtoksa}%
+ \if \PDFhyperlinks \PDFmark{T:#2}\fi
+ \if \notp{\emptyargp{#2}}%
+ \edef \znext{\noexpand\xref{bib}{\noexpand\folio}
+ {???}
+ {{\the\zbibtoksa}{\the\zbibtoksb}{\the\zbibtoksc}}
+ {#2}}%
+ \znext
+ \if \citeself \nocite{#2}\fi
+ \fi
+ \if \indexcites
+ \edef \znext {\noexpand\xbiblio1{\the\zbibtoksb}}%
+ \znext
+ \fi
+ \ignorespaces}
+
+% Bibliography Citation Page List
+% ------------ -------- ---- ----
+
+
+\setflag \zcitexrefsloaded = \false
+
+
+% If this macro is specified as the \endpartext of a bibliography
+% list, it will append a list of the citation pages to each entry.
+
+\def \citepagelist #1{% {button?}
+ \if \notp{\zcitexrefsloaded}%
+ \mapxrefcites{\zbibcitelist}%
+ \global\setflag \zcitexrefsloaded = \true
+ \fi
+ \setflag \zbibfirstpage = \true
+ \def \zbibprevpage {}%
+ \withname\maplistlf {\=citetag:\the\bibitemtag}
+ {\zbibcitepage{##1}{#1}}}
+
+\def \zbibcitelist #1#2{% {page}{tag}
+ \if \withname\undefinedp {\=citetag:#2}%
+ \withname\setlist {\=citetag:#2}={}%
+ \fi
+ \withname\appendlf {\=citetag:#2}{#1}}
+
+\def \zbibcitepage #1#2{% {page}{button?}
+ \stringeql{\zsamepage}{#1}{\zbibprevpage}%
+ \if \notp{\zsamepage}%
+ \if \notp{\emptydefp{\zbibprevpage}},\space \fi
+ \if #2%
+ \pagebutton{#1}{#1}%
+ \else
+ #1%
+ \fi
+ \def \zbibprevpage {#1}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zzblock.tex b/macros/plain/contrib/zztex/tex/zzblock.tex
new file mode 100644
index 0000000000..989bb4363b
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzblock.tex
@@ -0,0 +1,327 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Blocks
+%
+% Synopsis: This module provides facilities for defining and creating
+% element blocks.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 23 August 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Block Definition
+% ----- ----------
+
+
+\setlist \zblocklist = {}
+
+\def \defineblock #1#2#3#4{% {\name}{\endname}{snap?}{redefine}
+ \if \emptyargp{#4}%
+ \withname\definecount{#1depth}{0}%
+ \withname\definecount{#1number}{0}%
+ \withname\definetoks{#1comptext}%
+ \withname\gdef{#1varinit}{}%
+ \if #3\withname\declaresnapitem{#1number}\fi
+ \append{#1}{\zblocklist}%
+ \fi}
+
+\def \resetinvcontext #1{% {\name}
+ \zdeclareeveryvcontext{\zblockvcontext{#1}}}
+
+\def \zblockvcontext #1{% {\name}
+ \zsavevcontext{\name{#1depth}=\the\name{#1depth}%
+ \name{#1number}=\the\name{#1number}%
+ \name{#1comptext}={\the\name{#1comptext}}}%
+ \global\name{#1depth}= 0\relax
+ \global\name{#1number}= 0\relax}
+
+% Block Utilities
+% ----- ---------
+
+
+\defineskip{\enclosingbaselineskip}{0pt}
+\defineskip{\enclosingleftss}{0pt}
+\definedimen{\enclosingparindent}{0pt}
+\definedimen{\enclosingparrag}{0pt}
+\defineskip{\enclosingparskip}{0pt}
+\defineskip{\enclosingrightss}{0pt}
+
+
+\def \beginblockscope #1{%
+ \begingroup
+ \zpushblock{#1}%
+ \enclosingbaselineskip = \baselineskip
+ \enclosingleftss = \leftskip
+ \tdimena = \leftskip
+ \advance \enclosingleftss by -\tdimena
+ \enclosingparindent = \parindent
+ \enclosingparrag = \parrag
+ \enclosingparskip = \parskip
+ \enclosingrightss = \rightskip
+ \tdimena = \rightskip
+ \advance \enclosingrightss by -\tdimena}
+
+\def \endblockscope #1{%
+ \zpopblock{#1}%
+ \endgroup}
+
+\def \processdesign #1#2{% {\block}{type etc.}
+ \zprocessvariant{#1}%
+ \resetnumber = {}%
+ \if \definedp{#1#2design}%
+ \name{#1#2design}\relax % \relax terminates numbers and such.
+ \else
+ \error{nodesign}{No design has been defined for the `\string#1#2' block}%
+ \fi
+ \zprocesswith
+ {\globaldefs = 1 \the\resetnumber}}
+
+\def \inblockp #1{% {\block-name}
+ \if \posp{\name{#1depth}}\true \else \false \fi}
+
+\def \setcomptext #1{% {\xxxcomptext}
+ \edef \znext {\comptextformat}%
+ #1= \expandafter{\znext}}%
+
+\def \blockmustbein #1#2{% {\inner}{\outer}
+ \if \zerop{\name{#2depth}}%
+ \error{blkmustnest}{A `\string#1' must be nested in a `\string#2'}%
+ \fi}
+
+\def \blockcantbein #1#2{% {\inner}{\outer}
+ \if \posp{\name{#2depth}}%
+ \error{blkcantnest}
+ {A `\string#1' cannot be nested inside a `\string#2'}%
+ \fi}
+
+\def \closeifinblock #1#2{% {\block}{\endblock}
+ \if \inblockp{#1}#2\fi}
+
+% Block Stack
+% ----- -----
+
+
+\setlist \zblockstack = {}
+\setlist \zlinestack = {}
+
+\def \zpushblock #1{%
+ \push{#1}{\zblockstack}%
+ \edef \znext {\noexpand\push{\the\inputlineno}}%
+ \znext{\zlinestack}}
+
+\def \zpopblock #1{%
+ \pop{\zblk}{\zblockstack}%
+ \pop{\zline}{\zlinestack}%
+ \stringeql{\znext}{\zblk}{#1}%
+ \if \notp{\znext}%
+ \error{blkinvnest}{The `\string\end#1' command does not match the
+ `\zblk' block that was started on line \zline}%
+ \fi}
+
+\def \zemptyblockstackp {\emptylistp{\zblockstack}}
+
+% Block Variants
+% ----- --------
+
+
+\def \definevariant #1#2#3{% {\block}{\style}{\modifier0,\modifier1,...}
+ \if \emptyargp{#3}%
+ \error{varmod}{Between 1 and 8 modifier commands must be specified}%
+ \fi
+ \withname\definecount{#2variant}{0}%
+ \withname\xdef{#1varinit}{\name{#1varinit}\name{#2variant}=0}%
+ {\tcounta = 0
+ \zdefvarpre #2#3,\zmark
+ \if \gtrp{\tcounta}{8}%
+ \error{varmod}{Between 1 and 8 modifier commands must be specified}%
+ \fi
+ \ztoksa = \expandaftertwice{\name{\zvarcase\lcromannumeral\tcounta}}%
+ \edef \znext {\global\let \name{#2varcase}=\the\ztoksa}%
+ \znext}}
+
+\def \zdefvarpre #1#2,#3\zmark{% \style\modifier,\modifier,...,\zmark
+ \xdef #2{\noexpand\variant{\name{#1variant}=\the\tcounta}}%
+ \increment \tcounta
+ \if \notp{\emptyargp{#3}}\zdefvarpre #1#3\zmark \fi}
+
+\gdef \zvariant {} % Holds \stylevariant assignments.
+
+\def \variant #1{% {\stylevariant assignment}
+ {\ztoksa = \expandafter{\zvariant}%
+ \ztoksb = {#1}%
+ \xdef \zvariant {\the\ztoksa \the\ztoksb}}%
+ \ignorespaces}
+
+\def \zprocessvariant #1{% {\block}
+ \name{#1varinit}%
+ \zvariant \relax % \relax terminates numbers and such.
+ \gdef \zvariant {}}
+
+\def \varcase #1{% \style
+ \name{#1varcase}#1}
+
+\long\def \zvarcasei #1#2{% \style {var1 code}
+ \ifcase \name{#1variant}#2\else\zbadvar\fi\relax}
+\long\def \zvarcaseii #1#2#3{% \style {var1 code}{var2 code}
+ \ifcase \name{#1variant}#2\or#3\else\zbadvar\fi\relax}
+\long\def \zvarcaseiii #1#2#3#4{%
+ \ifcase \name{#1variant}#2\or#3\or#4\else\zbadvar\fi\relax}
+\long\def \zvarcaseiv #1#2#3#4#5{%
+ \ifcase \name{#1variant}#2\or#3\or#4\or#5\else\zbadvar\fi\relax}
+\long\def \zvarcasev #1#2#3#4#5#6{%
+ \ifcase \name{#1variant}#2\or#3\or#4\or#5\or#6\else\zbadvar\fi\relax}
+\long\def \zvarcasevi #1#2#3#4#5#6#7{%
+ \ifcase \name{#1variant}#2\or#3\or#4\or#5\or#6\or#7\else\zbadvar\fi\relax}
+\long\def \zvarcasevii #1#2#3#4#5#6#7#8{%
+ \ifcase \name{#1variant}#2\or#3\or#4\or#5\or#6\or#7\or#8\else\zbadvar\fi\relax}
+\long\def \zvarcaseviii #1#2#3#4#5#6#7#8#9{%
+ \ifcase\name{#1variant}#2\or#3\or#4\or#5\or#6\or#7\or#8\or#9\else\zbadvar\fi\relax}
+
+\def \setvariant #1{% \modifier
+ #1%
+ \zvariant \relax
+ \gdef \zvariant {}}
+
+\def \zbadvar {%
+ \zzerror{Invalid value for variant}}
+
+% Block Options
+% ----- -------
+
+
+\gdef \zwith {} % Holds \with parameters.
+
+
+%~ The |\with| modifier can be used to modify specific design
+%~ parameters for the following block. It only makes sense
+%~ preceding block commands. Sometimes it is used with parameters
+%~ that are specifically intended for |\with|:
+%~ \with{\itemnumber=4} \list{number}
+%~ Other times it is used with a parameter that needs to be
+%~ changed for one particular block.
+%~ \with{\advance\belowskip by -8pt} \float{figure}
+%~ Again, be careful to use |\with| only on block commands.
+
+\long\def \with #1{% {parameter-assignments} %^modifier
+ {\ztoksa = \expandafter{\zwith}%
+ \ztoksb = {#1}%
+ \xdef \zwith {\the\ztoksa \the\ztoksb}}%
+ \ignorespaces}
+
+\def \zprocesswith {%
+ \zwith \relax % \relax terminates numbers and such.
+ \gdef \zwith {}}
+
+%~ This block modifier forces a page break above the block.
+
+\def \breakabove {% %^modifier
+ \with{\abovepenalty=\breakalways}}
+
+%~ This block modifier forces a page break below the block.
+
+\def \breakbelow {% %^modifier
+ \with{\belowpenalty=\breakalways}}
+
+% Common Design Parameters
+% ------ ------ ----------
+
+
+% These design parameters are used by a variety of ZZTeX's blocks, so
+% they are defined here.
+
+% Integer parameters:
+
+\definecount{\abovepenalty}{0} % Penalty above block.
+\definecount{\authorlevel}{0} % Author ToC entry level.
+\definecount{\belowpenalty}{0} % Penalty below block.
+\definecount{\continue}{0} % Block is continued (bit 0) and/or continuation (bit 1).
+\definecount{\difficulty}{0} % Level of difficulty of the block.
+
+% Flag parameters:
+
+\setflag \allowbreaks = \false % Allow page breaks in block?
+\setflag \allowintoc = \false % Allow section in ToC?
+
+% Dimension parameters:
+
+\definedimen{\height}{0pt} % Height of text.
+\definedimen{\ruleshift}{0pt} % Horizontal shift for rule.
+\definedimen{\ruleheight}{0pt} % Height (thickness) of rule.
+\definedimen{\rulewidth}{0pt} % Width of rule.
+\definedimen{\topadjust}{\mindimen} % Adjustment for head at top of page.
+\definedimen{\vshift}{0pt} % Vertical shift.
+\definedimen{\width}{0pt} % Width of text.
+
+% Skip (glue) parameters:
+
+\defineskip{\aboveskip}{0pt} % Base/base skip above block.
+\defineskip{\belowskip}{0pt} % Base/base skip below block.
+\defineskip{\columngutter}{0pt} % Width of gutter between columns.
+\defineskip{\interrowskip}{0pt} % Extra space between rows.
+\defineskip{\leftindent}{0pt} % Left indentation glue.
+\defineskip{\numbersink}{0pt} % Sinkage to section number, or
+\defineskip{\numberskip}{0pt} % Space b/b to section number.
+\defineskip{\parhang}{0pt} % Hanging indent for paragraph.
+\defineskip{\rightindent}{0pt} % Right indentation glue.
+\defineskip{\ruleskip}{0pt} % Vskip for rule.
+\defineskip{\textsink}{0pt} % Vsink for text.
+\defineskip{\textskip}{0pt} % Base/base skip for text.
+\defineskip{\titlesink}{0pt} % Sinkage to section title, or
+\defineskip{\titleskip}{0pt} % Space b/b to section title.
+
+% Token list parameters:
+
+\definetoks{\authortext} % Part/chapter author text.
+\definetoks{\bodyfont} % Font for body of block.
+\definetoks{\divisions} % List of division names.
+\definetoks{\numberfont} % Font for block number.
+\definetoks{\numberwordfont} % Font for block word like "chapter".
+\definetoks{\openertext} % Part/chapter opener text.
+\definetoks{\position} % Position of the block.
+\definetoks{\resetnumber} % List of sequence numbers to reset.
+\definetoks{\rulecolor} % Color of a rule.
+\definetoks{\runners} % Running head/foot macros.
+\definetoks{\style} % Heading style.
+\definetoks{\textcolor} % Color of text.
+\definetoks{\titlefont} % Font for title.
+
+% Macro parameters:
+
+\def \numberformat #1{} % {code} %~ Formatter for block number.
+\def \paging {} % {code} %~ Page control commands.
+\def \providemark #1{} % {code} %~ Provide marks for the block.
+\def \titleformat {} % {code} %~ Formatter for title.
+
+% The \continue Parameter
+% --- --------- ---------
+
+
+% The \continue parameter is set as follows:
+% 0: neither continued nor continuation
+% 1: continued
+% 2: continuation
+% 3: both continuation and continued
+
+
+\def \continuedp {\oddp{\continue}}
+
+\def \continuationp {\gtrp{\continue}{1}}
+
+\def \zsetcontinue {%
+ \if \andp{\zerop{\continue}}{\continuation}%
+ \continue = 2\relax
+ \fi}
+
+% Break Element
+% ----- -------
+
+
+\long\def \breakelement #1{%
+ \global\setflag \zinpar = {\hmodep}%
+ \if \zinpar \flushendpar \fi
+ #1%
+ \if \zinpar \noindent \ignorespaces \fi} \ No newline at end of file
diff --git a/macros/plain/contrib/zztex/tex/zzcmmath.tex b/macros/plain/contrib/zztex/tex/zzcmmath.tex
new file mode 100644
index 0000000000..a7c3f9f24b
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzcmmath.tex
@@ -0,0 +1,15 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: Computer Modern math font support
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+% Not really much to do.
+
+\setstyleskewchar{\mit}{"7F}
+\setstyleskewchar{\msy}{"30}
+
diff --git a/macros/plain/contrib/zztex/tex/zzcomenc.tex b/macros/plain/contrib/zztex/tex/zzcomenc.tex
new file mode 100644
index 0000000000..4fecdcdfeb
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzcomenc.tex
@@ -0,0 +1,153 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: Redefinitions for Common Encoding
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+% Redefine accents.
+
+\def \"#1{{\accent 8 #1}} %~ Umlaut accent. %^accent
+
+\def \.#1{{\accent 11 #1}} %~ Dot accent. %^accent
+
+\def \H #1{{\accent 12 #1}} %~ Long Hungarian umlaut accent. %^accent
+
+\def \^#1{{\accent 7 #1}} %~ Circumflex accent. %^accent
+
+\def \g #1{% %~ Ogonek accent. %^accent
+ \setbox \zboxa = \hbox{#1}%
+ \if \dimeqlp{\ht\zboxa}{1ex}%
+ \accent 14 #1%
+ \else
+ {\ooalign{\hidewidth \char 14 \hidewidth \cr
+ \unhbox \zboxa}}%
+ \fi}
+
+\def \~#1{{\accent 15 #1}} %~ Tilde accent. %^accent
+
+
+% Redefine standard ASCII characters.
+
+\def \udquote {% %~ Undirected double quote. %^named_char
+ \ensurepar
+ \char "22\relax}
+
+\def \dollar {% %~ Dollar sign. %^named_char
+ \zprehyph{\dollarhyph}%
+ \char "24\relax
+ \zposthyph{\dollarhyph}}
+
+\let \$ = \dollar
+
+\def \less {% %~ Less-than sign. %^named_char
+ \ensurepar
+ \char "3C\relax}
+
+\let \< = \relax
+
+\def \greater {% %~ Greater-than sign. %^named_char
+ \ensurepar
+ \char "3E\relax}
+
+\let \> = \relax
+
+\def \backslash {% %~ Backslash. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmbackslash
+ \else
+ \char "5C\relax
+ \fi}
+
+\let \\ = \backslash
+
+\def \underscore {% %~ Underscore. %^named_char
+ \ensurepar
+ \zprehyph{\underscorehyph}%
+ \char "5F\relax
+ \zposthyph{\underscorehyph}}
+
+\let \_ = \underscore
+
+\def \lbrace {% %~ Left brace. %^named_char
+ \relax
+ \if \mathmodep
+ \zmlbrace
+ \else
+ \char "7B\relax
+ \fi}
+
+\let \{ = \lbrace
+
+\def \verticalbar {% %~ Vertical bar. %^named_char
+ \ensurepar
+ \char "7C\relax}
+
+\def \rbrace {% %~ Right brace. %^named_char
+ \relax
+ \if \mathmodep
+ \zmrbrace
+ \else
+ \char "7D\relax
+ \fi}
+
+\let \} = \rbrace
+
+
+% Define additional special characters.
+
+\def \specialchar #1#2{% {text-char}{math-char}
+ \ensurepar
+ \if \mathmodep
+ \if \emptyargp{#2}%
+ \error{scinmath}{Cannot use that special character in math mode}%
+ \else
+ #2\relax
+ \fi
+ \else
+ #1\relax
+ \fi}
+
+% Decided not to make these two characters pseudo-ligatures.
+
+\def \exclamdown {\specialchar{\char 142}{}} %~ Upside-down exclamation.
+\def \questiondown {\specialchar{\char 143}{}} %~ Upside-down question mark.
+
+\def \bullet {\specialchar{\char 150}{\zmbullet}} %~ Bullet.
+\def \cent {\specialchar{\char 151}{}} %~ Cent sign.
+\let \cents = \cent
+\def \copyright {\specialchar{\char 152}{}} %~ Copyright symbol.
+\def \currency {\specialchar{\char 153}{}} %~ Currency symbol.
+\def \dagger {\specialchar{\char 154}{\zmdagger}} %~ Dagger.
+\def \ddagger {\specialchar{\char 155}{\zmddagger}}%~ Double dagger.
+\def \degree {\specialchar{\char 156}{^\circ}} %~ Degree sign.
+\let \degrees = \degree
+\def \Edh {\specialchar{\char 157}{}} %~ Uppercase Edh.
+\def \edh {\specialchar{\char 158}{}} %~ Lowercase edh.
+\def \euro {\specialchar{\char 159}{}} %~ Euro symbol.
+\def \florin {\specialchar{\char 160}{}} %~ Florin.
+\def \lguill {\specialchar{\char 161}{}} %~ Left guillemot.
+\def \rguill {\specialchar{\char 162}{}} %~ Right guillemot.
+\def \L {\specialchar{\char 163}{}} %~ Uppercase Polish L.
+\def \l {\specialchar{\char 164}{}} %~ Lowercase Polish l.
+\def \minus {\specialchar{\char 165}{}} %~ Minus sign.
+\def \P {\specialchar{\char 166}{}} %~ Paragraph symbol (pilcrow).
+\def \perthousand {\specialchar{\char 167}{}} %~ Per thousand symbol.
+\def \usquote {\specialchar{\char 168}{}} %~ Undirected single quote.
+\def \registered {\specialchar{$^\roman{\char 169}$}{}} %~ Registered symbol.
+\def \S {\specialchar{\char 170}{}} %~ Section sign.
+\def \SS {\specialchar{\char 170\kern -.1em\char 170}{}} %~ Double section sign.
+\def \sterling {\specialchar{\char 171}{}} %~ Pound sterling symbol.
+\def \Thorn {\specialchar{\char 172}{}} %~ Uppercase Thorn.
+\def \thorn {\specialchar{\char 173}{}} %~ Lowercase thorn.
+\def \trademark {\specialchar{$^\roman{\char 174}$}{}} %~ Trademark symbol.
+\def \yen {\specialchar{\char 175}{}} %~ Yen symbol.
+
+% Redefine a few math things.
+
+\definemathchar{\zmdagger}{\classbinop}{\rmfam}{9A}
+\definemathchar{\zmddagger}{\classbinop}{\rmfam}{9B}
diff --git a/macros/plain/contrib/zztex/tex/zzdiv.tex b/macros/plain/contrib/zztex/tex/zzdiv.tex
new file mode 100644
index 0000000000..509fd4910c
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzdiv.tex
@@ -0,0 +1,128 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Division Facilities
+%
+% Synopsis: This module contains the macros to support divisions, which
+% allow a book to be processed in pieces.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 September 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Divisions
+% ---------
+
+
+\def \zdivext {tex}
+
+\definetoks{\divisionname} % Name of current division.
+\definetoks{\zdivreq} % Divisions requested with \setdivisions.
+\zdivreq = {\all}
+\definetoks{\zdivset} % Divisions set.
+\setlist \zdivset = {}
+
+
+%~ This command is used in the book's root file to specify
+%~ the list of divisions that should be processed by ZzTeX.
+%~ All other divisions are not processed. If the command
+%~ does not appear in the root file, all divisions are processed.
+
+\def \setdivisions #1{% {division,...}
+ \if \emptyargp{#1}%
+ \warning{nodivs}{The \noexpand\setdivisions command does not specify any divisions}
+ \else
+ \global\zdivreq = {#1}%
+ \fi}
+
+%~ This command is used in the book's root file to specify the
+%~ name of a book division file (e.g., |chap01|, |appa|). The order
+%~ of these commands determines the order of the divisions.
+
+\def \division #1{% {division}
+ \global\divisionname = {#1}%
+ \edef \znext {\noexpand\inclusionlist\noexpand\zset{#1}{\the\zdivreq}}%
+ \znext
+ \if \zset
+ \remark{Starting division `\the\divisionname'.}%
+ \push{#1}{\zdivset}%
+ \freshpage{\short\floats\any}%
+ \setcolumnnumber{1}%
+ \zxdivinit{#1}{\true}%
+ \zindexdivinit{#1}%
+ \zmndivinit
+ \zpndivinit
+ \zframedivinit
+ \zmrdivinit
+ \zfltdivinit
+ \include{#1.\zdivext}%
+ \endgraf
+ \freshpage{\short\floats\any}%
+ \zortahdivfinal
+ \zindexdivfinal
+ \zxdivfinal{#1}%
+ \else
+ \zxdivinit{#1}{\false}%
+ {\globaldefs = 1 \name{\=zS:#1}}% % Invoke snapshot.
+ \fi
+ \global\divisionname = \expandafter{\jobname}}
+
+% This macro is invoked at the end of the document.
+
+\def \zdivmsg {%
+ \edef \znext {\the\zdivreq}%
+ \edef \znextfirst {\expandafter\zdivmsga \znext\zmark}%
+ \if \tokeqlp{\znext}{\zallname}%
+ \remark{The entire book was processed.}%
+ \else\if \tokeqlp{\znextfirst}{\zallbutname}%
+ \relax
+ \else
+ \commalist{\zreqlist}{\the\zdivreq}%
+ \maplist{\zdivmsgb{##1}}{\zreqlist}%
+ \fi\fi}
+
+\def \zdivmsga #1#2\zmark{#1}
+
+\def \zdivmsgb #1{%
+ \member{\zexists}{#1}{\zdivset}%
+ \if \notp{\zexists}%
+ \warning{divnotexist}{The requested division `#1' does not exist}%
+ \fi}
+
+% Division Snapshots
+% -------- ---------
+
+
+\setlist \zsnaplist = {} % List of registers to be snapshot.
+
+
+\def \declaresnapitem #1{% {\name}
+ \append{#1}{\zsnaplist}}
+
+
+\def \ztakesnap {%
+ \let \zmodesave = \xrefmode
+ \let \xrefmode = \xrefsnapmode
+ \def \znext {}%
+ \maplist{\zsnapone{##1}}{\zsnaplist}%
+ \ztoksa = \expandafter{\znext}%
+ \edef \znext {\noexpand\xref{snap}{\noexpand\folio}{}%
+ {\the\ztoksa}{\the\divisionname}}%
+ \znext
+ \let \xrefmode = \zmodesave}
+
+\def \zsnapone #1{% {\register}
+ \ztoksa = \expandafter{\znext}%
+ \edef \znext {\the\ztoksa \noexpand#1\the#1}}
+
+
+% Store division snapshot information in a special name in the tag namespace.
+
+\def \xrefsnap #1#2#3#4{% {}{}{code}{division}
+ \ifnum \xrefmode=\xrefloadtagmode
+ \if \undefinedp{\=zS:#4}\withname{\gdef}{\=zS:#4}{}\fi
+ \withname\xdef{\=zS:#4}{\name{\=zS:#4}#3}%
+ \fi} \ No newline at end of file
diff --git a/macros/plain/contrib/zztex/tex/zzdoc.tex b/macros/plain/contrib/zztex/tex/zzdoc.tex
new file mode 100644
index 0000000000..072436a43a
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzdoc.tex
@@ -0,0 +1,500 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Document Facilities
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 9 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Loading Design Files
+% ------- ------ -----
+
+
+\def \bookauthor {}
+\def \booktitle {}
+\def \bookpublisher {}
+\def \bookISBN {}
+
+
+\def \loaddesign #1{% {file-list}
+ \zdtinit
+ \zloadinifile
+ \global\divisionname = \expandafter{\jobname}%
+ \setfoliostyle{\arabic}% % Initialize various options that
+ \setsentencespacing{\false}% $ might be set in the design file.
+ \setmathspaces{4mu plus .4mu minus .75mu}
+ {4mu plus .4mu minus .75mu}
+ {4mu plus .4mu minus .75mu}%
+ \protectcitecommands
+ \commalist{\zdeslist}{#1}%
+ \maplist{\zinputdes{##1}}{\zdeslist}%
+ \textsize\rm % In case \documentdesign resets
+ % \normallineskip[limit].
+ \if \DVIWindorules \setflag \DVIWindoinuse = \true \fi %%% Temporary.
+ \if \newbiblio \input zzbiblio \else \input zzbibtex \fi
+ \if \rangep{\newmath}{1}{2}\input zznewmath\relax \fi
+ \if \newrunners \input zzrunner\relax \fi
+ \if \zerop{\tabularversion}%
+ \tabularversion = \if \newtabular 2\else 1\fi\relax
+ \fi
+ \if \neqlp{\tabularversion}{3}\input zztabularv\the\tabularversion\relax \fi
+ \if \newtitleadjustment \input zzttladj\relax \fi}
+
+\def \zinputdes #1{% {design-file}
+ \checkfile{\znext}{#1.zzd}%
+ \if \znext
+ \input #1.zzd\relax
+ \else
+ \error{nodesfile}{The design file `#1.zzd' is missing}
+ \zend
+ \fi
+ \if \orp{\hmodep}{\posp{\pagetotal}}
+ \error{desjunk}
+ {The design file `#1.zzd' has some spurious junk in it}
+ \fi
+ \textsize\rm % So \documentdesign macro can use it.
+ \documentdesign}
+
+\def \announcedesign #1{% {title}
+ \remark{Loading design file `#1'._}}
+
+\def \bookdata #1#2#3#4{% {author}{title}{publisher}{ISBN}
+ \gdef \bookauthor {#1}%
+ \gdef \booktitle {#2}%
+ \gdef \bookpublisher {#3}%
+ \gdef \bookISBN {#4}}
+
+%~ Deprecated in favor of |\bookdata|.
+
+\def \bookinfo #1#2#3{% {author}{title}{publisher}
+ \gdef \bookauthor {#1}%
+ \gdef \booktitle {#2}%
+ \gdef \bookpublisher {#3}}
+
+\def \commonencoding {%
+ \input zzcomenc\relax
+ \global\setflag \zcommonencoding = \true}
+
+\def \protectcitecommands {%
+ \let \cite = \citeleterror
+ \let \citeauthr = \citeleterror
+ \let \citeyear = \citeleterror
+ \let \nocite = \citeleterror}
+
+\def \citeleterror {%
+ \error{citelet}{Cannot use \noexpand\let to define \noexpand\cite commands}}
+
+% Design Alternatives
+% ------ ------------
+
+
+% Design alternatives are deprecated.
+
+\def \designalternative #1#2{% {\name}{choice}
+ \withname\gdef{\=zA:\string#1}{#2}}
+
+\def \definedesignalternative #1#2#3{% {\name}{required?}{choice1,...}
+ \definecount{#1}{-1}%
+ \if \undefinedp{\=zA:\string#1}%
+ \if #2%
+ \error{altreq}{The design alternative `\string#1' must be specified}%
+ \else
+ \zdefalt{#1}#3,\zmark
+ \fi
+ \fi
+ \commalist{\zaltlist}{#3}%
+ \tcounta = -1\relax
+ \maplist{\zcompalt{#1}{##1}}{\zaltlist}%
+ \if \negp{#1}%
+ \error{altinv}{The design alternative `\string#1' is invalid}%
+ \fi}
+
+\def \zdefalt #1#2,#3\zmark{% {\name}choice1,...\zmark
+ \designalternative{#1}{#2}}
+
+\def \zcompalt #1#2{% {\name}{choice}
+ \increment \tcounta
+ \stringeql{\znext}{\name{\=zA:\string#1}}{#2}%
+ \if \znext \global#1 = \tcounta \fi \relax}
+
+\let \altcase = \ifcase
+
+% Document Parameters
+% -------- ----------
+
+
+% The following PDF document information options are available.
+
+\chardef \PDFinfodefault = 0
+\chardef \PDFinfofull = 1
+\chardef \PDFinfocomp = 2
+\chardef \PDFinfonone = 3
+
+
+% Integer parameters:
+
+\adjdemerits = 10000 % Adjacent incompatible lines.
+\binoppenalty = 700 % Line break after binary operator.
+%\brokenpenalty = 0 % See \even and \oddbrokenpenalty.
+\clubpenalty = 500 % Club line at bottom of page.
+\defaulthyphenchar = `\- % Default hyphen character.
+\defaultskewchar = -1 % Default skew character.
+\delimiterfactor = 941 % Math delimiter size factor.
+\displaywidowpenalty = 500 % Widow line above math display.
+\definecount{\dollarhyph}{0} % 0: no hyphenation after dollar signs;
+ % 1: hyphenate after, but nowhere else;
+ % 2: hyphenate after and other places.
+\doublehyphendemerits = 80000 % Consecutive hyphenated lines.
+\errorcontextlines = 8 % Maximum error context line pairs.
+\definecount{\evenbrokenpenalty}{3000} % Column breaks after hyphenated
+ % line, but on same spread.
+\exhyphenpenalty = 0 % Line break after explicit hyphen.
+\finalhyphendemerits = 10000 % Penultimate hyphenated line.
+\hbadness = 1000 % Above which bad hboxes are shown.
+\hyphenpenalty = 50 % Line break after discretionary hyphen.
+\interlinepenalty = 0 % Between lines of a paragraph.
+\language = 0 % Current set of hyphenation rules.
+\lefthyphenmin = 2 % Shortest fragment at beginning of
+ % hyphenated word.
+\linepenalty = 10 % Increment at each line break.
+\definecount{\lineslong}{0} % Number of lines page can go long.
+\definecount{\linesperpage}{0} % Number of lines per page.
+\definecount{\linesshort}{0} % Number of lines page can go short.
+\definecount{\maxbottomcolumnfloats}{1} % Floats at column bottom.
+\definecount{\maxbottompagefloats}{1} % Floats at page bottom.
+\definecount{\maxtopcolumnfloats}{1} % Floats at column top.
+\definecount{\maxtoppagefloats}{1} % Floats at page top.
+\definecount{\mintextpercent}{10} % Percent of page that must have text.
+\newlinechar = -1 % Newline character for \write.
+\definecount{\newmath}{0} % Revision level of math---DEPRECATED.
+\definecount{\oddbrokenpenalty}{10000} % Spread breaks after
+ % hyphenated line.
+\definecount{\PDFinfo}{\PDFinfodefault} % Include document info in final PDF file.
+\pretolerance = 400 % Badness tolerated before hyphenation.
+\relpenalty = 500 % Line break after relation operator.
+\righthyphenmin = 3 % Shortest fragment at end of hypenated word.
+\definecount{\shrinkpercent}{10} % Percentage shrink is of nominal.
+\definecount{\stretchpercent}{25} % Percentage of the maximum stretch.
+\definecount{\tabularversion}{0} % Version of tabular facility.
+\tolerance = \pretolerance % Badness tolerated after hyphenation.
+\tracinglostchars = 1 % Positive to trace lost characters.
+\definecount{\tracingpagemakeup}{0} % Positive to trace page makeup.
+\tracingstats = 1 % Positive to trace memory statistics.
+\uchyph = 1 % Positive to hyphenate Capitalized words.
+\definecount{\underscorehyph}{1} % See \dollarhyph.
+\vbadness = 2000 % Above which bad vboxes are shown.
+\widowpenalty = 10000 % Widow line at top of page.
+\definecount{\xrefcites}{0} % Cross-reference \cite's:
+ % 0: no
+ % 1: simple xref entry
+ % 2: custom xref entry
+
+% Flag Parameters:
+
+\setflag \allowcolor = \true % Allow color specials?
+\setflag \allowreftitle = \false % Allow use of \reftitle?
+\setflag \baselinetoprules = \true % Rules at page top sit on baseline?
+\setflag \DVIWindoinuse = \false % Generate DVIWindo-specific goodies?
+\setflag \DVIWindorules = \false % Display page makeup rules? [deprecated]
+\setflag \forceepsbb = \false % Force reading of EPS bounding box?
+\setflag \indexcites = \false % \cite generates indexing command?
+\setflag \newbiblio = \false % Use new biblio facility?
+\setflag \newdots = \false % Use new \xdots commands?
+\setflag \newrunners = \false % Use new runners scheme?
+\setflag \newtabular = \false % Use new tabular module? [deprecated]
+\setflag \newtitleadjustment = \false % Use new title adjustment scheme?
+\setflag \PDFhyperlinks = \false % Generate PDF hyperlinks?
+\setflag \raggedbottom = \false % Ragged-bottom pages?
+\setflag \risingbottomfloats = \false % Bottom floats rise up on page?
+\setflag \risingfootnotes = \false % Footnotes rise up on page?
+\setflag \topdeltaadjustment = \false % Use \topdelta?
+\setflag \zcommonencoding = \false % Set with \commonencoding command.
+
+% Dimension Parameters:
+
+\boxmaxdepth = \maxdimen % Maximum depth of explicit vboxes.
+\delimitershortfall = 4pt % Maximum math delimiter shortfall.
+\emergencystretch = 4pt % Emergency stretchability of each line.
+\definedimen{\evenbleedshift}{0pt} % Bleed shift for versos.
+\definedimen{\eveninnermargin}{0pt} % Inner margin (gutter) for versos.
+\definedimen{\evenlefttextmargin}{0pt} % Left text margin for versos.
+\definedimen{\evenoutermargin}{0pt} % Outer margin for versos.
+\definedimen{\evenrighttextmargin}{0pt} % Right text margin for versos.
+\definedimen{\footerheight}{0pt} % Height of footer box.
+\definedimen{\headerheight}{0pt} % Height of running head.
+\definedimen{\headmargin}{0in} % Head (top) margin.
+\hfuzz = 0.33pt % Overrun before overfull hbox messages.
+\hoffset = 0pt % Overall horizontal offset.
+\zremovePlaindef \jot
+\definedimen{\jot}{3pt} % Increment for opening up math displays.
+\lineskiplimit = 0pt % Threshold where \lineskip is used
+ % instead of \baselineskip.
+\let \linewidth = \hsize % Alternate name for \hsize.
+\maxdepth = 4pt % Maximum depth of boxes on main pages.
+\zremovePlaindef \normallineskiplimit
+\definedimen{\normallineskiplimit}{0pt} % Normal line skip limit.
+\nulldelimiterspace = 1.2pt % Width of a null delimiter.
+\definedimen{\oddbleedshift}{0pt} % Bleed shift for rectos.
+\definedimen{\oddinnermargin}{0pt} % Inner margin (gutter) for rectos.
+\definedimen{\oddlefttextmargin}{0pt} % Left text margin for rectos.
+\definedimen{\oddoutermargin}{0pt} % Outer margin for rectos.
+\definedimen{\oddrighttextmargin}{0pt} % Right text margin for rectos.
+\overfullrule = 6pt % Width of rule appended to overfull boxes.
+\parindent = 0pt % Width of paragraph indent.
+\definedimen{\parrag}{0pt} % Raggedness of paragraph lines.
+\scriptspace = .25pt % Extra space after a sub/superscript.
+\splitmaxdepth = \maxdimen % Maximum depth of boxes on split pages.
+\definedimen{\standardbleed}{.125in} % Standard bleed required by press.
+\definedimen{\standardindent}{0pt} % Standard indentation amount.
+\definedimen{\textareaheight}{\mindimen}% Height of text area.
+\definedimen{\textmeasure}{0pc} % Width of text area.
+\let \textareawidth = \textmeasure
+\definedimen{\topdelta}{0pt} % \topskip - height(first line).
+\definedimen{\trimheight}{0in} % Trimmed paper height.
+\definedimen{\trimwidth}{0in} % Trimmed paper width.
+\definedimen{\trimplusbleedheight}{0in} % Trim plus bleed top and bottom.
+\definedimen{\trimplusbleedwidth}{0in} % Trim plus bleed both sides.
+\definedimen{\typeareaheight}{\mindimen}% Height of type area.
+\definedimen{\typeareawidth}{0pt} % Width of type area.
+\vfuzz = 0.5pt % Overrun before overfull vbox messages.
+\voffset = 0pt % Overall vertical offset.
+
+% Skip (glue) Parameters:
+
+\leftskip = 0pt % At left end of paragraph lines.
+\lineskip = 0pt % When \baselineskip isn't possible.
+\zremovePlaindef \normalbaselineskip
+\defineskip{\normalbaselineskip}{0pt} % Normal baseline distance.
+\zremovePlaindef \normallineskip
+\defineskip{\normallineskip}{0pt} % Normal line skip limit.
+\parfillskip = 0pt plus 1fil % Additional \rightskip at paragraph end.
+\parskip = 0pt % Above paragraphs.
+\rightskip = 0pt % At right end of lines.
+\spaceskip = 0pt % Between words (if nonzero).
+\splittopskip = 10pt % At top of split pages.
+\defineskip{\standardskip}{0pt} % Standard skip above/below elements.
+\topskip = \mindimen % At top of main pages.
+\xspaceskip = 0pt % Between sentences (if nonzero).
+
+% Muskip (mu glue) Parameters:
+
+\definemuskip{\fracbarhang}{0mu} % Fraction bar overhang.
+\thinmuskip = 0mu % Math space after punctuation.
+\medmuskip = 0mu % Math space around binary operators.
+\thickmuskip = 0mu % Math space around relational operators.
+
+% Token list parameters:
+
+\definetoks{\annotationfont} % Font for annotations (e.g., proof identification).
+\annotationfont = {cmssi10 at 7pt}
+\definetoks{\baselinemultiplier}% Multiplier for baselines.
+\baselinemultiplier = {1}
+\definetoks{\decimalpoint} % Decimal point character.
+\decimalpoint = {.}
+\definetoks{\PDFbuttoncolor} % Color of hyperlinked text.
+\definetoks{\matrixspread} % Baseline multiplier for matrices.
+\matrixspread = {1.0}
+
+% The following parameters are fixed and hidden from the user.
+
+\mathsurround = 0pt % Space around a math formula in text.
+
+% Parameter Calculation
+% --------- -----------
+
+
+\def \calculatetextareaheight #1{% {lines}
+ \relax
+ \if \dimnegp{\topskip}%
+ \error{misstopskip}{The value of \string\topskip must be set}%
+ \fi
+ {\global\linesperpage = #1\relax
+ \tcounta = #1\relax
+ \decrement \tcounta
+ \textareaheight = \the\tcounta\baselineskip
+ \global\advance \textareaheight by \topskip
+ \measurecapheight{\topdelta}%
+ \measureascenderheight{\tdimena}%
+ \if \dimgtrp{\tdimena}{\topdelta}\topdelta = \tdimena \fi
+ \advance \topdelta by -\topskip
+ \global\negate \topdelta}}
+
+\def \calculatetypeareaheight #1#2{% {head-height}{head-b/b}
+ \relax
+ \if \dimnegp{\textareaheight}%
+ \error{misstah}{The value of \string\textareaheight must be set}%
+ \fi
+ {\typeareaheight = \textareaheight
+ \advance \typeareaheight by -\topskip
+ \advance \typeareaheight by #1\relax
+ \advance \typeareaheight by #2\relax
+ \global\advance \typeareaheight by \footerheight
+ \headerheight = #1\relax
+ \advance \headerheight by #2\relax
+ \global\advance \headerheight by -\topskip}}
+
+\def \calculateoffsets #1#2{% {sheet-width}{sheet-height}
+ \relax
+ \if \andp{\dimposp{\trimwidth}}{\dimposp{\trimheight}}%
+ \hoffset = #1\relax
+ \advance \hoffset by -\trimwidth
+ \divide \hoffset by 2
+ \advance \hoffset by -1in
+ \voffset = #2\relax
+ \advance \voffset by -\trimheight
+ \divide \voffset by 2
+ \advance \voffset by -1in\relax
+ \else
+ \error{misstrim}{The values of \string\trimwidth and
+ \string\trimheight must be set}%
+ \fi}
+
+\def \calculatepdfoffsets #1#2#3{% {virtual-width}{virtual-height}{bleeds?}
+ \relax
+ \if \andp{\dimposp{\trimwidth}}{\dimposp{\trimheight}}%
+ \hoffset = -1in
+ \if #3\advance \hoffset by \standardbleed \fi
+ \calculate \voffset = {#2,-,\trimheight,-,1in}%
+ \if #3\advance \voffset by -\standardbleed \fi
+ \else
+ \error{misstrim}{The values of \string\trimwidth and
+ \string\trimheight must be set}%
+ \fi}
+
+\def \setskip #1=#2#3#4{% \parameter = {nominal}{max-stretch}{[shrink]}
+ \tdimena = #2\relax
+ \calculate \tdimenb = {#3,P,\stretchpercent}%
+ \if \emptyargp{#4}%
+ \calculate \tdimenc = {\tdimena,P,\shrinkpercent}%
+ \else
+ \tdimenc = #4\relax
+ \fi
+ #1 = \the\tdimena plus \the\tdimenb minus \the\tdimenc\relax}
+
+\def \fromtrim #1{% \setskip or \register
+ \if \tokeqlp{#1}{\setskip}%
+ \let \znext = \zfromtrima
+ \else
+ \def \zfromtrimreg {#1}%
+ \let \znext = \zfromtrimb
+ \fi
+ \znext}
+
+\def \zfromtrima #1=#2#3#4{%
+ \setskip #1={#2}{#3}{#4}%
+ \advance #1 by -\headmargin}
+
+\def \zfromtrimb {%
+ \afterassignment\zfromtrimc \zfromtrimreg}
+
+\def \zfromtrimc {%
+ \advance \zfromtrimreg by -\headmargin}
+
+% Document Block
+% -------- -----
+
+
+\def \document {%
+ % There is no point to embedding the entire document in a group.
+ % \documentdesign was already invoked by \loaddesign.
+ \zpushblock{document}%
+ \xdef \znext {%
+ \noexpand\definefont \noexpand\zannofont{\the\annotationfont}}
+ \znext
+ \zfontsummary{\false}%
+ \zopentfmlist
+ \zwritePDFinfo
+ \zpageinit
+ \zpushvcontext
+ \setparrag{\parrag}%
+ \zxrefinit
+ \zbiblioinit
+ \zindexinit
+ \zfloatinit
+ \setpagecolumns{}{1}{0pt}%
+ \if \definedp{\documentprolog}\documentprolog \fi}
+
+\def \enddocument {%
+ \endgraf
+ \if \definedp{\documentepilog}\documentepilog \fi
+ \closeanychapter
+ \closeanysection
+ \zpopblock{document}%
+ \freshpage{\short\floats\any}%
+ \zindexfinal
+ \zxreffinal
+%%% \zbibfinal
+ \zmissingartmsg
+ \ztagsummary
+ \zpopvcontext
+ \zlayoutsummary
+ \zfontsummary{\true}%
+ \zwritetfmlist
+ \if \posp{\tracingstats}\zregstats \fi
+ \zfeaturewarns
+ \ztodomsg
+ \zdivmsg
+ \zproofidfile
+ \zend}
+
+\def \zfeaturewarns {%
+ \messagenl{_}%
+ \if \zoverlayset
+ \remark{Overlays are present on each page.}%
+ \fi
+ \zproofident}
+
+\def \zproofident {%
+ \zproofidentline
+ \if \emptytoksp{\zproofid}%
+ \messagenl{| No proof identification.}%
+ \else
+ \messagenl{| \the\zproofid\space\space
+ \number\year/\number\month/\number\day\space
+ \formattime\space\space\space
+ \inicompositor}%
+ \fi
+ \zproofidentline}
+
+\def \zproofidentline {%
+ \messagenl{+-----------------------------------------------------------------------------_}}
+
+% Write PDF Document Information
+% ----- --- -------- -----------
+
+
+\def \zwritePDFinfo {%
+ \ifcase \PDFinfo
+ \relax
+ \or
+ \special{PDF: Title \booktitle}%
+ \special{PDF: Author \bookauthor}%
+ \special{PDF: Subject}%
+ \special{PDF: Keywords Publisher: \bookpublisher,
+ Compositor: \inicompositor}%
+ \or
+ \special{PDF: Title}%
+ \special{PDF: Author}%
+ \special{PDF: Subject}%
+ \special{PDF: Keywords Compositor: \inicompositor}%
+ \or
+ \special{PDF: Title}%
+ \special{PDF: Author}%
+ \special{PDF: Subject}%
+ \special{PDF: Keywords}%
+ \fi}
+
+% Disable \end
+% ------- ----
+
+
+\let \zend = \end
+
+\def \end {%
+ \error{noend}{Do not use the TeX \string\end\space command}}
diff --git a/macros/plain/contrib/zztex/tex/zzerror.tex b/macros/plain/contrib/zztex/tex/zzerror.tex
new file mode 100644
index 0000000000..693451b2c3
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzerror.tex
@@ -0,0 +1,123 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Error Handling
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 13 August 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Remarks & Errors
+% ------- - ------
+
+
+\def \remark #1{% {text}
+ \messagenl{_ZzTeX: #1_}}
+
+\def \warning #1#2{% {help-id}{text}
+ \zsethelp{#1}%
+ \zerrmsg{warning}{#2}}
+
+\def \error #1#2{% {help-id}{text}
+ \zsethelp{#1}%
+ \zerrmsg{error}{#2}%
+ \remark{Continuing from an error may cause unpredictable results.}}
+
+\def \zzerror #1{% {text}
+ \zerrmsg{internal error}{#1}%
+ \remark{Continuing from an internal error will cause erroneous results.}}
+
+\def \zerrmsg #1#2{% {prefix}{text}
+ {\newlinechar = `\_%
+ \errmessage{ZzTeX #1: #2}}}
+
+%%%\def \zerrcontext #1{%
+%%% \listtop{\znext}{\zblockstack}%
+%%% \writelog{ZzTeX context: #1 \znext\space \the\typesizename
+%%% \the\typestyle \the\typeencoding.}}
+%%%
+%%%\def \context {%
+%%% \zerrcontext{???}%
+%%% \zend}
+
+% To-Do Facility
+% ----- --------
+
+
+\definecount{\ztodocount}{0}
+
+
+%~ The |\todo| command accepts a note that is stored in the composite
+%~ cross-reference file as a reminder of something that needs to
+%~ be done later. ZzExplore can display a list of the outstanding
+%~ to-dos.
+
+\long\def \todo #1{% {note}
+ \zwritetodo{#1}%
+ \ztodo #1\zmark
+ \global\increment \ztodocount}
+
+\long\def \ztodo #1#2\zmark{% {char1}{rest of message}
+ \if \codeeqlp{#1}{!}%
+ {\errorcontextlines = 0
+ \def \znext {#2}%
+ \zerrmsg{to-do}{\expandafter\zdefof \meaning\znext\zmark\space
+ [\the\divisionname]}}%
+ \else\if \codeeqlp{#1}{.}%
+ \def \znext {#2}%
+ \writelog{ZzTeX to-do: \expandafter\zdefof \meaning\znext\zmark\space
+ [\the\divisionname]}%
+ \else\if \codeeqlp{#1}{?}%
+ \def \znext {#2}%
+ \messagenl{_ZzTeX to-do: To come: \expandafter\zdefof \meaning\znext\zmark\space
+ [\the\divisionname]_}%
+ \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 0}\fi
+ ???%
+ \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
+ \else
+ \def \znext {#1#2}%
+ \messagenl{_ZzTeX to-do: \expandafter\zdefof \meaning\znext\zmark\space
+ [\the\divisionname]_}%
+ \fi\fi\fi}
+
+% Write a todo entry into the cross-reference file.
+
+\long\def \zwritetodo #1{% {message}
+ \zbeginhidewrite
+ \def \znext {#1}%
+ \edef \znext {\noexpand\xref{todo}{\noexpand\folio}{}
+ {\expandafter\zdefof \meaning\znext\zmark}
+ {\the\divisionname}}%
+ \znext
+ \zendhidewrite}
+
+% There is nothing to do with each entry in the cross-reference file
+% when it is loaded.
+
+\long\def \xreftodo #1#2#3#4{}
+
+% This macro is invoked at the end of the run.
+
+\def \ztodomsg {%
+ \if \posp{\ztodocount}%
+ \remark{Number of to-do reminders encountered: \the\ztodocount}%
+ \fi}
+
+
+% Help Text
+% ---- ----
+
+
+\def \zsethelp #1{%
+ \if \definedp{\=zH:#1}%
+ \global\errhelp = \expandafterthrice{\name{\=zH:#1}}%
+ \else
+ \global\errhelp = {No additional help is available.}%
+ \fi}
+
+
diff --git a/macros/plain/contrib/zztex/tex/zzfloat.tex b/macros/plain/contrib/zztex/tex/zzfloat.tex
new file mode 100644
index 0000000000..b6e3e08246
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzfloat.tex
@@ -0,0 +1,1164 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Float Facilities
+%
+% Synopsis: This module contains the float and caption blocks, as well as
+% all the code required to support the scheduling of floats.
+%
+% Notes: The broadside capability was implemented by Richard A. Wells and
+% integrated into ZzTeX on 9/7/94.
+%
+% Author: Richard A. Wells & Paul C. Anagnostopoulos
+% Created: 7 March 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Data Structures
+% ---- ----------
+
+
+\definecount{\zfltcount}{0}
+\def \zfloatfreeq {}
+\def \zfloatpendq {}
+
+
+\def \zdeffloat #1#2{% {\float}{\float-box}
+ \definebox{#2}%
+ \zfreefloat{#1}{#2}%
+ \global\increment \zfltcount}
+
+\def \zgetfloat #1{% {\float}
+ \if \emptydefp{\zfloatfreeq}%
+ \error{toomanyflt}
+ {More than `\the\zfltcount' floats remain for page makeup}%
+ \else
+ \pop{#1}{\zfloatfreeq}%
+ \fi}
+
+\def \zfreefloat #1#2{% {\float}{\float-box}
+ \gdef #1{\def \zcurfloatbox {#2}}%
+ \append{#1}{\zfloatfreeq}}
+
+\zdeffloat{\zflta}{\zfltboxa}
+\zdeffloat{\zfltb}{\zfltboxb}
+\zdeffloat{\zfltc}{\zfltboxc}
+\zdeffloat{\zfltd}{\zfltboxd}
+\zdeffloat{\zflte}{\zfltboxe}
+\zdeffloat{\zfltf}{\zfltboxf}
+\zdeffloat{\zfltg}{\zfltboxg}
+\zdeffloat{\zflth}{\zfltboxh}
+\zdeffloat{\zflti}{\zfltboxi}
+\zdeffloat{\zfltj}{\zfltboxj}
+\zdeffloat{\zfltk}{\zfltboxk}
+\zdeffloat{\zfltl}{\zfltboxl}
+\zdeffloat{\zfltm}{\zfltboxm}
+\zdeffloat{\zfltn}{\zfltboxn}
+\zdeffloat{\zflto}{\zfltboxo}
+\zdeffloat{\zfltp}{\zfltboxp}
+\zdeffloat{\zfltq}{\zfltboxq}
+\zdeffloat{\zfltr}{\zfltboxr}
+\zdeffloat{\zflts}{\zfltboxs}
+\zdeffloat{\zfltt}{\zfltboxt}
+\zdeffloat{\zfltu}{\zfltboxu}
+\zdeffloat{\zfltv}{\zfltboxv}
+\zdeffloat{\zfltw}{\zfltboxw}
+\zdeffloat{\zfltx}{\zfltboxx}
+\zdeffloat{\zflty}{\zfltboxy}
+\zdeffloat{\zfltz}{\zfltboxz}
+
+% There is an insert class for each of the two places where floats
+% can go.
+
+\defineinsert{\ztopcolinsert} % Floats at top of column.
+\count\ztopcolinsert = 1000
+\dimen\ztopcolinsert = \maxdimen
+\skip\ztopcolinsert = 0pt
+\defineinsert{\zbotcolinsert} % Floats at bottom of column.
+\count\zbotcolinsert = 1000
+\dimen\zbotcolinsert = \maxdimen
+\skip\zbotcolinsert = 0pt
+
+
+% We need a dimension register to capture box depths.
+
+\definedimen{\zfloatdp}{0pt}
+
+% Float Types
+% ----- -----
+
+
+\setlist \zfloattypelist = {}
+
+
+\def \definefloattype #1#2#3{% {type}{toc-level}{association}
+ \if \emptyargp{#3}%
+ \withname\definecount{\float#1number}{0}%
+ \withname\declaresnapitem{\float#1number}%
+ \else
+ \edef \znext {%
+ \global\withname\let{\float#1number}=\name{\float#3number}}%
+ \znext
+ \fi
+ \withname\gdef{\zflt#1lvl}{#2}%
+ \append{#1}{\zfloattypelist}}
+
+
+\def \resetfloatnumbers {%
+ \maplist{\global\name{\float##1number}=0\relax}{\zfloattypelist}}
+
+
+% Predefined float types (don't forget an index locator for each one).
+
+\definefloattype{algorithm}{101}{}
+\definefloattype{figure}{102}{}
+\definefloattype{table}{103}{}
+\definefloattype{listing}{104}{}
+\definefloattype{sidebar}{105}{}
+
+% Float Block
+% ----- -----
+
+
+\defineblock{\float}{\endfloat}{\false}{}
+
+%~block float Type
+% \aboveskip = glue % Space b/b above float.
+% \def \beginformat {...} % Beginning of float formatter.
+% \belowskip = glue % Space b/b below float.
+% \def \comptextformat {...} % Composite number text formatter.
+% \continue = integer % Continued or continuation.
+% \def \endformat {...} % End of float formatter.
+% \leftindent = dimen % Horizontal fudge for all floats.
+% \pageplacement = {...} % Overriding page placement.
+% \position = {...} % Position (see below).
+% \runners = {style} % Runners for a page of floats.
+% \topfloatfudge = dimen % Vertical fudge for topmost float.
+% \width = dimen % Explicit width for float.
+%~end
+
+\definetoks{\pageplacement}
+\definedimen{\topfloatfudge}{0pt}
+
+% These derived parameters are needed here and by \caption. They may
+% also be useful to the user.
+
+\definecount{\floatpage}{0}
+\definedimen{\floatshift}{0pt}
+\definedimen{\floatwidth}{0pt}
+
+\definecount{\zdivfltcounter}{0} % Count floats in each division.
+\definebox{\zfltbroadbox}
+
+
+% Floats are packaged up in a vbox using \vtop, so that the float box
+% has the same height as the first thing inside. This improves the
+% chances that a float at the top of a page will be positioned correctly.
+
+\def \float #1{% {type}
+ \if \undefinedp{\float#1number}%
+ \error{undefflt}{Float type `#1' has not been defined}%
+ \fi
+ \endgraf
+ \blockcantbein{\float}{\float}%
+ \blockcantbein{\float}{\multicolumn}%
+ \beginblockscope{float}%
+ \global\increment \floatdepth
+ \global\increment \zdivfltcounter
+ \whichpage{\floatpage}{zF:\the\divisionname-\the\zdivfltcounter}%
+ \def \beginformat {}% %~default soft
+ \continue = 0 %~default with
+ \def \comptextformat {}% %~default soft
+ \setflag \continuation = \false % Deprecated
+ \def \endformat {}% %~default soft
+ \leftindent = 0pt %~default soft
+ \pageplacement = {}% %~default with
+ \runners = {normal}% %~default soft
+ \zoldrunners{\normalheader\normalfooter}%
+ \width = \naturalwidth %~default soft
+ \processdesign{\float}{#1}%
+ \zsetcontinue % Handle old \continuation.
+ \if \notp{\continuationp}\global\withname\increment{\float#1number}\fi
+ \global\withname\floatnumber{\float#1number}%
+ \setcomptext{\floatcomptext}%
+ \def \zcurflttype {#1}%
+ \edef \zcurfltlvl {\name{\zflt\zcurflttype lvl}}%
+ \parindent = 0pt
+ \parrag = 0pt
+ \parskip = 0pt
+ \zparsefltpos{\the\position}%
+ \if \notp{\emptytoksp{\pageplacement}}%
+ \zparsefltpagepos{\the\pageplacement}%
+ \fi
+ \if \zfltposhere
+ \penalty \breakallowed % Synchronize main list.
+ \zparsefltpos{\the\position}% % Recalculate global stuff.
+ \if \notp{\emptytoksp{\pageplacement}}
+ \zparsefltpagepos{\the\pageplacement}%
+ \fi
+ \fi
+ \zcalcfltparams
+ \zgetfloat{\zcurfloat}%
+ \zcurfloat
+ \global\setbox \zcurfloatbox = \vtop \bgroup
+ \zpushvcontext
+ \setindentation{0pt}{0pt}%
+ \settextwidth{\floatwidth}%
+ \settaginfo{\the\floatcomptext}{}% % Set tag info without title.
+ \setsubtagnumber{0}%
+ \beginformat}
+
+\def \endfloat {%
+ \endgraf
+ \endformat
+ \global\zfloatdp = \prevdepth
+ \tagpageonly{\uniquetag{zF}{\the\zdivfltcounter}}%
+ \zpopvcontext
+ \egroup % \vtop
+ \expandafter\xdef \zcurfloat {%
+ \def \noexpand\zcurfloatid {\zcurflttype\space \the\floatnumber}%
+ \def \noexpand\zcurfloatbox {\zcurfloatbox}%
+ \zfloatdp = \the\zfloatdp
+ \aboveskip = \the\aboveskip
+ \belowskip = \the\belowskip
+ \leftindent = \the\leftindent
+ \position = {\the\position}%
+ \pageplacement = {\the\pageplacement}%
+ \runners = {\the\runners}%
+ \floatshift = \the\floatshift
+ \topfloatfudge = \the\topfloatfudge}%
+ \expandafter\append \zcurfloat{\zfloatpendq}%
+ \zschedulefloats{\znext}{\false}{\false}%
+ \if \gtrp{\znext}{99}%
+ \zfltpage{\zpenfloatpage}%
+ \fi
+ \global\decrement \floatdepth
+ \endblockscope{float}}
+
+%~ This |\float| modifier forces an alone float.
+
+\def \alonefloat {% %^modifier
+ \with{\pageplacement={\alone}}}
+
+%~ This |\float| modifier forces a bottom float.
+
+\def \bottomfloat {% %^modifier
+ \with{\pageplacement={\bottom}}}
+
+%~ This |\float| modifier forces a broadside float.
+
+\def \broadsidefloat {% %^modifier
+ \with{\pageplacement={\broadside}}}
+
+%~ This |\float| modifier forces a here float.
+
+\def \herefloat {% %^modifier
+ \with{\pageplacement={\here}}}
+
+%~ This |\float| modifier forces a separate float.
+
+\def \separatefloat {% %^modifier
+ \with{\pageplacement={\separate}}}
+
+%~ This |\float| modifier allows the float to occupy the
+%~ running head area. Any running head is deleted.
+
+\def \userharea {% %^modifier
+ \with{\runners={blind}%
+ \advance \topfloatfudge by -\headerheight}}
+
+\def \adjusttopfloatfudge #1{%
+ \global\advance \topfloatfudge by #1\relax}
+
+\def \piggybackfloat {%
+ \edef \znext {\noexpand\global\noexpand\increment
+ \name{\float\zcurflttype number}}%
+ \znext
+ \edef \znext {\floatnumber = \name{\float\zcurflttype number}}%
+ \znext}
+
+% Controlling Floats
+% ----------- ------
+
+
+% This macro is invoked at the beginning of each division.
+
+\def \zfltdivinit {%
+ \global\zdivfltcounter = 0\relax}
+
+
+\setflag \zschedflts = \true
+
+\def \deferfloats #1{% {boolean}
+ \global\setflag \zschedflts = {\notp{#1}}}
+
+
+% Scheduling Tools
+% ---------- -----
+
+
+% These counters keep track of the number of floats scheduled for the
+% current page.
+
+\definecount{\ztopcolfloats}{0} % Number of top column floats.
+\definecount{\zbotcolfloats}{0} % Number of bottom column floats.
+\definecount{\zfloatsinserted}{0} % Total number of floats.
+\definetoks{\zfltrunners} % Runners for first float on page.
+
+% This macro initializes for handling floats on a new page.
+
+\def \zfloatinit {%
+ \global\setflag \zschedflts = \true
+ \global\ztopcolfloats = 0
+ \global\zbotcolfloats = 0
+ \zfltrunners = {}}
+
+% These macros simply hide some of the details to make the \zsched*
+% macros easier to read.
+
+\def \ztallytopfloat {%
+ \if \orp{\notp{\zfltposmargonly}}{\posp{\ztopcolfloats}}%
+ \global\increment \ztopcolfloats
+ \fi}
+
+\def \zforcenewpage{%
+ \global\zfloatsinserted = 101\relax}
+
+\let \zquitscheding = \exitmaplist
+
+\def \zsetfloattall{%
+ \zmakefloatalone
+ \setflag \zfloattall = \true
+ \tracepagemakeup{Float is too tall for column; positioning `alone'.}}
+
+\def \zmakefloatalone{%
+ \setflag \zfltposalone = \true
+ \setflag \zfltposbottom = \false
+ \setflag \zfltposhereonly = \false
+ \setflag \zfltposhere = \false
+ \setflag \zfltposseparate = \false
+ \setflag \zfltpostop = \false}
+
+\def \zmakefloattop{%
+ \setflag \zfltposalone = \false
+ \setflag \zfltposbottom = \false
+ \setflag \zfltposhereonly = \false
+ \setflag \zfltposhere = \false
+ \setflag \zfltposseparate = \false
+ \setflag \zfltpostop = \true}
+
+% Float Scheduler
+% ----- ---------
+
+
+% return-count is a counter passed in by the caller that we should
+% set at the end of \zschedulefloats to indicate how
+% many floats were emitted during this call. A value
+% greater than 99 indicates that a new page should be
+% FORCED (e.g. for alone floats) by the output routine.
+% during-output? is a flag indicating that the caller is
+% part of the output routine.
+% flushing? A flag indicating whether we are flushing floats.
+
+\def \zschedulefloats #1#2#3{% {return-count}{during-output?}{flushing?}
+ \tracepagemakeup{[Scheduling \if #2floats during output%
+ \else float when encountered\fi.}%
+ \tracepagemakeup{Page total: \the\pagetotal; goal: \the\pagegoal.}%
+ % Reset our counter
+ \global\zfloatsinserted = 0
+ \if \zschedflts
+ \if \emptydefp{\zfloatpendq}%
+ \tracepagemakeup{There are no floats to be scheduled.}%
+ \else
+ \endgraf
+ \zinitfloatfit{#2}%
+ {\setflag \zschedfirstseparate = \true
+ \setflag \zschedseparateloop = \false
+ \maplist{\zschedone{#2}{#3}{##1}}{\zfloatpendq}}%
+ \fi
+ \else
+ \tracepagemakeup{Floats are deferred now.}%
+ \fi
+ \tracepagemakeup{Float scheduling complete;
+ floats inserted: \the\zfloatsinserted.]}%
+ \xdef #1{\the\zfloatsinserted}}
+
+
+\def \zschedone #1#2#3{% {during-output?}{flushing?}{\float}
+ #3%
+ \zparsefltpos{\the\position}%
+ \if \notp{\emptytoksp{\pageplacement}}
+ \zparsefltpagepos{\the\pageplacement}%
+ \fi
+ \if #2% % If flushing floats, force float
+ \setflag \zfltposbottom = \false % to a `separate'.
+ \setflag \zfltpostop = \false
+ \setflag \zfltposseparate = \true
+ \fi
+ \tracepagemakeup{Trying to schedule \zcurfloatid;
+ size: \the\ht\zcurfloatbox+\the\dp\zcurfloatbox.}%
+ \if \orp{\andp{\zfltposeven}{\oddpagep}}%
+ {\andp{\zfltposodd}{\evenpagep}}%
+ \tracepagemakeup{Float is deferred until appropriate even/odd page.}%
+ \zquitscheding
+ \else
+ \setflag \zfloatunsched = \true
+ \setflag \zfloattall = \false
+ % The following macros attempt, in order of priority, to schedule
+ % the current float. Each macro may set up state that causes
+ % the subsequent macro(s) to do nothing.
+ \zschedhereonly{#1}%
+ \zschedhere{#1}%
+ \zschedalone{#1}%
+ \zschedbroadside{#1}%
+ \zschedseparate{#1}%
+ \zschedtop{#1}%
+ \zschedbottom{#1}%
+ \if \zfloattall % Schedule as `alone'.
+ \zschedalone{#1}%
+ \fi
+ \if \zfloatunsched
+ \tracepagemakeup{Float could not be scheduled.}%
+ % This exits a \maplist call to \zschedone.
+ \zquitscheding
+ \else
+ % Remove the current float from the queue...
+ \pop{\zcurfloat}{\zfloatpendq}%
+ % ...and free up the associated data structures.
+ \expandaftertwice\zfreefloat \expandafter\zcurfloat\zcurfloatbox
+ \fi
+ \fi}
+
+% Fitting a Float
+% ------- - -----
+
+
+% These registers are used in float fitting. They contain,
+% respectively, the amount of vertical space used up by floats for
+% the current page and the maximum space available for floats.
+
+\definedimen{\zfloatpageused}{0pt}
+\definedimen{\zfloatmaxavail}{0pt}
+
+
+% Macro to initialize the above parameters (called in \zschedulefloats).
+
+\def\zinitfloatfit #1{% {during-output?}
+ \if #1
+ \zfloatpageused = 0pt
+ % Effectively: zfloatmaxavail = (100-mintextpercent) * vsize
+ \calculate \tcounta = {100,-,\mintextpercent}%
+ \calculate \zfloatmaxavail = {\vsize,P,\tcounta}%
+ \else
+ % Effectively: zfloatpageused = max(pagetotal, vsize * mintextpercent)
+ \calculate \zfloatpageused = {\vsize,P,\mintextpercent,X,\pagetotal}%
+ \zfloatmaxavail = \pagegoal
+ \fi}
+
+
+% The spacing above and below a float is fairly complicated.
+% In this table, h is the height of the float, d is the depth.
+%
+% Position Sequence Above Below
+%
+% \alone only \topskip - h + none
+% \topfloatfudge
+% \bottom first \aboveskip - h none
+% rest min(\aboveskip, none
+% \belowskip) - h
+%
+% \separate first \topskip - h + none
+% \topfloatfudge
+% rest min(\aboveskip, none
+% \belowskip) - h
+% \top first \topskip - h + \belowskip - \topskip - d
+% \topfloatfudge
+% rest min(\aboveskip, \belowskip - \topskip - d
+% \belowskip) - h
+
+
+% Here and broadside floats are handled differently, below in \zfitfloathere
+% and \zfitfloatbroadside
+
+\def \zfitfloat #1#2#3#4#5{% {result-flag}{top?}{aboveskip-first}
+ % {aboveskip-rest}{belowskip}
+ {\if \zfltposmargonly
+ \tcounta = 0 % Margin float should act as first one.
+ \else
+ \tcounta = \if #2\ztopcolfloats \else \zbotcolfloats \fi
+ \fi
+ \zskipa = \if \zerop{\tcounta}#3\else #4\fi
+ \advance \zskipa by -\ht\zcurfloatbox
+ \if \andp{#2}{\zerop{\tcounta}}\advance \zskipa by \topfloatfudge \fi
+ \tdimena = \zskipa
+ \advance \tdimena by \ht\zcurfloatbox
+ \advance \tdimena by \dp\zcurfloatbox
+ \tdimenb = #5\advance \tdimena by \tdimenb
+ \tdimenc = \zfloatpageused
+ \if \notp{\zfltposmargonly}\advance \tdimenc by \tdimena \fi
+ \tracepagemakeup{Requires: \the\tdimena;
+ available: \the\zfloatmaxavail;
+ used: \the\zfloatpageused.}%
+ \if \dimlssp{\tdimenc}{\zfloatmaxavail}%
+ \if \andp{\notp{#2}}{\zfltposmargonly}%
+ \insert \zbotcolinsert {%
+ \vbox to 0pt{%
+ \vss
+ \moveright \floatshift \box\zcurfloatbox
+ \vskip -\dp\zcurfloatbox}}%
+ \else
+ \insert \if #2\ztopcolinsert \else \zbotcolinsert \fi {%
+ \vskip \zskipa
+ \moveright \floatshift \box\zcurfloatbox
+ \nobreak
+ \if \zfltposmargonly
+ \vskip \tdimenb
+ \nobreak
+ \vskip -\tdimena
+ \else
+ \vskip #5\relax
+ \fi}%
+ \fi
+ \if \emptytoksp{\zfltrunners}%
+ \global\zfltrunners = \expandafter{\the\runners}%
+ \fi
+ \global\increment \zfloatsinserted
+ \global\zfloatpageused = \tdimenc
+ \global\setflag #1= \true
+ \else
+ \global\setflag #1= \false
+ \fi}}
+
+\def \zfitfloathere #1#2#3{% {result-flag}{aboveskip}{belowskip}
+ {\tdimena = #2\relax
+ \advance \tdimena by \dp\zcurfloatbox
+ \advance \tdimena by #3\relax
+ \tracepagemakeup{Requires: \the\tdimena;
+ page total: \the\pagetotal;
+ page goal: \the\pagegoal.}%
+ \advance \tdimena by \pagetotal
+ \if \dimlssp{\tdimena}{\pagegoal}%
+ \bbskipabove{\breaknever}{#2}%
+ \fakepar
+ \moveright \floatshift \box\zcurfloatbox
+ \prevdepth = \zfloatdp
+ \bbskipbelow{\breakallowed}{#3}%
+ \global\increment \zfloatsinserted
+ \global\setflag #1= \true
+ \else
+ \global\setflag #1= \false
+ \fi}}
+
+\def \zfitfloatbroadside {%
+ {% We know there are no other floats on the the topcolumn when
+ % this is called (by \zschedbroadside only) and we don't have to
+ % worry about fixing up the vertical position at the end of the
+ % page.
+ %
+ % Compute the space required
+ % Start with the topskip
+ \tdimena = \topfloatfudge
+ % Add the *width* (since the box will be rotated)
+ \advance \tdimena by \wd\zcurfloatbox
+ \tracepagemakeup{Requires: \the\tdimena;
+ broadside floats always fit.}%
+ \insert \ztopcolinsert {%
+ % vskip the top float fudge
+ \vskip \topfloatfudge
+ % save the width for unskipping later
+ \tdimenb = \wd\zcurfloatbox
+ % vskip the *width* of the box to do the position translation
+ % that we can't do with PostScript
+ \vskip \tdimenb
+ % Put our hbox in a vbox, so we can "lower" it rather than move
+ % it right (since it will be rotated)
+ \global\setbox\zfltbroadbox = \vbox{%
+ \vskip\floatshift % replaces \moveright in other floats
+ \box\zcurfloatbox}%
+ \rotatebox{\zfltbroadbox}{90}%
+ % Undo vertical skip so that insert doesn't cause additional page
+ \vskip -\tdimenb}%
+ \if \emptytoksp{\zfltrunners}%
+ \global\zfltrunners = \expandafter{\the\runners}%
+ \fi
+ \global\increment \zfloatsinserted
+ \global\zfloatpageused = \tdimena}}
+
+% Individual Schedulers
+% ---------- ----------
+
+
+% This is a temporary register used in calls to \zfitfloat where the
+% fit needs to take into account more than one skip value (such as
+% both the \aboveskip and \belowskip). In that case this dimen is
+% used as a temp to hold the sum of the skip values.
+
+\defineskip{\zfloatabove}{0pt}
+\defineskip{\zfloatbelow}{0pt}
+\definedimen{\zfloatextraskip}{0pt}
+
+
+% This scheduler is called for floats with position `here' and no others.
+
+\def\zschedhereonly #1{% {during-output?}
+ \if \andp{\zfloatunsched}{\zfltposhereonly}%
+ \tracepagemakeup{Float is to be positioned `here' only.}%
+ \if \zschedseparateloop
+ \tracepagemakeup{Making up a page of separates; quit.}%
+ \zforcenewpage
+ \zquitscheding
+ \else
+ \if #1% during output:
+ \tracepagemakeup{Float moved to top of this page.}%
+ \zmakefloattop
+ \else % when encountered:
+ \if \posp{\zbotcolfloats}%
+ \error{hereonlybot}{Cannot position float `here'; already floats
+ at bottom.}%
+ \else\if \dimzerop{\pagetotal}%
+ \tracepagemakeup{Float at top of column: schedule as `top' float.}%
+ \zmakefloattop
+ \else
+ \zfitfloathere{\zfloatfits}{\aboveskip}{\belowskip}%
+ \if \zfloatfits
+ \tracepagemakeup{Float inserted here.}%
+ \setflag \zfloatunsched = \false
+ \else
+ \tracepagemakeup{Float does not fit here.}%
+ \zforcenewpage
+ \zquitscheding
+ \fi
+ \fi\fi
+ \fi
+ \fi
+ \fi}
+
+
+% This scheduler is called for floats with position `here' along with at
+% least one other page position.
+
+\def\zschedhere #1{% {during-output?}
+ \if \andp{\zfloatunsched}{\zfltposhere}%
+ \tracepagemakeup{Float can be positioned `here'.}%
+ \if \zschedseparateloop
+ \tracepagemakeup{Making up a page of separates; quit.}%
+ \zforcenewpage
+ \zquitscheding
+ \else
+ \if #1% during output:
+ \relax
+ \else % when encountered:
+ \if \posp{\zbotcolfloats}%
+ \tracepagemakeup{There are already floats positioned `bottom'.}%
+ \else\if \dimzerop{\pagetotal}%
+ \tracepagemakeup{Float at top of column: schedule as `top' float.}%
+ \zmakefloattop
+ \else
+ \zfitfloathere{\zfloatfits}{\aboveskip}{\belowskip}%
+ \if \zfloatfits
+ \tracepagemakeup{Float inserted here.}%
+ \setflag \zfloatunsched = \false
+ \else
+ \tracepagemakeup{Float does not fit here.}%
+ \fi
+ \fi\fi
+ \fi
+ \fi
+ \fi}
+
+
+\def \zschedalone #1{% {during-output?}
+ \if \andp{\zfloatunsched}{\zfltposalone}%
+ \tracepagemakeup{Float can be positioned `alone'.}%
+ \if \zschedseparateloop
+ \tracepagemakeup{Making up a page of separates; quit.}%
+ \zforcenewpage
+ \zquitscheding
+ \else
+ \if \orp{#1}{\dimzerop{\pagetotal}}%
+ \if \firstcolumnp % building new page
+ \if \zerop{\zfloatsinserted}% no floats on this page, yet
+ \dp\zcurfloatbox = 0pt % Make it fit.
+ \zfitfloat{\zfloatfits}{\true}{\topskip}{999pt}{0pt}%
+ \if \zfloatfits
+ \ztallytopfloat
+ \tracepagemakeup{Inserted on a page by itself.}%
+ \zforcenewpage
+ \setflag \zfloatunsched = \false
+ \zquitscheding
+ \fi
+ \else % wait for next time
+ \tracepagemakeup{Already floats in this column; quit.}%
+ \zquitscheding
+ \fi
+ \else% still in the middle of a page
+ \tracepagemakeup{Not in first column of page; quit.}%
+ \zquitscheding
+ \fi
+ \else % As encountered, and page not empty.
+ \tracepagemakeup{Must wait for new page; quit.}%
+ \zquitscheding
+ \fi
+ \fi
+ \fi}
+
+\def \zschedbroadside #1{% {during-output?}
+ \if \andp{\zfloatunsched}{\zfltposbroadside}%
+ \tracepagemakeup{Float can be positioned `broadside'.}%
+ \if \zschedseparateloop
+ \tracepagemakeup{Making up a page of separates; quit.}%
+ \zforcenewpage
+ \zquitscheding
+ \else
+ \if \orp{#1}{\dimzerop{\pagetotal}}%
+ \if \firstcolumnp % building new page
+ \if \zerop{\zfloatsinserted}% no floats on this page, yet
+ % Broadside floats "always" fit. The output will have to be
+ % inspected.
+ \zfitfloatbroadside
+ \ztallytopfloat
+ \tracepagemakeup{Inserted on a page by itself.}%
+ \zforcenewpage
+ \setflag \zfloatunsched = \false
+ \zquitscheding
+ \else % wait for next time
+ \tracepagemakeup{Already floats on this page; quit.}%
+ \zquitscheding
+ \fi
+ \else% still in the middle of a page
+ \tracepagemakeup{Not in first column of page; quit.}%
+ \zquitscheding
+ \fi
+ \else % As encountered, and page not empty.
+ \tracepagemakeup{Must wait for new page; quit.}%
+ \zquitscheding
+ \fi
+ \fi
+ \fi}
+
+
+\def\zschedseparate #1{% {during-output?}
+ \if \andp{\zfloatunsched}{\zfltposseparate}%
+ \tracepagemakeup{Float can be positioned `separate'.}%
+ % If a separate float is called when encountered, we don't do anything.
+ \if #1% during output
+ \if \firstcolumnp % building a new page
+ \if \zschedfirstseparate
+ \if \zerop{\zfloatsinserted}% no floats on this page, yet
+ \zfloatmaxavail = \vsize % Entire page is available now.
+ \zfitfloat{\zfloatfits}{\true}{\topskip}{999pt}{0pt}%
+ \if \zfloatfits
+ \ztallytopfloat
+ \setflag \zfloatunsched = \false
+ \zforcenewpage % This is a page of separates now.
+ \tracepagemakeup{Inserted at the top of a new page.}%
+ \setflag \zschedfirstseparate = \false
+ \setflag \zschedseparateloop = \true
+ \else
+ \zsetfloattall
+ \fi
+ \else % wait for next time
+ \tracepagemakeup{Page already has other floats on it.}%
+ \zquitscheding
+ \fi
+ \else % Subsequent separates.
+ \zfloatabove = \if \dimlssp{\aboveskip}{\belowskip}\aboveskip
+ \else \belowskip \fi
+ \zfitfloat{\zfloatfits}{\true}{999pt}{\zfloatabove}{0pt}%
+ \if \zfloatfits
+ \ztallytopfloat
+ \setflag \zfloatunsched = \false
+ \tracepagemakeup{Inserted on a page with other separates.}%
+ \else
+ \zquitscheding
+ \tracepagemakeup{Does not fit on this page; start new page.}%
+ \fi
+ \fi
+ \else% still in the middle of a page
+ \tracepagemakeup{Must wait for new page; quit;}%
+ \zquitscheding
+ \fi
+ \else% when encountered
+ \tracepagemakeup{Must wait for new page; quit.}%
+ \zquitscheding
+ \fi
+ \fi}
+
+
+\def\zschedtop#1{% {during-output?}
+ \if \andp{\andp{\zfloatunsched}{\zfltpostop}}
+ {\orp{\notp{\zfltposfollow}}{#1}}%
+ \tracepagemakeup{Float can be positioned `top'.}%
+ \if \zschedseparateloop
+ \tracepagemakeup{Making up a page of separates; quit.}%
+ \zforcenewpage
+ \zquitscheding
+ \else
+ \if \lssp{\ztopcolfloats}{\maxtopcolumnfloats}%
+ \zfloatabove = \if \dimlssp{\aboveskip}{\belowskip}\aboveskip
+ \else \belowskip \fi
+ \advance \zfloatabove by -\belowskip
+ \advance \zfloatabove by \topskip
+ \zfloatbelow = \belowskip
+ \tdimena = \topskip
+ \advance \zfloatbelow by -\tdimena
+ \advance \zfloatbelow by -\zfloatdp
+ \zfitfloat{\zfloatfits}{\true}{\topskip}{\zfloatabove}{\zfloatbelow}%
+ \if \zfloatfits
+ \ztallytopfloat
+ \tracepagemakeup{Inserted at top of column.}%
+ \setflag \zfloatunsched = \false
+ \else
+ \if \andp{#1}{\zerop{\zfloatsinserted}}\zsetfloattall \fi
+ \fi
+ \fi
+ \fi
+ \fi}
+
+\def \zschedbottom#1{% {during-output?}
+ \if \andp{\zfloatunsched}{\zfltposbottom}%
+ \tracepagemakeup{Float can be positioned `bottom'.}%
+ \if \zschedseparateloop
+ \tracepagemakeup{Making up a page of separates; quit.}%
+ \zforcenewpage
+ \zquitscheding
+ \else
+ \if \lssp{\zbotcolfloats}{\maxbottomcolumnfloats}%
+ \zfloatbelow = \if \dimlssp{\aboveskip}{\belowskip}\aboveskip
+ \else \belowskip \fi
+ \zfitfloat{\zfloatfits}{\false}{\aboveskip}{\zfloatbelow}{0pt}%
+ \if \zfloatfits
+ \if \notp{\zfltpostopafterbot}%
+ \global\ztopcolfloats = \maxtopcolumnfloats
+ \fi
+ \global\increment \zbotcolfloats
+ \tracepagemakeup{Inserted at bottom of column.}%
+ \setflag \zfloatunsched = \false
+ \else
+ \if \andp{#1}{\zerop{\zfloatsinserted}}\zsetfloattall \fi
+ \fi
+ \fi
+ \fi
+ \fi}
+
+% Captions
+% --------
+
+
+\defineblock{\caption}{\endcaption}{\false}{}
+
+%~block caption Type
+% \aboveskip = glue % Space b/b above caption.
+% \setflag \allowintoc = flag % Allow caption in ToC.
+% \belowskip = glue % Space b/b below caption.
+% \captionfudge = dimen % Fudge for \aboveskip.
+% \def \comptextformat {...} % (No longer used with captions.)
+% \difficulty = integer % Level of difficulty.
+% \leftindent = glue % Left indentation.
+% \legendfont = {...} % Font for optional legend.
+% \def \legendformat ##1{...} % Legend formatter.
+% \numberfont = {...} % Font for float number.
+% \parindent = dimen % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \position = {...} % Position (see below).
+% \rightindent = glue % Right indentation.
+% \style = {...} % Heading style.
+% \titlefont = {...} % Font for caption title.
+% \def \titleformat ##1{...} % Title formatter.
+% \width = dimen % Width of caption text.
+%~end
+
+\definedimen{\captionfudge}{0pt}
+\definetoks{\legendfont}
+
+\definebox{\zcapbox}
+\definedimen{\zcapshift}{0pt}
+
+%~ This marker indicates that the following text is the legend or
+%~ credit for the caption.
+
+\definemarker{\legend}
+
+
+\def \caption #1{% {title with optional \legend}
+ \blockmustbein{\caption}{\float}%
+ \blockcantbein{\caption}{\caption}%
+ \beginblockscope{caption}%
+ \global\increment \captiondepth
+ \captionfudge = 0pt %~default with
+ \def \comptextformat {}% %~default hard
+ \style = {Initial cap/lowercase}% %~default soft
+ \difficulty = 0 %~default with
+ \processdesign{\caption}{\zcurflttype}%
+ \global\increment \captionnumber
+ \if \notp{\emptydefp{\comptextformat}}%
+ \error{capcomptext}{The \string\comptextformat\space parameter is no
+ longer used in captions}
+ \fi
+ \captionformat #1\legend\zmark
+ \if \andp{\allowintoc}{\notp{\continuationp}}\zcaptoc #1\legend\zmark \fi
+ \endcaption
+ \zcaptag #1\legend\zmark}% % Reset tag info with title.
+
+\def \endcaption {%
+ \global\decrement \captiondepth
+ \endblockscope{caption}}
+
+\def \captionformat #1\legend#2\zmark{%
+ \the\numberfont
+ \setbox\zcapbox = \vtop{%
+ \zpushvcontext
+ \setindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \setparrag{\parrag}%
+ \if \emptyargp{#2}%
+ \titleformat{#1}%
+ \else
+ \let \legend = \relax % So it won't interfere with formatting.
+ \titleformat{#1\the\legendfont \legendformat{#2}}%
+ \fi
+ \endgraf
+ \global\zfloatdp = \prevdepth
+ \zpopvcontext}%
+ \zparsecappos{\the\position}%
+ \zcalccapitems
+ \bbskipabove{\breaknever}{\aboveskip}%
+ \noindent \kern \zcapshift \box\zcapbox \par
+ \prevdepth = \zfloatdp
+ \bbskipbelow{\breaknever}{\belowskip}}
+
+\def \zcaptoc #1\legend#2\zmark{%
+ \tocentry{\the\floatcomptext}{#1}{\zcurfltlvl}}
+
+\def \zcaptag #1\legend#2\zmark{%
+ \settaginfo{\the\floatcomptext}{#1}}
+
+% Position Handling
+% -------- --------
+
+
+% This macro sets up variables that specify the position of a float,
+% according to the \position design parameter:
+%
+% \alone Place float on a page by itself.
+% \anypage Place float on any page.
+% \any (synonym for \anypage)
+% \bottom Place float at the bottom of a page.
+% \broadside Place float broadside (alone, rotated 90 degrees).
+% \evenpage Place float on an even page.
+% \follow Float must follow its position in the text.
+% \here Place float exactly where it appears.
+% \ifevenpage Use next position only on even page.
+% \ifoddpage Use next position only on odd page.
+% \leftmargin Shift float to left margin.
+% \margin Same as \leftmargin.
+% \marginonly Float fits in the margin and does not occupy any
+% vertical space on the page.
+% \nofollow Float need not follow its position in the text.
+% \oddpage Place float on an odd page.
+% \outsidemargin Shift float to outside margin.
+% \rightmargin Shift float to right margin.
+% \separate Place float on a page with floats only.
+% \textarea Leave float at left edge of text area.
+% \text (synonym for \textarea)
+% \top Place float at the top of a page.
+% \topafterbottom Okay to schedule \top float after \bottom.
+
+
+\definecount{\zfltposshift}{0}
+
+
+\def \zparsefltpos #1{% {options...}
+ {\zclearfltpagepos
+ \global\setflag \zfltposmargonly = \false
+ \global\zfltposshift = 0\relax
+ \zsetupfltpageopts
+ \def \ifevenpage ##1{\if \evenp{\floatpage}##1\fi}%
+ \def \ifoddpage ##1{\if \oddp{\floatpage}##1\fi}%
+ \def \leftmargin {\global\zfltposshift=1\relax}%
+ \let \margin = \leftmargin
+ \def \marginonly {\global\setflag\zfltposmargonly=\true}%
+ \def \outsidemargin{\ifevenpage{\leftmargin}\ifoddpage{\rightmargin}}%
+ \def \rightmargin {\global\zfltposshift=2\relax}%
+ \def \textarea {\global\zfltposshift=0\relax}%
+ \let \text = \textarea
+ \global\floatpage = \floatpage
+ #1%
+ \global\setflag \zfltposhereonly = \zfltposhere
+ \global\setflag \zfltposok = \zfltposhere
+ \if \orp{\zfltposalone}
+ {\orp{\zfltposbottom}
+ {\orp{\zfltposbroadside}
+ {\orp{\zfltposseparate}
+ {\zfltpostop}}}}%
+ \global\setflag \zfltposhereonly = \false
+ \global\setflag \zfltposok = \true
+ \fi
+ \if \zfltposhereonly \setflag \zfltposhere = \false \fi
+ \if \notp{\zfltposok}%
+ \warning{nofloatpos}{No page position has been specified for a float}%
+ \global\setflag \zfltposalone = \true
+ \fi}}
+
+\def \zparsefltpagepos #1{% {options...}
+ {\zclearfltpagepos
+ \zsetupfltpageopts
+ #1%
+ \global\setflag \zfltposhereonly = \zfltposhere
+ \if \orp{\zfltposalone}
+ {\orp{\zfltposbottom}{\orp{\zfltposseparate}{\zfltpostop}}}%
+ \global\setflag \zfltposhereonly = \false
+ \fi
+ \if \zfltposhereonly \global\setflag \zfltposhere = \false \fi}}
+
+\def \zclearfltpagepos {%
+ \global\setflag \zfltposalone = \false
+ \global\setflag \zfltposbottom = \false
+ \global\setflag \zfltposbroadside = \false
+ \global\setflag \zfltposeven = \false
+ \global\setflag \zfltposfollow = \false
+ \global\setflag \zfltposhere = \false
+ \global\setflag \zfltposodd = \false
+ \global\setflag \zfltposseparate = \false
+ \global\setflag \zfltpostop = \false
+ \global\setflag \zfltpostopafterbot = \false}
+
+\def \zsetupfltpageopts {%
+ \def \alone {\global\setflag\zfltposalone=\true}%
+ \def \anypage {\global\setflag\zfltposeven=\false
+ \global\setflag\zfltposodd=\false}%
+ \let \any = \anypage
+ \def \bottom {\global\setflag\zfltposbottom=\true}%
+ \def \broadside {\global\setflag\zfltposbroadside=\true}%
+ \def \evenpage {\global\setflag\zfltposeven=\true}%
+ \def \follow {\global\setflag\zfltposfollow=\true}%
+ \def \here {\global\setflag\zfltposhere=\true}%
+ \def \nofollow {\global\setflag\zfltposfollow=\false}%
+ \def \oddpage {\global\setflag\zfltposodd=\true}%
+ \def \separate {\global\setflag\zfltposseparate=\true}%
+ \def \top {\global\setflag\zfltpostop=\true}%
+ \def \topafterbottom {\global\setflag\zfltpostopafterbot=\true}}
+
+\def \zcalcfltparams {%
+ \floatshift = 0pt\relax
+ % Set \floatshift
+ \ifcase \zfltposshift
+ \relax
+ \or
+ \floatshift = \if \evenp{\floatpage}-\evenlefttextmargin
+ \else -\oddlefttextmargin \fi \relax
+ \or
+ \floatshift = \textmeasure
+ \else
+ \zzerror{Invalid value for float `\string\zfltposshift'}%
+ \fi
+ \advance \floatshift by \leftindent
+
+ % Set \floatwidth. Default of \naturalwidth is handled differently
+ % for broadsides than for non-broadsides. If \width not default, use
+ % it without modification.
+
+ \if \dimeqlp{\width}{\naturalwidth}%
+ \if \zfltposbroadside
+ \floatwidth = \textareaheight \relax
+ \else
+ \floatwidth = \textmeasure \relax
+ \ifcase \zfltposshift
+ \relax
+ \or
+ \advance \floatwidth by -\floatshift
+ \or
+ \floatwidth = \if \evenp{\floatpage}\evenrighttextmargin
+ \else \oddrighttextmargin \fi \relax
+ \else
+ \zzerror{Invalid value for float `\string\zfltposshift'}%
+ \fi
+ \fi
+ \else
+ \floatwidth = \width \relax
+ \fi}
+
+
+% This macro sets up variables that specify the position of a caption,
+% according to the \position design parameter:
+%
+% \above Caption is placed above the figure.
+% \below Caption is placed below the figure.
+% \follow Caption follows left edge of float.
+% \ifevenpage Use next position only on even page.
+% \ifoddpage Use next position only on odd page.
+% \leftmargin Force caption in left margin.
+% \margin Same as \leftmargin
+% \outsidemargin Shift caption to outside margin.
+% \rightmargin Force caption in right margin.
+% \rise Caption rises up from bottom of figure.
+% \separate Caption is separate from figure.
+% \sink Caption sinks down from top of figure.
+% \textarea Force caption at left edge of text area.
+% \text (synonym for \textarea)
+% \textarearight Force caption at right edge of text area.
+% \textright (synonym for \textarearight)
+
+
+\definecount{\zcapposshift}{0}
+\definecount{\zcapposvflow}{0}
+
+\def \zparsecappos #1{% {options...}
+ {\global\setflag \zcapposabove = \true
+ \global\zcapposvflow = 0\relax
+ \global\zcapposshift = 0\relax
+ \def \above {\global\setflag\zcapposabove=\true}%
+ \def \below {\global\setflag\zcapposabove=\false}%
+ \def \follow {\global\zcapposshift=4\relax}%
+ \def \ifevenpage ##1{\if \evenp{\floatpage}##1\fi}%
+ \def \ifoddpage ##1{\if \oddp{\floatpage}##1\fi}%
+ \def \leftmargin {\global\zcapposshift=1\relax}%
+ \let \margin = \leftmargin
+ \def \outsidemargin {\ifevenpage{\leftmargin}\ifoddpage{\rightmargin}}%
+ \def \rightmargin {\global\zcapposshift=2\relax}%
+ \def \rise {\global\zcapposvflow=1\relax}%
+ \def \separate {\global\zcapposvflow=0\relax}%
+ \def \sink {\global\zcapposvflow=2\relax}%
+ \def \textarea {\global\zcapposshift=0\relax}%
+ \let \text = \textarea
+ \def \textarearight {\global\zcapposshift=3\relax}%
+ \let \textright = \textarearight
+ #1}}
+
+\def \zcalccapitems {%
+ \ifcase \zcapposshift
+ \zcapshift = 0pt
+ \or
+ \zcapshift = \if \evenp{\floatpage}-\evenlefttextmargin
+ \else -\oddlefttextmargin \fi \relax
+ \or
+ \zcapshift = \textmeasure
+ \or
+ \zcapshift = \textmeasure
+ \advance \zcapshift by -\wd\zcapbox
+ \or
+ \zcapshift = \floatshift
+ \else
+ \zzerror{Invalid value for caption `\string\zcapposshift'}%
+ \fi
+ \advance \zcapshift by -\floatshift
+ % Captions in broadsides *always* follow, i.e. \zcapshift is 0pt
+ \if \zfltposbroadside
+ \zcapshift = 0pt\relax
+ \fi
+ \ifcase \zcapposvflow
+ \relax
+ \or
+ \forcenextbbskip
+ \aboveskip = -\dp\zcapbox
+ \advance \aboveskip by \zfloatdp
+ \advance \aboveskip by \captionfudge
+ \or
+ \advance \belowskip by -\dp\zcapbox
+ \advance \belowskip by -\captionfudge
+ \else
+ \zzerror{Invalid value for caption `\string\zcapposvflow'}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zzfont.tex b/macros/plain/contrib/zztex/tex/zzfont.tex
new file mode 100644
index 0000000000..f2b15f3775
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzfont.tex
@@ -0,0 +1,453 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Font Facilities
+%
+% Synopsis: This module contains all the macros necessary to define type
+% sizes, styles, and fonts.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 28 August 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Baselines & Struts
+% --------- - ------
+
+
+\zremovePlaindef \strutbox
+\definebox{\strutbox} % Strut for current type size.
+
+\def \strut {%
+ \relax
+ \if \mathmodep
+ \copy \strutbox
+ \else
+ \unhcopy \strutbox
+ \fi}
+
+\def \normalbaselines {%
+ \baselineskip = \the\baselinemultiplier\normalbaselineskip
+ \lineskiplimit = \normallineskiplimit
+ \lineskip = \normallineskip}
+
+% Type Style & Size Definition
+% ---- ----- - ---- ----------
+
+
+% The following character set encodings are available. Odd numbers
+% indicate italic; numbers > 20 indicate monospaced.
+
+\chardef \encoderoman = 0 % Roman. %^encoding
+\chardef \encodeitalic = 1 % Italic. %^encoding
+\chardef \encodemathitalic = 3 % Math italic. %^encoding
+\chardef \encodemathsymbol = 4 % Math symbols. %^encoding
+\chardef \encodemathextended = 6 % Math extended symbols. %^encoding
+\chardef \encodematharrow = 8 % Math arrows. %^encoding
+\chardef \encodeother = 10 % Generic. %^encoding
+\chardef \encodemono = 22 % Monospaced. %^encoding
+\chardef \encodemonoitalic = 23 % Monospaced italic. %^encoding
+
+\setlist \zfsizelist = {}
+\setlist \zfstylelist = {}
+
+
+\def \definetypestyle #1#2{% {\name}{\encoding}
+ \append{#1}{\zfstylelist}%
+ \zfwithfam{\zdeffam}{#1}%
+ \zfwithmat{\def}{#1}{\zfl}{}%
+ \zfwithmat{\xdef}{#1}{\zen}{#2}}
+
+\def \definetypesize #1#2{% {\name}{size/baseline}
+ \append{#1}{\zfsizelist}%
+ \zdefsize #1#2/%
+ \zdefstrut #1#2/%
+ \zfbldsize{#1}}
+
+\def \zdefsize #1#2/#3/{% \name size/baseline/
+ \zfwithmat{\xdef}{#1}{\zsz}{#2pt}}
+
+\def \zdefstrut #1#2/#3/{% \name size/baseline/
+ {\calculate \tdimena = {#3pt,P,70}%
+ \tdimenb = #3pt\relax
+ \advance \tdimenb by -\tdimena
+ \zfwithmat{\xdef}{#1}{\zst}{height \the\tdimena\space depth \the\tdimenb}}}
+
+
+% A few useful predicates.
+
+\def \typestylep #1{% {\style}
+ \xtokeqlp{\the\typestyle}{#1}}
+
+\def \italicencodingp {%
+ \oddp{\typeencoding}}
+
+\def \monoencodingp {%
+ \gtrp{\typeencoding}{20}}
+
+% Commands to set font parameters.
+
+\def \setstylefontparam #1#2#3{% {\style}{param}{value}
+ \zfwithmat\maplistlf {#1}{\zfl}{%
+ \zfsetfp{##1}{#2}{#3}}}
+
+\def \setstylehyphenchar #1#2{% {\style}{number}
+ \setstylefontparam{#1}{-2}{#2}}
+
+\def \setstyleskewchar #1#2{% {\style}{number}
+ \setstylefontparam{#1}{-1}{#2}}
+
+\def \zfsetfp #1#2#3{% {font}{param}{value}
+ \if \eqlp{#2}{-2}%
+ \hyphenchar #1=#3\relax
+ \else\if \eqlp{#2}{-1}%
+ \skewchar #1=#3\relax
+ \else
+ \fontdimen#2#1=#3\relax
+ \fi\fi}
+
+% Style Relations
+% ----- ---------
+
+
+\def \definestylerelation #1#2#3{% {\style}{\relation}{\style}
+ \zfwithmat{\gdef}{#1}{#2}{#3}%
+ \gdef #2{\bgroup \zfrelstyle{#2}%
+ \if \italicencodingp \aftergroup \/\fi
+ \let \znext}}
+
+\def \zfrelstyle #1{% {\relation}
+ \if \mathmodep
+ \ztoksa = \expandaftertwice{\zfmat\math#1}%
+ \expandafter\ifx \the\ztoksa\relax
+ \zfnorelstyle{math}{#1}%
+ \fi
+ \else
+ \ztoksa = \expandafterthrice{\expandafter\zfmat\the\typestyle#1}%
+ \expandafter\ifx \the\ztoksa\relax
+ \zfnorelstyle{\the\typestyle}{#1}%
+ \fi
+ \fi
+ \the\ztoksa}
+
+\def \zfnorelstyle #1#2{%
+ \error{norelstyle}
+ {The current `#1' style has no related style for `\string#2'}}
+
+% Font Definition
+% ---- ----------
+
+
+\setlist \ztfmlist = {}%
+
+
+\def \definefont #1#2{% {\name}{tfm at size}
+ \global\font #1 = #2\relax
+ \zregistertfm #2\zmark
+ \if \zcommonencoding
+ \if \andp{\dimposp{\fontdimen7#1}}{\dimlssp{\fontdimen7#1}{.1pt}}%
+ \fontdimen7#1 = \fontdimen2#1\relax % Unlock it.
+ \else\if \dimeqlp{\fontdimen7#1}{\fontdimen2#1}
+ \relax % Already unlocked.
+ \else
+ \error{lockedfont}{The TFM for font `#2' is locked}%
+ \fi\fi
+ \fi}
+
+\def \zregistertfm #1 #2\zmark{% tfm at size\zmark
+ \member{\ztfmreg}{#1}{\ztfmlist}%
+ \if \notp{\ztfmreg}\append{#1}{\ztfmlist}\fi}
+
+\def \fontinterwordspacing #1#2{% {font}{factor}
+ \fontdimen2#1= #2\fontdimen2#1%
+ \fontdimen3#1= #2\fontdimen3#1%
+ \fontdimen4#1= #2\fontdimen4#1%
+ \fontdimen7#1= #2\fontdimen7#1}
+
+% Font Selection
+% ---- ---------
+
+
+\definetoks{\typesizename} % Current type size name.
+\definedimen{\typesize}{0pt} % Current type size in points.
+\definetoks{\typestyle} % Current type style.
+\definecount{\typeencoding}{0} % Current type encoding.
+
+
+% Equal signs and by's have been omitted for the sake of efficiency.
+
+\def \setfont #1#2#3{% {\size}{\style}{\font}
+ \setfontmath{#1}{#2}{#3}{\nullfont}{\nullfont}}
+
+\def \setfontmath #1#2#3#4#5{% {\size}{\style}{\text}{\script}{\scriptscript}
+ \edef \zfam {\zffam{#2}}%
+ \zfwithmat{\xdef}{#1}{#2}{%
+ \textfont \zfam #3%
+ \scriptfont \zfam #4%
+ \scriptscriptfont \zfam #5%
+ \def \noexpand#2{%
+ \typestyle {\noexpand#2}%
+ \typeencoding \zfmat{#2}{\zen}%
+ #3%
+ \fam \zfam}}%
+ \zfbldsize{#1}%
+ \zfaddfont{#2}{#3}%
+ \zfaddfont{#2}{#4}%
+ \zfaddfont{#2}{#5}}
+
+\def \zfbldsize #1{% {\size}
+ {\gdef #1{}
+ \maplist{\zfaddstyle{#1}{##1}}{\zfstylelist}%
+ \ztoksa \expandafter{#1}%
+ \xdef #1{%
+ \typesizename {\noexpand#1}%
+ \typesize \zfmat{#1}{\zsz}%
+ \the\ztoksa
+ \setbox\strutbox \hbox{\vrule \zfmat{#1}{\zst} width 0pt}%
+ \normalbaselineskip \ht\strutbox
+ \advance \normalbaselineskip \dp\strutbox
+ \noexpand\normalbaselines
+ \typestyle {none}\nullfont \fam -1\relax}}}
+
+\def \zfaddstyle #1#2{% {\size}{\style}
+ \ztoksa \expandafter{#1}%
+ \ztoksb \expandaftertwice{\zfmat{#1}{#2}}%
+ \expandafter\ifx \the\ztoksb\relax
+ \xdef #1{\the\ztoksa
+ \noexpand\zclearfam{\zffam{#2}}%
+ \def \noexpand#2{\noexpand\zfundef{\noexpand#1}{\noexpand#2}}}%
+ \else
+ \xdef #1{\the\ztoksa \the\ztoksb}%
+ \fi}
+
+\def \zfaddfont #1#2{% {\style}{font}
+ \zfwithmat{\appendlf}{#1}{\zfl}{#2}}
+
+
+% This macro clears out a family so TeX can't set math in it.
+
+\def \zclearfam #1{% {family}
+ \textfont #1 \nullfont
+ \scriptfont #1 \nullfont
+ \scriptscriptfont #1 \nullfont}
+
+% This macro is called if the user selects a type style that has no font
+% in the current size.
+
+\def \zfundef #1#2{% {\size}{\style}
+ \error{nofontset}
+ {No font has been set for size `\string#1' style `\string#2'}}
+
+% Miscellaneous
+% -------------
+
+
+% The following definition allows the user to write:
+% \withfont{\bf Hi there}
+
+\let \withfont = \relax
+
+% This macro helps with defining math fonts.
+
+\def \definemathfonts #1#2#3#4#5#6{% {prefix}{rm-font}{mit}{msy}{mex}{size}
+ \edef \znext {%
+ \noexpand\definefont{\name{#1rm}}{#2 at #6}%
+ \noexpand\definefont{\name{#1mit}}{#3 at #6}%
+ \noexpand\definefont{\name{#1msy}}{#4 at #6}%
+ \noexpand\definefont{\name{#1mex}}{#5 at #6}}%
+ \znext}
+
+% This macro helps with setting math fonts.
+
+\def \setmathfonts #1#2#3#4{% {\size}{\text}{\script}{\scriptscript}
+ \edef \znext {%
+ \noexpand\setfontmath{\noexpand#1}{\noexpand\rm}%
+ {\name{#2rm}}{\name{#3rm}}{\name{#4rm}}%
+ \noexpand\setfontmath{\noexpand#1}{\noexpand\mit}%
+ {\name{#2mit}}{\name{#3mit}}{\name{#4mit}}%
+ \noexpand\setfontmath{\noexpand#1}{\noexpand\msy}%
+ {\name{#2msy}}{\name{#3msy}}{\name{#4msy}}%
+ \noexpand\setfontmath{\noexpand#1}{\noexpand\mex}%
+ {\name{#2mex}}{\name{#2mex}}{\name{#2mex}}}%
+ \znext}
+
+% Measuring Things
+% --------- ------
+
+
+\definebox{\zmeasbox}
+
+
+\def \measureascenderheight #1{% {\dimen}
+ \zsetmeasbox{bdfhijklt}%
+ #1 = \ht\zmeasbox}
+
+\def \measurecapheight #1{% {\dimen}
+ \zsetmeasbox{ABCDEFGHIJKLMNOPQRSTUVWXYZ}%
+ #1 = \ht\zmeasbox}
+
+\def \measuredescenderdepth #1{% {\dimen}
+ \zsetmeasbox{gjpqy}%
+ #1 = \dp\zmeasbox}
+
+\def \measuredigitheight #1{% {\dimen}
+ \zsetmeasbox{0123456789}%
+ #1 = \ht\zmeasbox}
+
+\def \measuredigitwidth #1{% {\dimen}
+ \zsetmeasbox{0}%
+ #1 = \wd\zmeasbox}
+
+\def \measureemwidth #1{% {\dimen}
+ #1 = 1em}
+
+\def \measurespacewidth #1{% {\dimen}
+ #1 = \fontdimen2\font}
+
+\def \measurexheight #1{% {\dimen}
+ #1 = 1ex}
+
+\def \measuretextwidth #1#2{% {\dimen}{text}
+ \zsetmeasbox{#2}%
+ #1 = \wd\zmeasbox}
+
+\def \measuretextheight #1#2{% {\dimen}{text}
+ \zsetmeasbox{#2}%
+ #1 = \ht\zmeasbox}
+
+\def \measuretextdepth #1#2{% {\dimen}{text}
+ \zsetmeasbox{#2}%
+ #1 = \dp\zmeasbox}
+
+\def \zsetmeasbox #1{\setbox\zmeasbox = \hbox{#1}}
+
+\def \definewidthdimen #1#2{% {\dimen}{text}
+ \definedimen{#1}{0pt}%
+ \measuretextwidth{#1}{#2}}
+
+% Utilities
+% ---------
+
+
+\def \zfmat #1#2{% {\size}{\style}
+ \csname zf\expandafter\discardtok \string#1%
+ \expandafter\discardtok \string#2\endcsname}
+
+\def \zfwithmat #1#2#3{% {\command}{\size}{\style}
+ \expandafter#1\csname zf\expandafter\discardtok \string#2%
+ \expandafter\discardtok \string#3\endcsname}
+
+
+\def \zffam #1{% {\style}
+ \csname \expandafter\discardtok \string#1fam\endcsname}
+
+\def \zfwithfam #1#2{% {\command}{\style}
+ \expandafter#1\csname \expandafter\discardtok \string#2fam\endcsname}
+
+% Built-in Styles
+% -------- ------
+
+
+\zremovePlaindef \itfam
+\zremovePlaindef \bffam
+\zremovePlaindef \ttfam
+
+ % Family Name
+\definetypestyle{\rm}{\encoderoman} % 0 RoMan
+\definetypestyle{\mit}{\encodemathitalic} % 1 Math ITalic
+\definetypestyle{\msy}{\encodemathsymbol} % 2 Math SYmbol
+\definetypestyle{\mex}{\encodemathextended} % 3 Math EXtended symbol
+\definetypestyle{\cal}{\encoderoman} % 4 CALigraphic letters
+\definetypestyle{\bbb}{\encoderoman} % 5 BlackBoard Bold
+\definetypestyle{\it}{\encodeitalic} % 6 ITalic
+\definetypestyle{\bf}{\encoderoman} % 7 Bold Face
+\definetypestyle{\bi}{\encodeitalic} % 8 Bold Italic
+\definetypestyle{\tt}{\encodemono} % 9 monospaced (TypewriTer)
+
+% Note: style \math is reserved for math mode.
+
+\definestylerelation{\math}{\bbbold}{\bbb}
+\definestylerelation{\math}{\bold}{\bf}
+\definestylerelation{\rm}{\bold}{\bf}
+\definestylerelation{\it}{\bold}{\bi}
+\definestylerelation{\math}{\callig}{\cal}
+\definestylerelation{\rm}{\callig}{\cal}
+\definestylerelation{\rm}{\emph}{\it}
+\definestylerelation{\it}{\emph}{\rm}
+\definestylerelation{\bf}{\emph}{\bi}
+\definestylerelation{\bi}{\emph}{\bf}
+\definestylerelation{\math}{\fraktur}{\frk}
+\definestylerelation{\tt}{\meta}{\it}
+\definestylerelation{\math}{\roman}{\rm}
+\definestylerelation{\rm}{\roman}{\rm}
+\definestylerelation{\it}{\roman}{\rm}
+\definestylerelation{\bf}{\roman}{\rm}
+\definestylerelation{\tt}{\roman}{\rm}
+\definestylerelation{\rm}{\smallcaps}{\sc}
+
+% We do not define any sizes or fonts. They just take up memory.
+
+% Doodad Font
+% ------ ----
+
+
+\def \zrequiredoodad #1#2{% {\name}{size}
+ \if \undefinedp{\zfdoodad#2}%
+ \withname\definefont {\zfdoodad#2}{zztexorn at #2}%
+ \fi
+ \edef \znext {\let \noexpand#1\name{\zfdoodad#2}}%
+ \znext}
+
+% Font Style Summary
+% ---- ----- -------
+
+
+{\catcode`\_ = \catactive
+
+\gdef \zfontsummary #1{% {font-list?}
+ {\def _{\space}%
+ \writelog{}%
+ \writelog{Type Styles:}%
+ \writelog{}%
+ \writelog{Name_____Math Family}%
+ \writelog{----_____-----------}%
+ \maplist{\zfsone{##1}}{\zfstylelist}%
+ \if #1%
+ \writelog{}%
+ \maplist{\writelog{ZzTeX: Font used: ##1}}{\ztfmlist}%
+ \fi
+ \writelog{}}}
+
+\gdef \zfsone #1{%
+ \tcounta = \name{#1fam}%
+ \writelog{\string #1______%
+ \if \lssp{\tcounta}{10}%
+ _\number\tcounta
+ \else\if \lssp{\tcounta}{15}%
+ \number\tcounta
+ \else
+ ---%
+ \fi\fi}}
+
+}% \catcode
+
+% TFM List File
+% --- ---- ----
+
+
+\definewrite{\ztfmlistfile}
+
+
+\def \zopentfmlist {%
+ \if \zcommonencoding
+ \immediate\openout \ztfmlistfile = tfmlist.zzz\relax
+ \immediate\write \ztfmlistfile {\jobname}%
+ \fi}
+
+\def \zwritetfmlist {%
+ \if \zcommonencoding
+ \maplist{\immediate\write \ztfmlistfile {##1}}{\ztfmlist}%
+ \immediate\closeout \ztfmlistfile
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zzfront.tex b/macros/plain/contrib/zztex/tex/zzfront.tex
new file mode 100644
index 0000000000..f0f281a9fc
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzfront.tex
@@ -0,0 +1,247 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Front Matter Facilities
+%
+% Synopsis: This file provides facilities for typesetting the front
+% matter of a book.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Copyright Page
+% --------- ----
+
+
+\def \copyrightline #1#2{% {year}{publisher}
+ \noindent Copyright \copyright\ #1 by #2\par}
+
+\def \concisecopyrightline #1#2{% {year}{publisher}
+ \noindent \copyright\ #1 by #2\par}
+
+\def \superconcisecopyrightline #1#2{% {year}{publisher}
+ \noindent \copyright\ #1 #2\par}
+
+\def \copyrightnotice {%
+ All rights reserved. No part of this publication may be reproduced,
+ stored in a retrieval system, or transmitted, in any form or by any
+ means, electronic, mechanical, photocopying, recording, or otherwise,
+ without the prior written permission of the publisher.}
+
+
+% We provide a standard text design for the Library of Congress
+% Cataloging-in-Publication data.
+
+\def \textcipdataidesign {%
+ \aboveskip = \noskip
+ \belowskip = \noskip
+ \bodyfont = {}%
+ \setflag \enabletabbing = \false
+ \leftindent = 0pt
+ \parindent = \enclosingparindent
+ \parrag = \enclosingparrag
+ \parskip = 0pt
+ \rightindent = 0pt
+ \setflag \verbatimlines = \true
+ \width = \naturalwidth}
+
+\def \textcipdataiidesign {%
+ \textcipdataidesign}
+
+% Table of Contents Entries
+% ----- -- -------- -------
+
+
+% This macro is used to write a ToC entry in the cross-reference file.
+
+\def \ztocentry #1#2#3#4{% {number}{title}{level}{allow?}
+ {\ztoksa = {#2}%
+ \tcounta = #3\relax
+ \edef \znext {\noexpand\xref{toc}{\noexpand\folio}{#1}{\the\ztoksa}
+ {\the\divisionname,\the\tcounta,%
+ \the\difficulty,\if #41\else 0\fi}}%
+ \znext}}
+
+% This is the public command for writing ToC entries.
+
+\def \tocentry #1#2#3{% {number}{title}{level}
+ \ztocentry{#1}{#2}{#3}{\true}}
+
+% This macro allows the compositor to adjust pages in the ToC.
+
+\setlist \ztocadjlist = {}
+
+\long\def \tocadjustment #1#2#3{% {toc-type}{number}{commands}
+ \append{{#1}{#2}{#3}}{\ztocadjlist}}
+
+% Table of Contents Block
+% ----- -- -------- -----
+
+
+\defineblock{\toc}{\endtoc}{\false}{}
+
+%~block toc Type
+% \abovepenalty = integer % Penalty above text.
+% \aboveskip = glue % Space b/b above text.
+% \belowpenalty = integer % Penalty below text.
+% \belowskip = glue % Space b/b below text.
+% \bodyfont = {\size\style} % Default font for body.
+% \divisions = {...} % List of divisions to include.
+% \foliofont = {\size\style} % Default font for folio.
+% \leftindent = glue % Left indentation.
+% \levels = {...} % List of levels to include.
+% \setflag \minitoc = boolean % Is this a miniToC?
+% \parindent = dimen % Paragraph indentation.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \rightindent = glue % Right indentation.
+% \tocwidtha = dimen % General width a.
+% \tocwidthb = dimen % General width b.
+% \tocwidthc = dimen % General width c.
+% \width = dimen % Line width
+% \xreffile = {...} % Name of composite xref file to use.
+%~end
+
+\definetoks{\foliofont}
+\definetoks{\levels}
+\definedimen{\tocwidtha}{0pt}
+\definedimen{\tocwidthb}{0pt}
+\definedimen{\tocwidthc}{0pt}
+\definetoks{\xreffile}
+
+\definecount{\prevtocprimarylevel}{-1} % Previous level >= 70.
+
+
+\def \toc #1{% {type}
+ \beginblockscope{toc}%
+ \def \ztoctype {#1}%
+ \global\increment \tocdepth
+ \abovepenalty = \breaknever %~default hard
+ \belowpenalty = \breakbest %~default hard
+ \bodyfont = {}% %~default soft
+ \divisions = {\all}% %~default soft
+ \setflag \minitoc = \false %~default soft
+ \tocwidtha = 0pt %~default soft
+ \tocwidthb = 0pt %~default soft
+ \tocwidthc = 0pt %~default soft
+ \xreffile = {}% %~default hard
+ \processdesign{\toc}{#1}%
+ \global\increment \tocnumber
+ \commalist{\zlevlist}{\the\levels}%
+ \the\bodyfont
+ \tocformat
+ \endtoc}
+
+\def \endtoc {%
+ \endgraf
+ \endtocformat
+ \global\decrement \tocdepth
+ \endblockscope{toc}}
+
+\def \tocformat {%
+ \endgraf
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \setparrag{\parrag}%
+ \zadjtitle = \if \minitoc \zadjtitleminitoc \else \zadjtitletoc \fi
+ % \adjusttitle should adjust appropriate ToC.
+ \def \zadjloc {\toc}%
+ \if \emptytoksp{\xreffile}%
+ \zxloadcomp{\xrefloadtocmode}%
+ \else
+ \zxloadothercomp{\the\xreffile}{\xrefloadtocmode}%
+ \fi}
+
+\def \endtocformat {%
+ \fakepar % In case the ToC is empty.
+ \setlist \ztocadjlist = {}%
+ \bbskipbelowblock{\belowpenalty}{\belowskip}}
+
+
+% The following macro is called for each entry in the cross-reference file.
+% Each entry must NOT be in a group.
+
+\def \xreftoc #1#2#3#4{%
+ \ifnum \xrefmode=\xrefloadtocmode
+ \xreftocb{#1}{#2}{#3}{#4}%
+ \fi}
+
+\definecount{\ztoclevel}{0}
+
+\def \xreftocb #1#2#3#4{% {page}{number}{title}
+ % {division,level,difficulty,allow}
+ \def \znext ##1,##2,##3,##4,##5\zmark{%
+ \ztoksa={##1}\ztoclevel=##2\difficulty=##3\tcounta=##4\relax}%
+ \znext #4,1,\zmark%
+ \if \posp{\tcounta}%
+ \edef \znext {\noexpand\inclusionlist\noexpand\ztoctest
+ {\the\ztoksa}{\the\divisions}}%
+ \znext
+ \if \ztoctest
+ \ztesttoclev{\ztoclevel}%
+ \if \ztoctest
+ \zchktocadj{#2}{#3}%
+ \the\bodyfont
+ \name{\toc\ztoctype\romannumeral\ztoclevel format}{#1}{#2}{#3}%
+ \if \gtrp{\ztoclevel}{69}%
+ \prevtocprimarylevel = \ztoclevel % Save ToC level.
+ \global\authortext = {}% % Clear author text.
+ \fi
+ \fi
+ \fi
+ \fi}
+
+\def \ztesttoclev #1{% {level}
+ \setflag \ztoctest = \false
+ \maplist{\ztesttoca{#1}##1-\zmark}{\zlevlist}}
+
+\def \ztesttoca #1#2-#3\zmark{% {n}low-high\zmark
+ \if \emptyargp{#3}%
+ \setflag \ztoctest = {\eqlp{#1}{#2}}%
+ \else
+ \ztesttocb{#1}{#2}#3%
+ \fi
+ \if \ztoctest \exitmaplist \fi}
+
+\def \ztesttocb #1#2#3-{% {n}{low}high-
+ \setflag \ztoctest = {\andp{\notp{\lssp{#1}{#2}}}
+ {\notp{\gtrp{#1}{#3}}}}}
+
+\long\def \zchktocadj #1#2{% {number}{title}
+ \maplist{\zchktocadjb##1{#1}{#2}}{\ztocadjlist}}
+
+\long\def \zchktocadjb #1#2#3#4#5{% {type}{number}{commands}{number}{title}
+ {\stringeql{\znext}{#1}{\ztoctype}%
+ \if \znext
+ \stringeql{\znext}{#2}{#4}%
+ \if \znext
+ #3\relax
+ \else
+ \def \tempa {#2}% % Don't expand titles.
+ \def \tempb {#5}%
+ \if \tokeqlp{\tempa}{\tempb}%
+ #3\relax
+ \fi
+ \fi
+ \fi}}
+
+\def \bbskipabovetochead #1#2#3#4#5{% {level}{penalty}{skip}{penalty}{skip}
+ \if \eqlp{\prevtocprimarylevel}{#1}%
+ \bbskipabove{#2}{#3}%
+ \else
+ \bbskipabove{#4}{#5}%
+ \fi}
+
+\definetoks{\zdelaytoc}
+
+\def \delaytocformatter #1{%
+ \global\zdelaytoc = \expandafter{\the\zdelaytoc #1}}
+
+\def \dodelayedtocformatter {%
+ \the\zdelaytoc
+ \global\zdelaytoc = {}}
diff --git a/macros/plain/contrib/zztex/tex/zzhelp.tex b/macros/plain/contrib/zztex/tex/zzhelp.tex
new file mode 100644
index 0000000000..6d947fbf6b
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzhelp.tex
@@ -0,0 +1,359 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Help Text
+%
+% Synopsis: This file contains the help text for each error and
+% warning signaled by ZzTeX.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 3 July 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+\long\def \definehelp #1#2{% {help-id}{text}
+ \withname\gdef{\=zH:#1}{#2}}
+
+
+\definehelp{adjheads}{
+ You must eliminate the inter-row space between two adjacent rows_
+ of column heads. This is done with the \closeuprows command.}
+
+\definehelp{altinv}{
+ The design alternative named above was specified with an_
+ invalid value in a \designalternative command.}
+
+\definehelp{altreq}{
+ The design alternative named above must be specifed with a_
+ \designalternative command preceding the \loaddesign in_
+ your root file. There is no default.}
+
+\definehelp{artpos}{
+ The \art command is in the wrong position relative to the_
+ \caption command.}
+
+\definehelp{blkcantnest}{
+ The file contains an occurence of the first block mentioned above_
+ nested inside the second block. This is not allowed.}
+
+\definehelp{blkinvnest}{
+ A command to end a block is not properly associated with the command_
+ to begin the block. For example, an \endtext is matched with a \list._
+ All blocks must be properly nested.}
+
+\definehelp{blkmustend}{
+ The file contains an occurence of the block ending command_
+ mentioned first, but it is not preceded by the block starting_
+ command mentioned second. Each block must have a starting command.}
+
+\definehelp{blkmustnest}{
+ The file contains an occurence of the first block mentioned above,_
+ but it is not nested inside the second block. The first block_
+ must be nested in the second.}
+
+\definehelp{cananchor}{
+ The object anchor specified mentioned above is invalid._
+ Valid anchors are 'a' -- 'h'.}
+
+\definehelp{celldecpt}{
+ The picutre for this decimal-aligned cell did not include a decimal_
+ point, but the number to be typeset does. You must include a_
+ decimal point in the template or remove it from the number.}
+
+\definehelp{citelet}{
+ It appears that you have used \let to define a \citexxx command_
+ in the design file. This done not work; use \def instead.}
+
+\definehelp{desjunk}{
+ The design file named above contains some paragraph (horizontal mode)_
+ text that should not be there.__
+ You probably left a percent sign off a comment.}
+
+\definehelp{divnotexist}{
+ The division specified in the message is not included with a_
+ \division command in the root file.}
+
+\definehelp{dupart}{
+ The art file named above is used more than once in the book.__
+ If a figure really is used more than once, you must copy it with
+ another name and change one of the \art commands.}
+
+\definehelp{dupreg}{
+ The register named above has already been defined with another_
+ \definexxx command.}
+
+\definehelp{divortah}{
+ The \overridetextareaheight command has been used to override the_
+ text area height, but the override crosses from one division to the next.__
+ If you continue from the warning, the override will be cancelled.}
+
+\definehelp{empshape}{
+ The \shapepar command must be specified with at least one pair of_
+ indent/width arguments. You have specified one with no arguments.}
+
+\definehelp{hereonlybot}{
+ ZzTeX cannot position the float `here' because there is already_
+ a float positioned at the bottom of the page. Floats must be_
+ positioned in order.}
+
+\definehelp{invindexlvl}{
+ The level specified in an indexing command must be 1, 2, or 3.}
+
+\definehelp{invoper}{
+ The operator shown above is not valid in the expression argument_
+ of the \calculate command.}
+
+\definehelp{invsubpart}{
+ The subpart argument to \markinfo(upcased) must be 1 or 2._
+ You have specified the invalid subpart number shown above.}
+
+\definehelp{locattr}{
+ The attributes of the index locator are not valid. You must specify_
+ at least one of \page or \text.}
+
+\definehelp{missbb}{
+ The specified art file does not have a bounding box comment, so_
+ ZzTeX cannot determine the size of the art.}
+
+\definehelp{misset}{
+ A tabular column template must begin with \set, so that the column
+ type will be correctly interpreted.}
+
+\definehelp{misstah}{
+ The value of \textareaheight must be established by the document_
+ design macro before \calculatetypeareaheight can be used.__
+ You can set it directly or calculate it with \calculatetextareaheight.}
+
+\definehelp{misstopskip}{
+ The value of \topskip must be established by the document design_
+ macro before \calculatetextareaheight can be used.}
+
+\definehelp{misstrim}{
+ The values of \trimwidth and \trimheight must be established by the_
+ document design macro before \calculateoffsets can be used}
+
+\definehelp{needheads}{
+ The \tabheadrule and \skipbelowcolhead commands require that the_
+ previous row is a row of heads.}
+
+\definehelp{negtabvsp}{
+ A negative \tabvspace will not work; it produces no spacing at all._
+ You must use \tabcloseup.}
+
+\definehelp{noartfile}{
+ You have requested the art file named above for an \art block,_
+ but the file does not exist.__
+ If you continue from this warning, the art space will be framed_
+ with corner marks and contain the name of the missing file.}
+
+\definehelp{nobblfile}{
+ You have requested a bibliography list with the \biblio command,_
+ but there is no bibliography item file.__
+ If you continue from this warning, the bibliography list will not_
+ be typeset. You must first run BibTeX to produce the item file.}
+
+\definehelp{nodesfile}{
+ The design file named above is required for this book, but it_
+ does not exist.__
+ You may have misspelled the name of the design file in the_
+ \loaddesign command. If not, the design file must be created.}
+
+\definehelp{nodesign}{
+ The file contains a use of the block named above, but the_
+ book's design file does not contain a design macro_
+ for the block.__
+ It's possible you have misspelled the name of the block_
+ or its type (if any). If not, a design macro must be_
+ added to the design file.}
+
+\definehelp{nodivs}{
+ The \setdivisions command must specify one or more divisions to set.}
+
+\definehelp{noend}{
+ Do not use the \end command in ZzTeX. The root file is terminated_
+ with the \enddocument command.__
+ If you are trying to end a block, such as a \list block, you must_
+ use the corresponding ending command, such as \endlist.}
+
+\definehelp{nofloatpos}{
+ The \position parameter for a float does not specify any_
+ page positions for the float. The page positions are \alone,_
+ \bottom, \here, \separate, and \top. Without a page_
+ position, the float cannot be placed on the page.__
+ This error could be due to a missing position in the design file._
+ Or, you may have specified the \position parameter in a \with_
+ command on the float block and forgotten to include any of the_
+ page positions.__
+ If you continue, the float will be placed alone on a page. This_
+ message may appear again for the same float.}
+
+\definehelp{nofontset}{
+ The file has requested a font of the size and style mentioned above._
+ No font has been set for this size/style in the book's design file.__
+ You may have misspelled the name of the size or style. If not,_
+ the appropriate font must be established in the design file.}
+
+\definehelp{noheadfoot}{
+ The design file does not contain a definition for the header_
+ or footer format specified in the message. These definitions_
+ must be included in the design file.}
+
+\definehelp{noinclfile}{
+ The file mentioned above has been requested with an \include or_
+ \division command, but it does not exist.__
+ You may have misspelled the name of the file. If not, you must_
+ create it before processing the book again.__
+ If you continue from this error, ZzTeX will prompt you for another_
+ file name.}
+
+\definehelp{nomarks}{
+ The \markinfo command is being used to format a running head_
+ or foot, but no mark information has been provided for the_
+ current page.__
+ This only happens at the beginning of a book, before the first_
+ chapter or quasichapter. You may have set running heads and_
+ feet with \setrunners before the first chapter or quasichapter.}
+
+\definehelp{nomnpos}{
+ The \position parameter for a margin note does not specify any_
+ horizontal position for the float. The positions are \leftmargin,_
+ \rightmargin, and \outsidemargin.}
+
+\definehelp{noreftitle}{
+ The use of the \reftitle command has been disabled in the_
+ design file with the \allowreftitle document parameter.__
+ If you did not intend to use the \reftitle command, you must_
+ remove it from the file. If you need to use it, then modify_
+ the design file appropriately.}
+
+\definehelp{noregsleft}{
+ All of the available registers of the type specified in the_
+ message have been allocated for use, but a request for another_
+ such register has been made.}
+
+\definehelp{norelstyle}{
+ You have requested a type style related to the current style,_
+ but no such relation has been established. For example, the_
+ current style is \tt and you want to emphasize text with the_
+ \emph command, but no style for emphasizing monospaced text_
+ has been established.__
+ Use the \definestylerelation command to establish the appropriate_
+ relationship.}
+
+\definehelp{notaginfo}{
+ A \tag command has been specified in the current block, but_
+ the composite number and title has not been established yet.}
+
+\definehelp{notindexing}{
+ ZzTeX has encountered an indexing command (e.g., \xpage), but_
+ you have not included a \produceindex command in the root file._
+ At least one \produceindex command is required if the files contain_
+ indexing commands.__
+ If you continue from the warning, the index entries will be written_
+ to the log file.}
+
+\definehelp{notps}{
+ The feature show above is only available when you are producing_
+ PostScript output. It requires PostScript capabilities.}
+
+\definehelp{nowith}{
+ The \with modifier is not allowed on the command specified in the_
+ message. You must remove the \with modifier.__
+ If you continue from this warning, the \with will be ignored._
+ If you used \with on an \item command, use it on the \list_
+ command instead (it will apply to the entire list).}
+
+\definehelp{obsolete}{
+ The command named above is obsolete in this version of ZzTeX.}
+
+\definehelp{openblock}{
+ One or more blocks are in progress at the end of a chapter,_
+ appendix, or quasichapter. The names of the blocks are listed_
+ in messages preceding this warning.__
+ The problem is caused by missing \endxxx commands. For example,_
+ you have coded a list but forgotten the \endlist command. You_
+ will probably see the message `(\end occurred inside a group at_
+ level 1)' at the end of the log.}
+
+\definehelp{overortah}{
+ The \overridetextareaheight command has been used to override the_
+ text area height, but a previous override is still in progress.__
+ If you continue from the warning, the first command will be cancelled_
+ and the second one will take effect. However, the height of the current_
+ page may be incorrect.}
+
+\definehelp{pagepar}{
+ A command has been used to request a page break in the middle of_
+ a paragraph.__
+ You must terminate the paragraph before using the command.}
+
+\definehelp{plaintex}{
+ The Plain TeX command shown below cannot be used in ZzTeX.}
+
+\definehelp{scinmath}{
+ You have tried to use a special character that is not available_
+ in math mode.__
+ If you need it, use it in a \text command.}
+
+\definehelp{setminus}{
+ When using the MathTime fonts, it is better to use \setdiff than_
+ \setminus. If you really want to use \setminus, you will need_
+ to define it in the design file.}
+
+\definehelp{spectah}{
+ The design spec's text area height, as specified by \spectextareaheight,_
+ differs from the calculated text area height by more than 3 points._
+ You should contact the designer about this.}
+
+\definehelp{skipab}{
+ A sequence of elements in the book has resulted in a request_
+ for a `skip below an element' followed immediately by a_
+ `skip above an element'. Such a sequence is invalid.__
+ There is probably an error in the design file.}
+
+\definehelp{toomanyflt}{
+ There are more than the specified number of floats pending for_
+ page makeup. A float is pending for makeup when it has been_
+ encountered in a file but not yet placed on a page of the book.__
+ You must reorganize the file so that the floats are more spread_
+ out in the text, this giving ZzTeX an opportunity to place the_
+ floats on pages as soon as they are encountered.}
+
+\definehelp{undefat}{
+ The atsign command sequence specified above has not been defined_
+ in this block. It must be defined before you can use it.__
+ Use the \defineatsigncommand command to define the command.}
+
+\definehelp{undefflt}{
+ The float type specified above has not been defined. It must be_
+ defined before you can use it.__
+ Use the \definefloattype command to define the float.}
+
+\definehelp{unimpl}{
+ The ZzTeX feature mentioned above is not yet implemented.__
+ Please contact Windfall Software if you need the feature.}
+
+\definehelp{lockedfont}{
+ The font specified above is locked, which means it was not correctly_
+ installed with ZzTFM.__
+ Please contact Windfall Software to determine a remedy.}
+
+\definehelp{varmod}{
+ A variant definition must include between 1 and 8 modifier commands.__
+ Modifier commands are specified as a comma-separated list in the third_
+ argument to \definevariant.}
+
+\definehelp{xtran}{
+ An error flag from the XTran H converter is still present in this_
+ file. The flag message is shown in the above error message.__
+ You should fix the error flagged by XTran and remove the flag_
+ message from the source file.}
+
+\definehelp{zztran}{
+ An error flag from the ZzTran converter is still present in this_
+ file. The flag message is shown in the above error message.__
+ You should fix the error flagged by ZzTran and remove the flag_
+ message from the source file.} \ No newline at end of file
diff --git a/macros/plain/contrib/zztex/tex/zzhmode.tex b/macros/plain/contrib/zztex/tex/zzhmode.tex
new file mode 100644
index 0000000000..8e9553e8ac
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzhmode.tex
@@ -0,0 +1,924 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Horizontal Mode Facilities
+%
+% Synopsis: This module provides various facilities that operate in
+% horizontal mode, within a paragraph. See also ZZHMODEB.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 21 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Starting Paragraphs
+% -------- ----------
+
+
+% The following token register is executed at the beginning of
+% every paragraph.
+
+\definetoks{\everyparagraph}
+\everyparagraph = {}
+
+% This is what we have to do at the beginning of every paragraph:
+
+\everypar = {\requiredeverypar \the\everyparagraph}
+
+% The following command ensures that we are in horizontal mode,
+% without doing anything if we already are.
+
+\def \ensurepar {\unhbox \voidbox}
+
+% The following command fakes up the start of a paragraph while
+% leaving us in vertical mode.
+
+\def \fakepar {%
+ \endgraf
+ \vspace{\parskip}%
+ \requiredeverypar}
+
+% Paragraph Penalties
+% --------- ---------
+
+
+\definecount{\zclubsv}{-100000} % Overridden \clubpenalty.
+\definecount{\zclubct}{1} % Overridden paragraph count.
+
+
+\def \overrideclubpenalty #1{% {penalty}
+ \if \eqlp{\zclubsv}{-100000}\global\zclubsv = \clubpenalty \fi
+ \global\clubpenalty = #1\relax
+ \global\zclubct = \if \vmodep -1\else 0\fi \relax}
+
+\declareeverypar{\zclubpar}
+
+\def \zclubpar {%
+ \ifnum \zclubct=0
+ \global\clubpenalty=\zclubsv
+ \global\zclubsv=-100000\relax
+ \fi
+ \global\advance \zclubct 1\relax}
+
+% Single-Character Commands
+% ---------------- --------
+
+
+% Name Description
+
+% \<space> Control space
+% \! Negative sixth space; negative thin space in math;
+% callout in code
+% \" Dieresis (umlaut) accent
+% \# Pound sign
+% \$ Dollar sign
+% \% Percent sign
+% \& Ampersand
+% \' Acute accent
+% \( (reserved
+% \) for user)
+% \* \discretionary{}{}{}
+% \+ Hair space
+% \, Sixth space; thin space in math
+% \- Discretionary hyphen
+% \. Dot accent
+% \/ Italic correction
+% \0 \phantom{0}
+% \1 -- \9 (reserved for user)
+% \: List element separator
+% \; Third space; thick space in math
+% \< (reserved for user)
+% \= Macron accent; prefix for tag namespace
+% \> (reserved for user)
+% \? (reserved for user)
+% \@ At-sign
+% \H Hungarian umlaut accent
+% \L Polish suppressed L
+% \O Scandinavian O slash
+% \P Paragraph sign (pilcrow)
+% \S Section sign
+% \[ (reserved for user)
+% \\ Backslash
+% \] (reserved for user)
+% \^ Circumflex accent
+% \_ Underscore
+% \` Grave accent
+% \b Bar-under accent
+% \c Cedilla accent
+% \d Dot-under accent
+% \g Ogonek accent
+% \h Small horizontal space
+% \i Dotless i
+% \j Dotless j
+% \l Polish suppressed l
+% \o Scandinavian o slash
+% \r ring accent
+% \t Tie-after accent
+% \u Breve accent
+% \v Hacek accent
+% \x \
+% \y } (reserved for user, for index command abbreviations)
+% \z /
+% \{ Left brace
+% \| Vertical bar; \Vert in math mode
+% \} Right brace
+% \~ Tilde accent
+
+% Characters
+% ----------
+
+
+% These definitions are in alphabetical order.
+
+\def \AA {% %~ Ring A (Angstrom). %^named_char
+ \ensurepar
+ \if \mathmodep
+ \mtext{\AA}%
+ \else
+ \r{A}%
+ \fi}
+
+\def \aa {% %~ Ring a. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \mtext{\aa}%
+ \else
+ \r{a}%
+ \fi}
+
+\chardef \AE = "1D %~ Scandinavian AE.
+
+\chardef \ae = "1A %~ Scandinavian ae.
+
+\chardef \ampersand = `\& %~ Ampersand.
+
+\let \& = \ampersand
+
+\chardef \atsign = `\@ %~ At sign.
+
+\let \@ = \atsign
+
+\def \backslash {% %~ Backslash. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmbackslash
+ \else \if \monoencodingp
+ \char "5C\relax
+ \else
+ \PSbackslash
+ \fi\fi}
+
+\let \\=\backslash
+
+\def \baselinebullet #1{% {size} %~ Bullet set on baseline.
+ \zrequiredoodad{\zdoodadfont}{#1}%
+ \hbox{\zdoodadfont .}}
+
+\def \bullet {% %~ Bullet. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmbullet
+ \else
+ \PSbullet
+ \fi}
+
+\def \cent {% %~ Cent sign. %^named_char
+ \ensurepar
+ \PScent}
+
+\let \cents = \cent
+
+\def \copyright {% %~ Copyright symbol. %^named_char
+ \ensurepar
+ \PScopyright}
+
+\def \cdquote {''} %~ Close double quote. %^named_char
+
+\def \dagger {% %~ Dagger. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmdagger
+ \else
+ \PSdagger
+ \fi}
+
+\def \ddagger {% %~ Double dagger. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmddagger
+ \else
+ \PSddagger
+ \fi}
+
+\def \dollar {% %~ Dollar sign. %^named_char
+ \zprehyph{\dollarhyph}%
+ \if \monoencodingp
+ \char "24\relax
+ \else
+ \PSdollar
+ \fi
+ \zposthyph{\dollarhyph}}
+
+\let \$ = \dollar
+
+\def \ellipsis {% %~ Text ellipsis.
+ \if \mathmodep
+ \ldots
+ \else
+ \unbreakable\thickspace
+ .\unbreakable\thickspace
+ .\unbreakable\thickspace
+ .\thickspace
+ \ignorespaces
+ \fi}
+
+\def \emdash {---} %~ Em dash. %^named_char
+
+\def \endash {--} %~ En dash. %^named_char
+
+\def \greater {% %~ Greater-than sign %^named_char
+ \ensurepar
+ \if \monoencodingp
+ \char "3E\relax
+ \else
+ \PSgreater
+ \fi}
+
+\def \>{% %~ Greater-than sign. %^named_char
+ \relax
+ \if \mathmodep \plainerror \else \greater \fi}
+
+\chardef \hash = `\# %~ Pound sign, hash, octothorpe.
+
+\let \# = \hash
+
+\def \hat {% %~ Hat symbol. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmhat
+ \else
+ \char "5E\relax
+ \fi}
+
+\chardef \i = "10 %~ Dotless i.
+
+\chardef \j = "11 %~ Dotless j.
+
+\def \L {\PSpolishL} %~ Uppercase Polish L. %^named_char
+
+\def \l {\PSpolishl} %~ Lowercase Polish l. %^named_char
+
+% \lbrace and \rbrace cannot start with \ensurepar, because that won't
+% work following a \left or \right command. However, the \relax is required.
+
+\def \lbrace {% %~ Left brace. %^named_char
+ \relax
+ \if \mathmodep
+ \zmlbrace
+ \else \if \monoencodingp
+ \char "7B\relax
+ \else
+ \PSbraceleft
+ \fi\fi}
+
+\let \{ = \lbrace
+
+\def \less {% %~ Less-than sign. %^named_char
+ \ensurepar
+ \if \monoencodingp
+ \char "3C\relax
+ \else
+ \PSless
+ \fi}
+
+\let \< = \less
+
+\chardef \O = "1F %~ Slashed O.
+
+\chardef \o = "1C %~ Slashed o.
+
+\chardef \OE = "1E %~ OE diphthong.
+
+\chardef \oe = "1B %~ oe diphthong.
+
+\def \odquote {``} %~ Open double quote. %^named_char
+
+\def \P {% %~ Paragraph symbol (pilcrow). %^named_char
+ \ensurepar
+ \PSparagraph}
+
+\chardef \percent = `\% %~ Percent sign.
+
+\let \% = \percent
+
+\def \perthousand {% %~ Per thousand symbol. %^named_char
+ \ensurepar
+ \PSperthousand}
+
+\def \prellipsis {% %~ Text ellipsis with no left space.
+ .\unbreakable\thickspace
+ .\unbreakable\thickspace
+ .\thickspace
+ \ignorespaces}
+
+\def \rbrace {% %~ Right brace. %^named_char
+ \relax
+ \if \mathmodep
+ \zmrbrace
+ \else \if \monoencodingp
+ \char "7D\relax
+ \else
+ \PSbraceright
+ \fi\fi}
+
+\let \} = \rbrace
+
+\def \registered {% %~ Registered symbol. %^named_char
+ \ensurepar
+ \PSregistered}
+
+\def \S {% %~ Section sign. %^named_char
+ \ensurepar
+ \PSsection}
+
+\def \SS {% %~ Double section sign. %^named_char
+ \ensurepar
+ \PSsection\PSsection}
+
+\chardef \ss = "19 %~ German eszett.
+
+\def \sterling {% %~ Pound sterling symbol. %^named_char
+ \ensurepar
+ \PSsterling}
+
+\def \tilde {% %~ Tilde. %^named_char
+ \ensurepar
+ \if \mathmodep
+ \zmtilde
+ \else
+ \char "7E\relax
+ \fi}
+
+\def \trademark {% %~ Trademark symbol. %^named_char
+ \ensurepar
+ \PStrademark}
+
+\def \underscore {% %~ Underscore. %^named_char
+ \ensurepar
+ \zprehyph{\underscorehyph}%
+ \if \monoencodingp
+ \char "5F\relax
+ \else
+ \PSunderscore
+ \fi
+ \zposthyph{\underscorehyph}}
+
+\let \_ = \underscore
+
+\def \udquote {% %~ Undirected double quote. %^named_char
+ \ensurepar
+ \if \monoencodingp
+ \char "22\relax
+ \else
+ \PSudquote
+ \fi}
+
+\def \usquote {% %~ Undirected single quote. %^named_char
+ \ensurepar
+ \if \monoencodingp
+ \char "0D\relax
+ \else
+ \PSusquote
+ \fi}
+
+\def \verticalbar {% %~ Vertical bar. %^named_char
+ \ensurepar
+ \if \monoencodingp
+ \char "7C\relax
+ \else
+ \PSbar
+ \fi}
+
+\def \|{% %~ Vertical bar. %^named_char
+ \relax
+ \if \mathmodep \Vert \else \verticalbar \fi}
+
+% Accents
+% -------
+
+
+\def \"#1{{\accent "7F #1}} %~ Umlaut accent. %^accent
+
+\def \'#1{{\accent 19 #1}} %~ Acute accent. %^accent
+
+\def \.#1{{\accent 95 #1}} %~ Dot accent. %^accent
+
+\def \=#1{{\accent 22 #1}} %~ Macron accent. %^accent
+
+\def \^#1{{\accent 94 #1}} %~ Circumflex accent. %^accent
+
+\def \`#1{{\accent 18 #1}} %~ Grave accent. %^accent
+
+\def \~#1{{\accent "7E #1}} %~ Tilde accent. %^accent
+
+\def \b #1{% %~ Bar-under accent. %^accent
+ \ozalign{\relax #1\cr
+ \hidewidth \vbox to .2ex {\hbox{\char 22}\vss}\hidewidth}}
+
+\def \c #1{% %~ Cedilla accent. %^accent
+ \setbox \zboxa = \hbox{#1}%
+ \if \dimeqlp{\ht\zboxa}{1ex}%
+ \accent 24 #1%
+ \else
+ {\ooalign{\hidewidth \char 24 \hidewidth \cr
+ \unhbox \zboxa}}%
+ \fi}
+
+\def \d #1{% %~ Dot-under accent. %^accent
+ \ozalign{\relax #1\cr
+ \hidewidth.\hidewidth}}
+
+\def \g #1{% %~ Ogonek accent. %^accent
+ \setbox \zboxa = \hbox{#1}%
+ \if \dimeqlp{\ht\zboxa}{1ex}%
+ \accent 154 #1%
+ \else
+ {\ooalign{\hidewidth \char 154 \hidewidth \cr
+ \unhbox \zboxa}}%
+ \fi}
+
+\def \H #1{{\accent "7D #1}} %~ Long Hungarian umlaut accent. %^accent
+
+\def \r #1{{\accent "17 #1}} %~ Ring accent. %^accent
+
+\def \t #1{% %~ Tie-after accent. %^accent
+ {\edef \znext {\the\font}\the\textfont1 \accent "7F \znext #1}}
+
+\def \u #1{{\accent 21 #1}} %~ Breve accent. %^accent
+
+\def \v #1{{\accent 20 #1}} %~ Hacek accent. %^accent
+
+% Spaces
+% ------
+
+
+% TeX space primitives include the following:
+%
+% <space> Produce a normal space, obeying \spacefactor.
+% \<space> Produce a normal space as if \spacefactor = 1000.
+
+% Here are a set of "space" commands that produce breakable space:
+
+%~ Specified amount of breakable horizontal space.
+
+\def \hspace #1{\ensurepar \hskip #1\relax}% {amount} %^hspace
+
+%~ Specified amount of unbreakable horizontal space
+%~ measured in tenths of a point.
+
+\def \h #1;{% tenths-points; %^hspace
+ {\tdimena = .1pt
+ \tdimena = #1\tdimena
+ \kern \tdimena}}
+
+\def \fiveemspace {\ensurepar \hskip 5em\relax} %~ Breakable 5 em space. %^hspace
+
+\def \fouremspace {\ensurepar \hskip 4em\relax} %~ Breakable 4 em space. %^hspace
+
+\def \threeemspace {\ensurepar \hskip 3em\relax} %~ Breakable 3 em space. %^hspace
+
+\def \twoemspace {\ensurepar \hskip 2em\relax} %~ Breakable 2 em space. %^hspace
+
+\def \emspace {\ensurepar \hskip 1em\relax} %~ Breakable 1 em space. %^hspace
+
+\def \enspace {\ensurepar \hskip .5em\relax} %~ Breakable 1 en space. %^hspace
+
+\def \digitspace {% %~ Breakable digit space. %^hspace
+ {\measuredigitwidth{\tdimena}%
+ \ensurepar \hskip \tdimena}}
+
+{\catcode`\| = \catactive
+\gdef \digitspacebar {%
+ \catcode`\| = \catactive
+ \def |{\digitspace}}
+}
+
+\def \thirdspace {\ensurepar \hskip .333em\relax} %~ Breakable 1/3 em space. %^hspace
+\let \thickspace = \thirdspace
+\def \negthickspace {\ensurepar \hskip -.333em\relax} %~ Breakable negative 1/3 em space. %^hspace
+
+\def \space { } %~ Normal space.
+\def \^^M{\ } %~ Normal space.
+
+\def \fontspace {\ensurepar \hskip \fontdimen2\font} %~ Breakable font space. %^hspace
+
+\def \visiblespace {% %~ Visible space. %^hspace
+ \ensurepar
+ \hbox {%
+ \measurespacewidth{\tdimena}%
+ \kern .16ex
+ \llap{\rule{width .08ex height .15ex depth .2ex}}%
+ \lower .2ex \hbox{\rule{width \tdimena height .08ex depth 0pt}}%
+ \rlap{\rule{width .08ex height .15ex depth .2ex}}%
+ \kern .16ex}}
+
+\def \fourthspace {\ensurepar \hskip .25em\relax} %~ Breakable 1/4 em space. %^hspace
+
+\def \fifthspace {\ensurepar \hskip .2em\relax} %~ Breakable 1/5 em space. %^hspace
+\let \thinspace = \fifthspace
+\def \negfifthspace {\ensurepar \hskip -.2em\relax} %~ Breakable negative 1/3 em space. %^hspace
+\let \negthinspace = \negfifthspace
+
+\def \sixthspace {\ensurepar \hskip .16667em\relax} %~ Breakable 1/6 em space. %^hspace
+\def \negsixthspace {\ensurepar \hskip -.16667em\relax} %~ Breakable negative 1/6 em space. %^hspace
+
+\def \seventhspace {\ensurepar \hskip .14286em\relax} %~ Breakable 1/7 em space. %^hspace
+\let \hairspace = \seventhspace
+\def \negseventhspace {\ensurepar \hskip -.14286em\relax} %~ Breakable negative 1/7 em space. %^hspace
+
+\def \qqqqquad {\unbreakable\fiveemspace} %~ Unbreakable 5 em space. %^hspace
+\def \qqqquad {\unbreakable\fouremspace} %~ Unbreakable 4 em space. %^hspace
+\def \qqquad {\unbreakable\threeemspace} %~ Unbreakable 3 em space. %^hspace
+\def \qquad {\unbreakable\twoemspace} %~ Unbreakable 2 em space. %^hspace
+\def \quad {\unbreakable\emspace} %~ Unbreakable 1 em space. %^hspace
+\def \nut {\unbreakable\enspace} %~ Unbreakable 1 en space. %^hspace
+
+%~ Unbreakable 1/3 em space.
+
+\def \;{\relax\if \mathmodep \mthickspace \else \unbreakable\thickspace \fi} %^hspace
+
+%~ Unbreakable 1/5 em space.
+
+\def \,{\relax\if \mathmodep \mthinspace \else \unbreakable\thinspace \fi} %^hspace
+
+%~ Unbreakable negative 1/5 em space.
+
+\def \!{\relax\if \mathmodep \mnegthinspace \else \unbreakable\negthinspace\fi} %^hspace
+
+\def \+{\unbreakable\hairspace} %~ Unbreakable 1/7 em space. %^hspace
+
+%~ Specified amount of unbreakable horizontal space
+%~ measured in hundredths of an em.
+
+\def \k #1;{% hundredths-em; %^hspace
+ {\tdimena = .01em
+ \tdimena = #1\tdimena
+ \kern \tdimena}}
+
+%~ This command retains horizontal space at the beginning of a line.
+%~ Such space is normally discarded.
+
+\def \retain {\vrule height 0pt depth 0pt width 0pt\relax} %^hspace
+
+%~ This declaration causes spaces to be "obeyed," so that every space
+%~ in the source is relevent.
+
+\def \obeyspaces {%
+ \catcode`\ =\catactive}
+
+{\obeyspaces
+\global\let =\ %
+}
+
+% Space Factors
+% ----- -------
+
+
+% IniTeX sets the space factor code of uppercase letters to 999 so
+% periods after them will not end sentences. That just gives people
+% one more rule to remember.
+
+ \sfcode`\A=1000 \sfcode`\B=1000 \sfcode`\C=1000 \sfcode`\D=1000
+ \sfcode`\E=1000 \sfcode`\F=1000 \sfcode`\G=1000 \sfcode`\H=1000
+ \sfcode`\I=1000 \sfcode`\J=1000 \sfcode`\K=1000 \sfcode`\L=1000
+ \sfcode`\M=1000 \sfcode`\N=1000 \sfcode`\O=1000 \sfcode`\P=1000
+ \sfcode`\Q=1000 \sfcode`\R=1000 \sfcode`\S=1000 \sfcode`\T=1000
+ \sfcode`\U=1000 \sfcode`\V=1000 \sfcode`\W=1000 \sfcode`\X=1000
+ \sfcode`\Y=1000 \sfcode`\Z=1000
+
+% A few characters should not affect the space factor.
+
+ \sfcode`\'=0
+ \sfcode`\)=0
+ \sfcode`\]=0
+
+
+\def \setsentencespacing #1{% {flag}
+ \if #1%
+ \sfcode`\. = 2250
+ \sfcode`\? = 2250
+ \sfcode`\! = 2250
+ \sfcode`\: = 2000
+ \else
+ \sfcode`\. = 1000
+ \sfcode`\? = 1000
+ \sfcode`\! = 1000
+ \sfcode`\: = 1000
+ \fi
+ \relax}
+
+% Numbers
+% -------
+
+
+\let \lcromannumeral = \romannumeral
+
+%~ This command formats an integer as uppercase Roman numerals.
+
+\def \ucromannumeral #1{% {number}
+ \uppercase\expandafter{\romannumeral#1}}
+
+%~ This command formats an integer as lowercase letters.
+
+\def \lcletter #1{% {number}
+ \ifcase #1%
+ 0\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m\or
+ n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z\else
+ \number#1\fi}
+
+%~ This command formats an integer as uppercase letters.
+
+\def \ucletter #1{% {number}
+ \ifcase #1%
+ 0\or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M\or
+ N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z\else
+ \number#1\fi}
+
+% Lines
+% -----
+
+
+\long\def \line #1{% {text}
+ \if \vmodep
+ {\parfillskip = 0pt
+ \noindent #1\retain \par}%
+ \else
+ \retain #1\tl
+ \fi}
+
+\long\def \leftline #1{\line{#1\hfil}}% {text}
+\long\def \rightline #1{\line{\hfil#1}}% {text}
+\long\def \centerline #1{\line{\hfil#1\hfil}}% {text}
+\long\def \spreadline #1#2{\line{{#1}\hfil{#2}}}% {text1}{text2}
+\long\def \centerspreadline #1#2#3{%
+ \line{\rlap{#1}\hfil #2\hfil \llap{#3}}}% {text1}{text2}{text3}
+
+
+% This declaration causes line breaks to be "obeyed," so that each
+% results in a paragraph end.
+
+{\catcode`\^^M = \catactive%
+\gdef \obeylines {\catcode`\^^M = \active \let ^^M = \par}%
+}
+
+% Line Breaks
+% ---- ------
+
+
+\def \linebreak #1{% {penalty}
+ \penalty #1\relax}
+
+\def \tl {\break}
+
+\def \nl {%
+ \gluevaries{\znlvar}{\leftskip}%
+ \if \znlvar \tl \else \hfil \break \fi}
+
+\def \blankline {\ensurepar \nl}
+
+
+% These commands are used to tie text on one line.
+
+\def ~{\nobreak \ } % Unbreakable space (tie).
+
+\def \tie {\ensurepar \hbox}
+
+% Indentation
+% -----------
+
+
+% Note that this macro just sets \leftskip and \rightskip, and so
+% blows away any \parrag.
+
+\def \setindentation #1#2{% {left}{right}
+ \leftskip = #1\relax
+ \rightskip = #2\relax}
+
+
+\def \alterindentation #1#2{% {left-delta}{right-delta}
+ \leftskip = 1\leftskip
+ \advance \leftskip by #1\relax
+ \rightskip = 1\rightskip
+ \advance \rightskip by #2\relax}
+
+% Text Width
+% ---- -----
+
+
+% This command must be used AFTER the indentation is established with
+% \setindentation or \alterindentation.
+
+\def \settextwidth #1{% {width}
+ \if \dimneqlp{#1}{\naturalwidth}%
+ \hsize = #1\relax
+ \advance \hsize by \leftskip
+ \advance \hsize by \rightskip
+ \fi}
+
+% Paragraph Raggedness
+% --------- ----------
+
+
+% This command must be used AFTER the indentation is established with
+% \setindentation or \alterindentation.
+
+\def \setparrag #1{% {rag-dimen}
+ \gluevaries{\zrsvar}{\rightskip}%
+ \if \notp{\zrsvar}%
+ \tdimena = #1\relax
+ \advance \rightskip by 0pt plus \tdimena\relax
+ \fi}
+
+\zdeclareeveryvcontext{\setindentation{0pt}{0pt}\setparrag{0pt}}
+
+% Paragraph Shapes
+% --------- ------
+
+
+\definecount{\zshparct}{0}
+\definecount{\zshparrep}{0}
+\definedimen{\zshpari}{0pt}
+\definedimen{\zshparw}{0pt}
+
+
+\def \nshapepar #1{% {[*repeat1,]indent1,width1,...}
+ \if \emptyargp{#1}%
+ \error{empshape}{The argument to \string\shapepar cannot be empty}%
+ \fi
+ \gdef \zshpartoks {}%
+ \global\zshparct = 0
+ {\zshapeparc #1,\zmark}%
+ \parshape = \zshparct\zshpartoks\relax}
+
+\def \zshapeparc #1#2,#3\zmark{% [*repeat],indent,...
+ \if \codeeqlp{#1}{*}%
+ \global\zshparrep = #2\relax
+ \def \znext {\zshapepare #3\zmark}%
+ \else
+ \global\zshparrep = 1
+ \def \znext {\zshapepare #1#2,#3\zmark}%
+ \fi
+ \znext}
+
+\def \zshapepare #1,#2,#3\zmark{% indent,width,...
+ \zshapepard #1,\false,\zshpari\zmark
+ \global\zshpari = \tdimena
+ \zshapepard #2,\true,\zshparw\zmark
+ \global\zshparw = \tdimena
+ \loop
+ \if \posp{\zshparrep}%
+ \xdef \zshpartoks {\zshpartoks \space \the\zshpari \space \the\zshparw}%
+ \global\increment \zshparct
+ \global\decrement \zshparrep
+ \repeat
+ \if \emptyargp{#3}%
+ \let \znext = \relax
+ \else
+ \def \znext {\zshapeparc #3\zmark}%
+ \fi
+ \znext}
+
+\def \zshapepard #1#2,#3,#4\zmark{% dimen1 dimen-rest,width?,prev
+ \if \codeeqlp{#1}{+}%
+ \calculate \tdimena = {#4,+,#2}%
+ \else\if \codeeqlp{#1}{-}%
+ \calculate \tdimena = {#4,-,#2}%
+ \else\if \andp{\codeeqlp{#1}{=}}{#3}%
+ \calculate \tdimena = {\hsize,-,\zshpari}%
+ \else
+ \tdimena = #1#2\relax
+ \if \dimeqlp{\tdimena}{\naturalwidth}%
+ \calculate \tdimena = {\hsize,-,\zshpari}%
+ \fi
+ \fi\fi\fi
+ \if #3%
+ %%% Do we want to adjust the width by \leftskip or \rightskip?
+ \fi}
+
+
+%%%\definecount{\zshparct}{0}
+\definedimen{\zshpard}{0pt}
+\definedimen{\zshpare}{0pt}
+
+
+\def \shapepar #1{% {indent1,width1,...}
+ \if \emptyargp{#1}%
+ \error{empshape}{The argument to \string\shapepar cannot be empty}%
+ \fi
+ \gdef \zshpartoks {}%
+ \global\zshparct = 0
+ {\zshapepara #1,\zmark}%
+ \parshape = \zshparct\zshpartoks\relax}
+
+\def \zshapepara #1,#2,#3\zmark{% indent,width,...\zmark
+ \zshpard = #1\relax
+ \xdef \zshpartoks {\zshpartoks \space \the\zshpard}%
+ \zshpare = #2\relax
+ \if \dimeqlp{\zshpare}{\naturalwidth}%
+ \zshpare = \hsize
+ \advance \zshpare by -\zshpard
+ \else
+ \advance \zshpare by \leftskip
+ \advance \zshpare by \rightskip
+ \fi
+ \xdef \zshpartoks {\zshpartoks \space \the\zshpare}%
+ \global\increment \zshparct
+ \if \emptyargp{#3}%
+ \let \znext = \relax
+ \else
+ \def \znext {\zshapepara #3\zmark}%
+ \fi
+ \znext}
+
+
+\def \hangalign #1#2#3{% {indent}{text1}{text2}
+ \endgraf
+ {\setbox \zboxa = \hbox{#2}%
+ \tdimena = \wd\zboxa
+ \advance \tdimena by #1\relax
+ \shapepar{#1,\naturalwidth,\tdimena,\naturalwidth}%
+ \noindent \box\zboxa #3\par}}
+
+\def \hindent #1{% {indent}
+ \noindent \hspace{#1}%
+ \ignorespaces}
+
+% Adjustments
+% -----------
+
+
+%~ This page overrides the number of lines in a paragraph. The argument
+%~ specifies the number of lines and should start with a plus or
+%~ minus sign. TeX does not guarantee the change.
+
+\def \overrideparlength #1{% {lines} %^page_makeup
+ \looseness = #1\relax}
+
+
+%~ This command is used in the middle of a paragraph, on a line by
+%~ itself, to make an adjustment
+%~ between two lines. A typical use is to force a page break:
+%~ \adjustpar{\fullpagebreak}
+%~ There is no need to put a percent sign (|%|) after the command.
+
+\long\def \adjustpar #1{% {command} %^page_makeup
+ \vadjust{#1}%
+ \ignorespaces}
+
+
+% This command is used to adjust the title of a chapter, section, etc.
+% The argument looks like `\loc{commands}\loc{commands}...'
+% where each \loc is:
+% \body To adjust the title in the body of the text.
+% \mark To adjust the title in the mark (running heads and feet).
+% \toc To adjust the title in the table of contents.
+
+\def \zadjloc {\body} % Normally, \adjusttitle should adjust body.
+
+\def \adjusttitle #1{% {\loc{commands}...}
+ {\def \body ##1{}%
+ \def \mark ##1{}%
+ \def \toc ##1{}%
+ \expandafter\let \zadjloc = \zadjtitleb
+ #1}}
+
+\def \zadjtitleb #1{%
+ #1%
+ \def \znext {#1}%
+ \if \tokeqlp{\znext}{\nl}%
+ \let \znext = \ignorespaces
+ \else
+ \let \znext = \relax
+ \fi
+ \znext}
+
+% These macros use \lspspace so they do the right thing while letterspacing.
+
+\def \titlenl {\adjusttitle{\body{\nl}}\lspspace}
+\def \titletl {\adjusttitle{\body{\tl}}\lspspace}
+\def \tocnl {\adjusttitle{\toc{\nl}}\lspspace}
+\def \toctl {\adjusttitle{\toc{\tl}}\lspspace}
+
+
+% These definitions are used by the new title adjustment scheme,
+% but need to be present even when it is not in use.
+
+\chardef \zadjtitlenone = 0
+\chardef \zadjtitlebody = 1
+\chardef \zadjtitlemark = 2
+\chardef \zadjtitletoc = 3
+\chardef \zadjtitleminitoc = 4
+
+\definecount{\zadjtitle}{\zadjtitlebody}
diff --git a/macros/plain/contrib/zztex/tex/zzhmodeb.tex b/macros/plain/contrib/zztex/tex/zzhmodeb.tex
new file mode 100644
index 0000000000..69c92d9c1e
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzhmodeb.tex
@@ -0,0 +1,239 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Horizontal Mode Facilities
+%
+% Synopsis: This module provides various facilities that operate in
+% horizontal mode, within a paragraph. See also ZZHMODE.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 11 January 1994
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Basic Tools
+% ----- -----
+
+
+\def \llap #1{\hbox to 0pt{\hss #1}}% {text}
+\def \rlap #1{\hbox to 0pt{#1\hss}}% {text}
+\def \clap #1{\hbox to 0pt{\hss #1\hss}}% {text}
+
+\def \minhbox to #1#2#3#4{% to width{text}{space-in}{space-out}
+ \measuretextwidth{\tdimena}{#2\hspace{#3}}%
+ \if \dimgtrp{\tdimena}{#1}%
+ {#2}\hspace{#4}%
+ \else
+ \hbox to #1{#2\hfil}%
+ \fi}
+
+% Drop Capitals
+% ---- --------
+
+
+\def \dropcapital #1#2#3{% {height}{lines}{text}
+ \setbox \zboxa = \hbox{#3}%
+ \tdimena = \ht\zboxa
+ \advance \tdimena by -#1\relax
+ \setbox \zboxa = \hbox{\lower \tdimena \box\zboxa}%
+ \dp\zboxa = 0pt
+ \def \zdropshape {0pt,\naturalwidth}%
+ \tcounta = #2\relax
+ \loop
+ \decrement \tcounta
+ \if \posp{\tcounta}%
+ \edef \zdropshape {\zdropshape ,\the\wd\zboxa,\naturalwidth}%
+ \repeat
+ \expandafter\shapepar\expandafter{\zdropshape,0pt,\naturalwidth}%
+ \noindent \box\zboxa}
+
+% Enclosing Text
+% --------- ----
+
+
+\def \enclose #1#2#3{% {thickness}{separation}{text}
+ \ensurepar
+ \hbox{\vrule width #1%
+ \vtop{\vbox{\hrule height #1%
+ \kern #2%
+ \hbox{\kern #2#3\kern #2}}%
+ \kern #2%
+ \hrule height #1}%
+ \vrule width #1}}
+
+\def \colorenclose #1#2#3#4{% {color}{thickness}{separation}{text}
+ \ensurepar
+ \hbox{\color{#1}\vrule width #2 \endcolor
+ \vtop{\vbox{\color{#1}\hrule height #2 \endcolor
+ \kern #3%
+ \hbox{\kern #3#4\kern #3}}%
+ \kern #3%
+ \color{#1}\hrule height #2 \endcolor}%
+ \color{#1}\vrule width #2 \endcolor}}
+
+% Fractions
+% ---------
+
+
+% This macro is specifically designed to work in math mode, too.
+
+\def \piecefraction #1{%
+ \ztfrac #1/}
+
+\def \ztfrac #1/#2/{%
+ \ensurepar
+ {\measuretextwidth{\tdimena}{/}%
+ \raise .5ex \hbox{$\scriptstyle #1$}%
+ \kern -.2\tdimena \raise .3ex \hbox{$\scriptstyle /$}\kern -.2\tdimena%
+ \hbox{$\scriptstyle #2$}}}
+
+\let \textfraction = \piecefraction % For compatibility.
+
+% Leaders
+% -------
+
+
+\def \alignedleaders #1{% {box-or-rule}
+ \leaders #1\hfill}
+
+\def \dotleaders {%
+ \alignedleaders{\hbox to 1em{\hss.\hss}}}
+
+\def \ruleleaders #1{% {rule}
+ \alignedleaders{#1}}
+
+\def \centeredleaders #1{% {box-or-rule}
+ \cleaders #1\hfill}
+
+\def \spreadleaders #1{% {box-or-rule}
+ \xleaders #1\hfill}
+
+% Paragraph Dingbats
+% --------- --------
+
+
+\def \pardingbat #1#2{% {space}{dingbat}
+ {\unskip \unbreakable\hfil \allowbreak
+ \hspace{#1}\retain\unbreakable\hfill
+ #2%
+ \finalhyphendemerits = 0 \par}}
+
+% Rules
+% -----
+
+
+\def \rule #1{% {dimensions}
+ \if \vmodep
+ \hrule #1\relax
+ \else
+ \vrule #1\relax
+ \fi}
+
+\def \colorrule #1#2{% {color}{dimensions}
+ \if \vmodep
+ \color{#1}
+ \nobreak
+ \hrule #2\relax
+ \endcolor
+ \else
+ \color{#1}\vrule #2\relax\endcolor
+ \fi}
+
+\def \slug #1#2{% {width}{height}
+ \rule{height #2 depth 0pt width #1}}
+
+% Shapes
+% ------
+
+
+\def \rectangle #1#2#3#4{% {rise}{width}{height}{thickness}
+ {\tdimena = #2\relax
+ \advance \tdimena by -#4\relax
+ \advance \tdimena by -#4\relax
+ \raise #1 \hbox{%
+ \vrule height #3 depth 0pt width #4\relax
+ \vbox to #3{%
+ \hrule height #4 depth 0pt width \tdimena\relax
+ \vfil
+ \hrule height #4 depth 0pt width \tdimena\relax}%
+ \vrule height #3 depth 0pt width #4}}}
+
+% Underlining & Overstriking
+% ----------- - ------------
+
+
+\def \fakebold #1{% {text}
+ \hbox{\rlap{#1}%
+ \rlap{\lower .009em \hbox{\kern .009em #1}}%
+ \lower .018em \hbox{\kern .018em #1}}}
+
+\def \multiunderline #1#2#3#4#5{% {count}{drop1}{drop2}{thickness}{text}
+ \ensurepar
+ {\setbox\zboxa = \hbox{#5}%
+ \rlap{\lower #2 \hbox{\vrule height #4 depth 0pt width \the\wd\zboxa}}%
+ \tcounta = #1\relax
+ \tdimena = #2\relax
+ \loop
+ \decrement \tcounta
+ \if \posp{\tcounta}%
+ \advance \tdimena by #3\relax
+ \rlap{\lower \tdimena \hbox{\vrule height #4 depth 0pt
+ width \the\wd\zboxa}}%
+ \repeat
+ \box\zboxa}}
+
+\def \overstrike #1#2{% {text1}{text2}
+ \ensurepar
+ {\setbox\zboxa = \hbox{#1}%
+ \setbox\zboxb = \hbox{#2}%
+ \tdimena = \wd\zboxa
+ \advance \tdimena by -\wd\zboxb
+ \divide \tdimena by 2
+ \rlap{\kern \tdimena \box\zboxb}\box\zboxa}}
+
+\def \strikethrough #1{% {text}
+ \ensurepar
+ {\setbox\zboxa = \hbox{#1}%
+ \rlap{\raise .45ex \hbox{\vrule height .1ex depth 0pt
+ width \the\wd\zboxa}}%
+ \box\zboxa}}
+
+\let \zunline = \underline
+
+\def \underline #1{% {text}
+ \relax
+ \if \mathmodep
+ \zunline{#1}%
+ \else
+ \multiunderline{1}{.4ex}{0pt}{.1ex}{#1}%
+ \fi}
+
+% Vertical Centering
+% -------- ---------
+
+
+\def \centeroncapheight #1{% {text}
+ \ensurepar
+ {\setbox\zboxa = \hbox{#1}%
+ \measurecapheight{\tdimena}% % Calculate ht(CAP) - ht(text)
+ \advance \tdimena by -\ht\zboxa % ------------------
+ \divide \tdimena by 2 % 2
+ \raise \tdimena \box\zboxa}}
+
+\def \centerondigitheight #1{% {text}
+ \ensurepar
+ {\setbox\zboxa = \hbox{#1}%
+ \measuredigitheight{\tdimena}% % Calculate ht(123) - ht(text)
+ \advance \tdimena by -\ht\zboxa % ------------------
+ \divide \tdimena by 2 % 2
+ \raise \tdimena \box\zboxa}}
+
+\def \centeronxheight #1{% {text}
+ \ensurepar
+ {\setbox\zboxa = \hbox{#1}%
+ \tdimena = 1ex % Calculate 1ex - ht(text)
+ \advance \tdimena by -\ht\zboxa % --------------
+ \divide \tdimena by 2 % 2
+ \raise \tdimena \box\zboxa}}
diff --git a/macros/plain/contrib/zztex/tex/zzhyper.tex b/macros/plain/contrib/zztex/tex/zzhyper.tex
new file mode 100644
index 0000000000..cf20d36eb2
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzhyper.tex
@@ -0,0 +1,185 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: PDF Hyperlink Facility
+%
+% Synopsis: This module provides facilities for creating PDF hyperlinks
+% in the document.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 12 March 2014
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Control Hyperlinking
+% ------- ------------
+
+
+% If hyperlinking is turned off, then we also clear the button color.
+
+\def \setPDFhyperlinks #1{%
+ \global\setflag \PDFhyperlinks = #1\relax
+ \if \notp{#1}\PDFbuttoncolor = {}\fi}
+
+% Hyperlink Marks
+% --------- -----
+
+
+% This macro generates a hyperlink mark that can be used as the target
+% of a button.
+
+\def \PDFmark #1{%
+ \if \PDFhyperlinks
+ \special{mark: #1}%
+ \if \vmodep \repeatpenalty \fi % In case glue follows \special.
+ \fi}
+
+% Hyperlink Buttons
+% --------- -------
+
+
+\def \pagebutton #1#2{% {folio}{text}
+ \if \PDFhyperlinks
+ \ztextbutton{P:#1}{#2}%
+ \if \emptytoksp{\PDFbuttoncolor}%
+ #2%
+ \else
+ \colortext{\the\PDFbuttoncolor}{#2}%
+ \fi
+ \else
+ #2%
+ \fi}
+
+\def \tagbutton #1#2{% {tag}{text}
+ \if \PDFhyperlinks
+ \ztextbutton{T:#1}{#2}%
+ \if \emptytoksp{\PDFbuttoncolor}%
+ #2%
+ \else
+ \colortext{\the\PDFbuttoncolor}{#2}%
+ \fi
+ \else
+ #2%
+ \fi}
+
+\def \URLbutton #1#2{% {URL}{text}
+ \if \PDFhyperlinks
+ \ztextbutton{#1}{#2}%
+ \if \emptytoksp{\PDFbuttoncolor}%
+ #2%
+ \else
+ \colortext{\the\PDFbuttoncolor}{#2}%
+ \fi
+ \else
+ #2%
+ \fi}
+
+\def \colorbuttontext {%
+ \if \andp{\PDFhyperlinks}{\notp{\emptytoksp{\PDFbuttoncolor}}}%
+ \color{\the\PDFbuttoncolor}%
+ \fi}
+
+\def \endcolorbuttontext {%
+ \if \andp{\PDFhyperlinks}{\notp{\emptytoksp{\PDFbuttoncolor}}}%
+ \endcolor
+ \fi}
+
+% Low-Level Button Macros
+% --------- ------ ------
+
+
+% These low-level macros do not check \PDFhyperlinks.
+
+
+\def \ztextbutton #1#2{% {mark}{text}
+ \measuretextwidth{\tdimena}{#2}%
+ \zwidthbutton{#1}{\tdimena}}
+
+\def \zwidthbutton #1#2{% {mark}{width-expr}
+ \calculate \tdimena = {#2}%
+ \if \hmodep
+ \smash{\lower .5ex \hbox{%
+ \special{button: \number\tdimena\space
+ \number\normalbaselineskip\space #1}}}%
+ \else
+ \special{button: \number\tdimena\space
+ \number\normalbaselineskip\space #1}%
+ \fi}
+
+\def \zURLbutton #1#2{% {url}{text}
+ \measuretextwidth{\tdimena}{#2}%
+ \def \zurltext {#1}%
+ \smash{\lower .5ex \hbox{%
+ \special{button: \number\tdimena\space
+ \number\normalbaselineskip\space
+ \expandafter\zdefof \meaning\zurltext\zmark}}}}
+
+% Email Addresses and URLs
+% ----- --------- --- ----
+
+
+\def \zurlprefix {}
+
+
+\def \urltext #1#2{% {font}{break before .?}{url}
+ \bgroup
+ #1%
+ \setflag \zurldotbreak = #2%
+ \catcode `\& = \catactive
+ \catcode `\. = \catactive
+ \catcode `\/ = \catactive
+ \catcode `\@ = \catactive
+ \catcode `\_ = \catactive
+ \zurltexta}
+
+\def \zurltexta #1{% {url}
+ \zurltextb #1\-\-\zmark}
+
+\def \zurltextb #1\-#2\-#3\zmark{% part1\-part2\-part3\zmark
+ \expandafter\def \expandafter\zfullurl \expandafter{\zurlprefix #1#2}%
+ \zurltextc{#1}%
+ \if \notp{\emptyargp{#2}}%
+ \break
+ \zurltextc{#2#3}%
+ \fi
+ \egroup
+ \gdef \zurlprefix {}}
+
+{\catcode `\& = \catactive
+ \catcode `\. = \catactive
+ \catcode `\/ = \catactive
+ \catcode `\@ = \catactive
+ \catcode `\_ = \catactive
+
+\gdef \zurltextc #1{% {url-text}
+ \def &{\ampersand \discretionary{}{}{}}% % Break after &
+ \let \& = &%
+ \if \zurldotbreak
+ \def .{\discretionary{}{}{}\char"2E }% % Break before .
+ \else
+ \def .{\char"2E \discretionary{}{}{}}% % Break after .
+ \fi
+ \def /{\char"2F \discretionary{}{}{}}% % Break after /
+ \def @{\atsign \discretionary{}{}{}}% % Break after @
+ \let \@ = @%
+ \let _ = \underscore % Set _
+ \let ~ = \tilde % Set ~
+ \def \-{\discretionary{}{}{}}% % No hyphenation
+ \if \PDFhyperlinks
+ \expandafter\zURLbutton \expandafter{\zfullurl}{#1}%
+ \fi
+ \colorbuttontext
+ #1%
+ \endcolorbuttontext}
+
+} % \catcode
+
+% Digital Object Identifiers
+% ------- ------ -----------
+
+
+\def \DOI {% {number}
+ \def \zurlprefix {http://dx.doi.org/}%
+ \ensurepar \url}
diff --git a/macros/plain/contrib/zztex/tex/zzhyph.tex b/macros/plain/contrib/zztex/tex/zzhyph.tex
new file mode 100644
index 0000000000..1aea8d1cd8
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzhyph.tex
@@ -0,0 +1,128 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Hyphenation Facilities
+%
+% Synopsis: This module provides the extra facilities for dealing with
+% hyphenation and related matters.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 6 October 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Hyphenating Words
+% ----------- -----
+
+
+\def \*{%
+ \discretionary{}{}{}}
+
+\def \hyphen{%
+ \nobreak -\zposthyph{2}}
+
+\def \slash {/\zposthyph{1}}
+
+
+% These macros are used in ZZHMODE to allow special characters to hyphenate.
+
+\def \zprehyph #1{% {\parameter}
+ \ifcase #1%
+ \relax
+ \or
+ \relax
+ \else
+ \nobreak
+ \fi}
+
+\def \zposthyph #1{% {\parameter}
+ \ifcase #1%
+ \relax
+ \or
+ \discretionary{}{}{}%
+ \else
+ \penalty \exhyphenpenalty \hskip 0pt\relax
+ \fi}
+
+% Displaying Hyphens
+% ---------- -------
+
+
+\def \showhyphens #1{%
+ \setbox\zboxa = \vbox{%
+ \hsize = \maxdimen
+ \parfillskip = 0pt
+ \pretolerance = -1
+ \tolerance = -1
+ \hbadness = 0pt
+ \showboxdepth = 0
+ \ #1}}
+
+% Hyphenation Exceptions
+% ----------- ----------
+
+
+\hyphenation{%
+ acad-e-my a-mi-no anag-no-sto-pou-los
+ an-a-lyse an-a-lysed an-a-lys-es
+ an-a-lys-ing analy-ses analy-sis a-no-ny-mi-ty
+ ap-pen-dix apple ap-pli-ca-tion ar-chive ar-chiv-ing ar-chiv-ist
+ arity aspect assume asyn-chro-nous asyn-chro-nous-ly
+ au-to-mat-ic au-to-ma-tion au-ton-o-mous
+ back-gam-mon berth-ing bio-che-mist bio-che-mists bio-med-i-cine
+ bio-poly-mer bio-poly-mers bit-map book-reader brows-ers
+ buff-er buff-er-ed buff-er-ing
+ cat-a-stroph-ic chi-ca-go ci-gar cig-a-rette cig-a-rettes
+ co-in-cide co-in-cides
+ co-iso-tro-pic col-umns com-pen-dium cor-vette cor-vettes
+ cross-over crypto-sys-tem crypto-sys-tems cur-vi-linear cy-to-cha-la-sin
+ data-base data-bases data-set data-sets date-stamp de-mon-strate de-mon-strates
+ der-i-va-tion dijk-stra di-lem-ma dis-tinc-tive
+ dump-ling dump-lings
+ eco-nom-ic eco-nom-ics econ-o-mies e-con-o-mist e-con-o-mists ec-ua-dor
+ ei-gen-space ei-gen-spaces elec-tro-dif-fu-sion en-gland
+ en-tre-pre-neur en-tre-pre-neurs en-tre-pre-neur-ship
+ e-pis-te-mol-o-gy e-pis-te-mo-log-i-cal
+ fashion fi-bo-nac-ci frame-work
+ geo-graph-ic ge-om-e-try geo-stro-phic graph-ics
+ he-mo-glo-bin hexa-dec-i-mal horse-rad-ish
+ ide-ol-o-gy ide-ol-o-gies ide-ol-o-gize idiom im-ped-ance im-plic-it
+ keynes-ian
+ leaf-lets li-chen life-style light-weight li-quid-i-ty li-thog-ra-phy lon-gi-tu-di-nal
+ look-ahead
+ ma-caque
+ mac-ro-eco-nom-ic mac-ro-eco-nom-ics mac-ro-eco-nom-ist mac-ro-eco-nom-ists
+ mac-ro-mol-e-cule mac-ro-mol-e-cules
+ man-u-script man-u-scripts mar-gin-al mas-sa-chu-setts
+ me-chan-i-cal me-di-um me-di-ter-ra-ne-an meta-bolic me-tab-o-lism
+ meta-lin-guis-tic met-a-phor met-a-phors met-a-phor-ic met-a-phor-i-cal
+ meth-od-ol-o-gy
+ mic-ro-eco-nom-ic mic-ro-eco-nom-ics mic-ro-eco-nom-ist mic-ro-eco-nom-ists
+ mini-tab mne-mon-ic meth-od-o-log-i-cal mol-ecule mol-ecules
+ mono-chrome mono-pole mono-poles mo-nop-o-ly
+ mono-sac-cha-rides mul-ti-pli-ca-tion mul-ti-pli-ca-tive
+ name-space noisi-ness noisy none-the-less not-with-stand-ing
+ often ol-i-gop-o-ly ol-i-gop-o-list-ic olym-pi-ad olym-pi-ads
+ om-e-lette om-e-lettes
+ op-er-and op-er-ands oper-ator over-view
+ paper pa-rab-o-la par-a-digm para-mag-ne-tic pa-ram-e-trized
+ patho-gen patho-gen-ic patho-gens people pe-ri-od per-suad-ed per-suad-ing
+ phoe-nix pho-neme pho-to-graphs pho-to-mi-cro-graph phys-i-co-chem-i-cal
+ phys-ics piano pic-to-graph pic-to-graph pic-to-graph-ic poly-sac-cha-rides
+ Post-Script pov-er-ty pow-er prayer pre-dimmed pref-er-a-ble pref-er-a-bly
+ pri-meval pro-cess pro-ces-sor pro-cure-ment
+ pro-gram-ma-ble prop-o-si-tion py-thag-o-re-an
+ qua-drat-ic qua-lia
+ ra-tional real-ly rec-tan-gu-lar re-pack-age re-pack-aged rep-er-toire
+ re-start re-start-ed re-start-able
+ sa-li-ent sched-ul-ing sche-nec-ta-dy scoun-drel scoun-drels ser-geant ser-geants
+ sha-pir-o small-talk so-lo-ist spec-tros-co-py stag-horn ste-reo-spe-cif-ic
+ sto-chas-tic syn-chro-nous syn-chro-nous-ly
+ table tem-po-rar-ily theo-rem time-stamp time-stamps to-ma-to
+ un-pre-dict-able uti-li-za-tion
+ water wave-guide wave-guides weap-on weap-ons which-ever white-space wild-life
+ woman women woman-kind
+ xe-rog-ra-phy
+}
diff --git a/macros/plain/contrib/zztex/tex/zzindexv1.tex b/macros/plain/contrib/zztex/tex/zzindexv1.tex
new file mode 100644
index 0000000000..c809d20c9f
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzindexv1.tex
@@ -0,0 +1,379 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Indexing Facilities, version 1
+%
+% Synopsis: This file contains the tools for producing an index.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 20 May 2006
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Index Version
+% ----- -------
+
+
+\def \indexversion #1{%
+ \input zzindexv#1\relax}
+
+% Define Index Locator Types
+% ------ ----- ------- -----
+
+
+% This list contains the definition of each locator. New ones must be
+% added to the end, and any program looking at the definitions must assume
+% that duplicates may exist, and that the last one prevails.
+
+\def \zixloclist {}
+
+
+%~ This command is deprecated in favor of |\definelocator|.
+
+\def \definelocatortype #1#2#3#4#5#6{% {name}{attributes}{precedence}
+ % {beginning-punc}{templates}
+ % {ending-punc}
+ {\setflag \pg = \true
+ \let \page = \relax
+ \def \nopage {\setflag \pg = \false}%
+ \setflag \txt = \false
+ \def \text {\setflag \txt = \true}%
+ \let \notext = \relax
+ #2%
+ \def \bpunc {#4}%
+ \def \temp {#5}%
+ \def \epunc {#6}%
+ \edef \znext {%
+ \noexpand\append{{#1}{\pg}{\txt}{#3}%
+ {\expandafter\zdefof \meaning\bpunc\zmark}%
+ {\expandafter\zdefof \meaning\temp\zmark}%
+ {\expandafter\zdefof \meaning\epunc\zmark}}}%
+ \znext{\zixloclist}%
+ \if \txt
+ \withname\gdef{\x#1}##1##2{\zixindex{#1}{##1}{S}{##2}}%
+ \if \pg
+ \withname\gdef{\x#1begin}##1##2{\zixindex{#1}{##1}{B}{##2}}%
+ \withname\gdef{\x#1end}##1##2{\zixindex{#1}{##1}{E}{##2}}%
+ \fi
+ \else
+ \withname\gdef{\x#1}##1{\zixindex{#1}{##1}{S}{}}%
+ \if \pg
+ \withname\gdef{\x#1begin}##1{\zixindex{#1}{##1}{B}{}}%
+ \withname\gdef{\x#1end}##1{\zixindex{#1}{##1}{E}{}}%
+ \fi
+ \fi}}
+
+
+% This command is deprecated.
+
+\def \defineindexlocator #1#2#3#4#5#6{% {name}{attributes}{precedence}
+ % {punctuation}{single-template}
+ % {range-template}
+}
+
+% Builtin Locator Types
+% ------- ------- -----
+
+
+% Precedences 0--1 and 6--9 are reserved for specific books.
+
+\definelocatortype{term}{\page\notext}{2.3}
+ {, |}{\bold{~P}|\bold{~P--~Q}|, }{. |}
+\definelocatortype{biblio}{\page\notext}{2.5}
+ {, |}{~P|~P--~Q|, }{. |}
+\definelocatortype{cite}{\page\notext}{2.5}
+ {, |}{~P|~P--~Q|, }{. |}
+\definelocatortype{page}{\page\notext}{2.5}
+ {, |}{~P|~P--~Q|, }{. |}
+\definelocatortype{figure}{\page\notext}{2.7}
+ {, |}{~P\+\emph{f}|~P--~Q\+\emph{f}|, }{. |}
+\definelocatortype{glossary}{\page\notext}{2.7}
+ {, |}{~P\+\emph{g}|~P--~Q\+\emph{g}|, }{. |}
+\definelocatortype{note}{\page\notext}{2.8}
+ {, |}{~P\+\emph{n}|~P--~Q\+\emph{n}|, }{. |}
+\definelocatortype{sidebar}{\page\notext}{2.7}
+ {, |}{~P\+\emph{s}|~P--~Q\+\emph{s}|, }{. |}
+\definelocatortype{table}{\page\notext}{2.7}
+ {, |}{~P\+\emph{t}|~P--~Q\+\emph{t}|, }{. |}
+\definelocatortype{see}{\nopage\text}{3}
+ {. |\See\ }{~T||; }{. |}
+\definelocatortype{seealso}{\nopage\text}{4}
+ {. |\Seealso\ }{~T||; }{. |}
+\definelocatortype{consult}{\nopage\text}{5}
+ {. |\Consult\ }{~T||; }{. |}
+
+% Index Preparation File
+% ----- ----------- ----
+
+
+% The \produceindex command must appear before the \document command.
+
+\setflag \zindexing = \false
+
+
+\def \produceindex #1#2{% {type}{prep-file}
+ {\processdesign{\index}{#1}%
+ \immediate\openout \zwritea = #2.zzh\relax
+ \immediate\write \zwritea {root \jobname}%
+ \immediate\write \zwritea {type #1}%
+ \immediate\write \zwritea {divisions {\the\divisions}}%
+ \immediate\write \zwritea {locators {\the\locators}}%
+ \immediate\write \zwritea {\the\indexparams}%
+ \maplist{\immediate\write \zwritea {define-locator ##1}}{\zixloclist}%
+ \immediate\closeout \zwritea}%
+ \global\setflag \zindexing = \true}
+
+% Index File Handling
+% ----- ---- --------
+
+\definewrite{\zixrootfile}
+\definewrite{\zixdivfile}
+\setflag \zixdivopen = \false
+
+
+\def \zindexinit {%
+ \if \zindexing
+ \immediate\openout \zixrootfile = \jobname.zzi\relax
+ \immediate\write \zixrootfile
+ {\zcomment Raw index entry file for book `\jobname'.}%
+ \fi}
+
+\def \zindexfinal {%
+ \if \zindexing
+ \immediate\write \zixrootfile {\zcomment [end]}%
+ \immediate\closeout \zixrootfile
+ \fi}
+
+\def \zindexdivinit #1{% {division}
+ \if \zindexing
+ \immediate\openout \zixdivfile = #1.zzi\relax
+ \immediate\write \zixdivfile
+ {\zcomment Raw index entry file for book `\jobname', division `#1'.}%
+ \global\setflag \zixdivopen = \true
+ \fi}
+
+\def \zindexdivfinal {%
+ \if \zixdivopen
+ \immediate\write \zixdivfile {\zcomment [end]}%
+ \immediate\closeout \zixdivfile
+ \global\setflag \zixdivopen = \false
+ \fi}
+
+% Generate Index Entry
+% -------- ----- -----
+
+
+% This macro is called from the indexing macros generated by
+% \definelocatortype.
+
+\def \zixindex #1#2#3#4{% {locator}{level}{page-code}{text}
+ \tcounta = #2\relax
+ \if \notp{\rangep{\tcounta}{1}{3}}%
+ \error{invindexlvl}{Invalid index level '#2' specified}%
+ \tcounta = 1
+ \fi
+ \name{\zixindex\romannumeral\tcounta}{#1}{#2}{#3}{#4}}
+
+\def \zixindexi #1#2#3#4#5{%
+ \zixindexw{#1}{#2}{#3}{#4}{#5}{}{}{\noexpand\folio}}
+\def \zixindexii #1#2#3#4#5#6{%
+ \zixindexw{#1}{#2}{#3}{#4}{#5}{#6}{}{\noexpand\folio}}
+\def \zixindexiii #1#2#3#4#5#6#7{%
+ \zixindexw{#1}{#2}{#3}{#4}{#5}{#6}{#7}{\noexpand\folio}}
+
+\catcode"B8 = \catother
+
+\gdef \zixindexw #1#2#3#4#5#6#7#8{% {locator}{level}{page-code}{text}
+ % {heading1}{heading2}{heading3}{page}
+ \if \notp{\zindexing}%
+ \warning{notindexing}{An indexing command was encountered,
+ but no \string\produceindex}%
+ \fi
+ \zbeginhidewrite
+ \def \zhdx {#5}%
+ \def \zhdy {#6}%
+ \def \zhdz {#7}%
+ \def \ztxt {#4}%
+ \edef \znext {#1^^b8%
+ #2^^b8%
+ \expandafter\zdefof \meaning\zhdx\zmark^^b8%
+ \expandafter\zdefof \meaning\zhdy\zmark^^b8%
+ \expandafter\zdefof \meaning\zhdz\zmark^^b8%
+ #3^^b8%
+ #8^^b8%
+ \expandafter\zdefof \meaning\ztxt\zmark}%
+ \write \if \zixdivopen \zixdivfile \else \zixrootfile \fi
+ \expandafter{\znext}%
+ \if \vmodep \repeatpenalty \fi % In case glue follows write.
+ \zendhidewrite}
+
+\catcode"B8 = \catinvalid
+
+% Discussion of Index Formatting
+% ---------- -- ----- ----------
+
+
+% An index is formatted inside an index block, which is more or less
+% like a text block. Within the index block are occurences of the
+% \indexentry macro, one for each entry. In addition, the
+% \alphabreak macro can be used to produce breaks preceding the `A'
+% entries, `B' entries, etc.
+%
+% In an index block, parts 4 and 5 of the mark are used to remember
+% index entries so they can be carried forward to subsequent columns
+% or pages. The mark is used as follows:
+%
+% Part Subpart Usage
+% 4 1 Boolean, true if in the midst of a first-level entry.
+% 4 2 The first-level entry text.
+% 5 1 Boolean, true if in the midst of a second-level entry.
+% 5 2 The second-level entry text.
+
+% Index Block
+% ----- -----
+
+
+\defineblock{\index}{\endindex}{\false}{}
+
+%~block index Type
+% \def \alphaformat ##1{...} % Alpha break formatter.
+% \bodyfont = {\size\style} % Body font.
+% \clubpenalty = penalty % Club penalty is often different.
+% \columngutter = glue % Column gutter.
+% \divisions = {...} % Which divisions to include.
+% \leftindent = glue % Left indentation.
+% \locators = {...} % Which locators to include.
+% \indexparams = {...} % Parameters for index generator.
+% \parhang = glue % Paragraph hang.
+% \parindent = dimen % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \position = {...} % Position and number of columns.
+% \rightindent = glue % Right indentation.
+%~end
+
+\definetoks{\locators}
+\definetoks{\indexparams}
+
+\definecount{\previndexlevel}{0}
+\definecount{\zixcols}{0}
+
+
+\def \index #1{% {type}
+ \blockcantbein{\index}{\index}%
+ \beginblockscope{index}%
+ \global\increment \indexdepth
+ \clubpenalty = \breakallowed %~default soft
+ \parskip = 0pt %~default soft
+ \processdesign{\index}{#1}%
+ \global\increment \indexnumber
+ \def \zixtype {#1}%
+ \zixparsepos
+ \indexformat}
+
+\def \indexformat {%
+ \the\bodyfont
+ \alterindentation{\leftindent}{\rightindent}%
+ \setparrag{\parrag}%
+ \setpagecolumns{\zixpageuse}{\the\zixcols}{\columngutter}%
+ \everycolumn = {\zixcarryover}%
+ \begingroup
+ \let \zfullcolumnbreak = \fullcolumnbreak
+ \let \fullcolumnbreak = \indexbreak
+ \let \shortcolumnbreak = \indexbreak
+ \global\previndexlevel = 0\relax}
+
+\def \endindex {%
+ \endgraf % End last entry.
+ \vbox{}% % Force start of column if not already.
+ \endgroup
+ \clearindexmarks
+ \everycolumn = {}%
+ \setpagecolumns{\usetextmeasure}{1}{0pt}%
+ \global\decrement \indexdepth
+ \endblockscope{index}}
+
+\def \zixparsepos {%
+ \zixcols = 1
+ \let \oneup = \relax
+ \def \twoup {\zixcols = 2}%
+ \def \threeup {\zixcols = 3}%
+ \def \zixpageuse {\usetextmeasure}%
+ \let \textarea = \relax
+ \def \typearea {\def \zixpageuse {\usetypewidth}}%
+ \let \leftmargin = \typearea
+ \the\position}
+
+% Index Entries
+% ----- -------
+
+
+\setflag \zixbreak = \false
+
+
+\def \indexentry #1#2#3{% level{heading}{locators}
+ \endgraf
+ \ifcase #1%
+ \or % Level 1 heading:
+ \clearindexmarks
+ \zixmaybebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixtype entryiformat}{#2\setmarkinfo{4}{\true}{#2}}{#3}}%
+%%% \setmarkinfo{4}{\true}{#2}%
+ \or % Level 2 heading:
+ \setmarkinfo{5}{\false}{}%
+ \zixmaybebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixtype entryiiformat}{#2\setmarkinfo{5}{\true}{#2}}{#3}}%
+%%% \setmarkinfo{5}{\true}{#2}%
+ \or % Level 3 heading:
+ \zixmaybebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixtype entryiiiformat}{#2}{#3}}%
+ \fi
+ \global\previndexlevel = #1\relax}
+
+\def \alphabreak #1{% {text}
+ \endgraf
+ \clearindexmarks
+ \zixmaybebreak
+ \alphaformat{#1}%
+ \endgraf}
+
+\def \indexbreak {%
+ \setflag \zixbreak = \true}
+
+\def \clearindexmarks {%
+ \setmarkinfo{4}{\false}{}%
+ \setmarkinfo{5}{\false}{}}
+
+\def \zixmaybebreak {%
+ \if \zixbreak
+ \zfullcolumnbreak
+ \setflag \zixbreak = \false
+ \fi}
+
+
+% This macro is invoked at the beginning of each column to perform
+% any first- and second-level entry carryovers. It only includes
+% carryovers on the first column of versos.
+
+\def \zixcarryover {%
+ \if \andp{\evenpagep}{\firstcolumnp}%
+ {\setflag \znext = {\markinfo{\bottommark}{4}{1}}%
+ \if \znext
+ \hangindent = \parhang \hangafter = 1
+ \name{\index\zixtype carryiformat}{\markinfo{\bottommark}{4}{2}}%
+ \setflag \znext = {\markinfo{\bottommark}{5}{1}}%
+ \if \znext
+ \hangindent = \parhang \hangafter = 1
+ \name{\index\zixtype carryiiformat}{\markinfo{\bottommark}{5}{2}}%
+ \fi
+ \endgraf
+ \tdimena = \zoutputcoldepth % Compensate for depth of
+ \advance \tdimena by -\prevdepth % previous column v. depth
+ \kern \tdimena % of carryover line(s).
+ \fi}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zzindexv2.tex b/macros/plain/contrib/zztex/tex/zzindexv2.tex
new file mode 100644
index 0000000000..e17a73102e
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzindexv2.tex
@@ -0,0 +1,448 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Indexing Facilities, version 2
+%
+% Synopsis: This file contains the facilities for generating index
+% parameter files, raw entry files, and for setting the indexes.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 13 June 2013
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Define Index Locators
+% ------ ----- --------
+
+
+% This list contains the definition of each locator. New ones must be
+% added to the end, and any program looking at the definitions must assume
+% that duplicates may exist and that the last one prevails.
+
+\def \zixloclist {}
+
+
+\def \definelocator #1#2#3{% {type}{attributes}{[format-args]}
+ {\setflag \pg = \false
+ \setflag \rng = \false
+ \setflag \txt = \false
+ \def \page {\setflag \pg = \true}%
+ \def \nopage {\setflag \pg = \false}%
+ \def \range {\setflag \pg = \true \setflag \rng = \true}%
+ \def \norange {\setflag \rng = \false}%
+ \def \text {\setflag \txt = \true}%
+ \def \notext {\setflag \txt = \false}%
+ #2%
+ {\def \attr {#2}%
+ \edef \znext {%
+ \noexpand\append{{#1}{\expandafter\zdefof \meaning\attr\zmark}}}%
+ \znext{\zixloclist}}%
+ \if \andp{\pg}{\notp{\txt}}%
+ \withname\gdef{\x#1}##1{\zixindex{#1}{S}{##1}{}}%
+ \if \rng
+ \withname\gdef{\x#1begin}##1{\zixindex{#1}{B}{##1}{}}%
+ \withname\gdef{\x#1end}##1{\zixindex{#1}{E}{##1}{}}%
+ \fi
+ \else\if \txt
+ \withname\gdef{\x#1}##1##2{\zixindex{#1}{S}{##1}{##2}}%
+ \if \rng
+ \withname\gdef{\x#1begin}##1##2{\zixindex{#1}{B}{##1}{##2}}%
+ \withname\gdef{\x#1end}##1##2{\zixindex{#1}{E}{##1}{##2}}%
+ \fi
+ \else
+ \error{locattr}{Invalid index locator attributes}%
+ \fi\fi
+ \if \notp{\emptyargp{#3}}%
+ \definelocatorformat{#1}#3\relax
+ \fi}}
+
+% Define Locator Formats
+% ------ ------- -------
+
+
+% This list contains the definition of each locator format. It works like
+% the locator list above.
+
+\def \zixformatlist {}
+
+\def \definelocatorformat #1#2#3#4{% {name}{rank.order}{level-1-items}{level-2-items}
+ {\def \lvli {#3}%
+ \def \lvlii {#4}%
+ \edef \znext {%
+ \noexpand\append{{#1}{#2}%
+ {\expandafter\zdefof \meaning\lvli\zmark}%
+ {\expandafter\zdefof \meaning\lvlii\zmark}}}%
+ \znext{\zixformatlist}}}
+
+% Builtin Locator Types
+% ------- ------- -----
+
+
+% These locators are built-in for ease of use. Ranks 0, 1, and 5 and higher
+% are reserved for the user. Ranks 10 and higher result in deferred
+% locators.
+
+\definelocator{page}{\page\range}
+ {{2.1}{prefix1:, |tmplt:?P|rtmplt:?P--?Q|sep:, }{}}
+
+\definelocator{figure}{\page\range}
+ {{2.3}{prefix1:, |tmplt:?P\emph{f}|rtmplt:?P--?Q\emph{f}|sep:, }{}}
+
+\definelocator{note}{\page}
+ {{2.5}{prefix1:, |tmplt:?P\emph{n}|sep:, }{}}
+
+\definelocator{table}{\page\range}
+ {{2.7}{prefix1:, |tmplt:?P\emph{t}|rtmplt:?P--?Q\emph{t}|sep:, }{}}
+
+\definelocator{see}{\nopage\text}
+ {{3}{prefix1:. \emph{See} |tmplt:?T|sep:; }{}}
+
+\definelocator{seealso}{\nopage\text}
+ {{4}{prefix1:. \emph{See also} |tmplt:?T|sep:; }{}}
+
+% Generate Indexes
+% -------- -------
+
+
+\def \zixnamelist {}
+\setflag \zindexing = \false
+
+
+\def \generateindex #1{% {name}
+ \append{#1}{\zixnamelist}%
+ \global\setflag \zindexing = \true}
+
+% Index File Handling
+% ----- ---- --------
+
+%\definewrite{\zixrootfile}
+%\definewrite{\zixdivfile}
+\setflag \zixdivopen = \false
+
+
+\def \zindexinit {%
+ \if \zindexing
+ \maplist{\zixwritezzp{##1}}{\zixnamelist}%
+ \immediate\openout \zixrootfile = \jobname.zzi\relax
+ \immediate\write \zixrootfile
+ {\zcomment Raw index entry file for book `\jobname' root.}%
+ \fi}
+
+\def \zindexfinal {%
+ \if \zindexing
+ \immediate\write \zixrootfile {\zcomment [end]}%
+ \immediate\closeout \zixrootfile
+ \fi}
+
+\def \zindexdivinit #1{% {division}
+ \if \zindexing
+ \immediate\openout \zixdivfile = #1.zzi\relax
+ \immediate\write \zixdivfile
+ {\zcomment Raw index entry file for book `\jobname', division `#1'.}%
+ \global\setflag \zixdivopen = \true
+ \fi}
+
+\def \zindexdivfinal {%
+ \if \zixdivopen
+ \immediate\write \zixdivfile {\zcomment [end]}%
+ \immediate\closeout \zixdivfile
+ \global\setflag \zixdivopen = \false
+ \fi}
+
+\def \zixwritezzp #1{% {name}
+ \begingroup
+ \processdesign{\index}{#1}%
+ \immediate\openout \zwritea = #1.zzp\relax
+ \immediate\write \zwritea {root \jobname;}%
+ \immediate\write \zwritea {index #1;}%
+ \immediate\write \zwritea {divisions \the\divisions;}%
+ \maplist{\immediate\write \zwritea {define-locator ##1;}}{\zixloclist}%
+ \maplist{\immediate\write \zwritea {define-format ##1;}}{\zixformatlist}%
+ \immediate\write \zwritea {locators \the\locators;}%
+ \immediate\write \zwritea {\the\indexparams}%
+ \immediate\closeout \zwritea
+ \endgroup}
+
+% Write Raw Index Entry
+% ----- --- ----- -----
+
+
+% This macro is called from the indexing macros defined by
+% \definelocator.
+
+\def \zixindex #1#2#3#4{% {locator}{page-code}{headings}{[text]}
+ \zixindexb {#1}{#2}{#4}#3|||\zmark}
+
+\catcode"B8 = \catother
+
+\def \zixindexb #1#2#3#4|#5|#6|#7\zmark{% {locator}{page-code}{text}
+ % head1|head2|head3|...\zmark
+ \if \zindexing
+ \zbeginhidewrite
+ \def \zhdx {#4}%
+ \def \zhdy {#5}%
+ \def \zhdz {#6}%
+ \def \ztxt {#3}%
+ \edef \znext {#1^^b8%
+ #2^^b8%
+ \noexpand\folio^^b8%
+ \expandafter\zdefof \meaning\zhdx\zmark^^b8%
+ \expandafter\zdefof \meaning\zhdy\zmark^^b8%
+ \expandafter\zdefof \meaning\zhdz\zmark^^b8%
+ \expandafter\zdefof \meaning\ztxt\zmark}%
+ \write \if \zixdivopen \zixdivfile \else \zixrootfile \fi
+ \expandafter{\znext}%
+ \if \vmodep \repeatpenalty \fi % In case glue follows write.
+ \zendhidewrite
+ \fi}
+
+\catcode"B8 = \catinvalid
+
+% Discussion of Index Formatting
+% ---------- -- ----- ----------
+
+
+% An index is formatted inside an index block, which is more or less
+% like a text block. Within the index block are occurences of the
+% \indexentry macro, one for each entry. In addition, the
+% \alphabreak macro can be used to produce breaks preceding the 'A'
+% entries, 'B' entries, etc.
+%
+% In an index block, parts 4 and 5 of the mark are used to remember
+% index headings so they can be carried forward to subsequent columns
+% or pages. The mark is used as follows:
+%
+% Part Subpart Usage
+% 4 1 Boolean, true if in the midst of a first-level entry.
+% 4 2 The first-level entry heading.
+% 5 1 Boolean, true if in the midst of a second-level entry.
+% 5 2 The second-level entry heading.
+
+% Index Block
+% ----- -----
+
+
+\defineblock{\index}{\endindex}{\false}{redefine}
+
+%~block index Type
+% \def \alphaformat ##1{...} % Alphabetic break formatter.
+% \bodyfont = {\size\style} % Body font.
+% \clubpenalty = penalty % Club penalty is often different.
+% \columngutter = glue % Column gutter.
+% \divisions = {...} % Which divisions to include.
+% \leftindent = glue % Left indentation.
+% \locators = {...} % Which locators to include.
+% \indexparams = {...} % Parameters for index generator.
+% \parhang = glue % Paragraph hang.
+% \parindent = dimen % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \position = {...} % Position and number of columns.
+% \rightindent = glue % Right indentation.
+%~end
+
+%\definetoks{\locators}
+%\definetoks{\indexparams}
+
+%\definecount{\previndexlevel}{0}
+%\definecount{\zixcols}{0}
+
+
+\def \index #1{% {type}
+ \blockcantbein{\index}{\index}%
+ \beginblockscope{index}%
+ \global\increment \indexdepth
+ \clubpenalty = \breakallowed %~default soft
+ \parskip = 0pt %~default soft
+ \processdesign{\index}{#1}%
+ \global\increment \indexnumber
+ \def \zixname {#1}%
+ \zixparsepos
+ \indexformat}
+
+\def \indexformat {%
+ \the\bodyfont
+ \alterindentation{\leftindent}{\rightindent}%
+ \setparrag{\parrag}%
+ \setpagecolumns{\zixpageuse}{\the\zixcols}{\columngutter}%
+ \everycolumn = {\zixcarryover}%
+ \begingroup
+ \let \zfullcolumnbreak = \fullcolumnbreak
+ \let \fullcolumnbreak = \zixcolumnbreak
+ \let \shortcolumnbreak = \zixcolumnbreak
+ \global\previndexlevel = 0\relax}
+
+\def \endindex {%
+ \endgraf % End last entry.
+ \vbox{}% % Force start of column if not already.
+ \endgroup
+ \zclearindexmarks
+ \everycolumn = {}%
+ \setpagecolumns{\usetextmeasure}{1}{0pt}%
+ \global\decrement \indexdepth
+ \endblockscope{index}}
+
+\def \zixparsepos {%
+ \zixcols = 1
+ \def \zixpageuse {\usetextmeasure}%
+ \setflag \zixrunin = \false
+ \let \oneup = \relax
+ \let \outline = \relax
+ \def \runin {\setflag \zixrunin = \true}%
+ \def \threeup {\zixcols = 3}%
+ \def \twoup {\zixcols = 2}%
+ \let \usetextmeasure = \relax
+ \let \usetextwidth = \relax
+ \def \usetypewidth {\def \zixpageuse {\usetypewidth}}%
+ \the\position}
+
+% Format Index Entries
+% ------ ----- -------
+
+
+\setflag \zixbreak = \false
+
+
+% This macro formats the main portion of an index entry.
+
+\def \indexentry #1#2#3{% level{heading}{locators}
+ \ifcase #1%
+ \or % Level 1 heading:
+ \endgraf
+ \zclearindexmarks
+ \zixmaybeforcebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixname entryiformat}{#2\setmarkinfo{4}{\true}{#2}}{#3}}%
+ \or % Level 2 heading:
+ \if \notp{\zixrunin}%
+ \endgraf
+ \if \eqlp{\previndexlevel}{1}\vpenalty{\breaknever}\fi
+ \fi
+ \setmarkinfo{5}{\false}{}%
+ \zixmaybeforcebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixname entryiiformat}{#2\setmarkinfo{5}{\true}{#2}}{#3}}%
+ \or % Level 3 heading:
+ \if \notp{\zixrunin}\endgraf \fi
+ \zixmaybeforcebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixname entryiiiformat}{#2}{#3}}%
+ \fi
+ \global\previndexlevel = #1\relax
+ \ignorespaces}
+
+% This macro format any deferred locators.
+
+\def \indexdeferred #1#2{% level{locators}
+ \ifcase #1%
+ \or % Level 1 deferred locators:
+ \if \notp{\zixrunin}\endgraf \fi
+ \setmarkinfo{5}{\false}{}%
+ \zixmaybeforcebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixname deferrediformat}{#2}}%
+ \or % Level 2 deferred locators:
+ \if \notp{\zixrunin}\endgraf \fi
+ \zixmaybeforcebreak
+ \hangindent = \parhang \hangafter = 1
+ {\name{\index\zixname deferrediiformat}{#2}}%
+ \fi
+ \ignorespaces}
+
+\def \alphabreak #1{% {text}
+ \endgraf
+ \zclearindexmarks
+ \zixmaybeforcebreak
+ \alphaformat{#1}%
+ \endgraf}
+
+\def \zclearindexmarks {%
+ \setmarkinfo{4}{\false}{}%
+ \setmarkinfo{5}{\false}{}}
+
+\def \zixcolumnbreak {%
+ \setflag \zixbreak = \true}
+
+\def \zixmaybeforcebreak {%
+ \if \zixbreak
+ \zfullcolumnbreak
+ \setflag \zixbreak = \false
+ \fi}
+
+
+% This macro is invoked at the beginning of each column to perform
+% any first- and second-level entry carryovers. It only includes
+% carryovers on the first column of versos.
+
+\def \zixcarryover {%
+ \if \andp{\evenpagep}{\firstcolumnp}%
+ {\setflag \znext = {\markinfo{\bottommark}{4}{1}}%
+ \if \znext
+ \hangindent = \parhang \hangafter = 1
+ \name{\index\zixname carryoveriformat}{\markinfo{\bottommark}{4}{2}}%
+ \setflag \znext = {\markinfo{\bottommark}{5}{1}}%
+ \if \znext
+ \hangindent = \parhang \hangafter = 1
+ \name{\index\zixname carryoveriiformat}{\markinfo{\bottommark}{5}{2}}%
+ \fi
+ \endgraf
+ \tdimena = \zoutputcoldepth % Compensate for depth of
+ \advance \tdimena by -\prevdepth % previous column v. depth
+ \kern \tdimena % of carryover line(s).
+ \fi}%
+ \fi}
+
+% Built-in Entry Formats
+% -------- ----- -------
+
+
+% These entry formats and carryovers are for a typical outliine style index.
+
+\def \indexoutlineentryiformat #1#2{%
+ \noindent #1#2\par}
+
+\def \indexoutlineentryiiformat #1#2{%
+ \indent #1#2\par}
+
+\def \indexoutlineentryiiiformat #1#2{%
+ \indent\indent #1#2\par}
+
+\def \indexoutlinedeferrediformat #1{%
+ \indent #1\par}
+
+\def \indexoutlinedeferrediiformat #1{%
+ \indent\indent #1\par}
+
+\def \indexoutlinecarryoveriformat #1{%
+ \noindent #1 \tie{\emph{(continued)}}\par}
+
+\def \indexoutlinecarryoveriiformat #1{%
+ \indent #1 \tie{\emph{(continued)}}\par}
+
+% These entry formats and carryovers are for a typical run-in style index.
+
+\setflag \zixplain = \false
+
+\def \indexruninentryiformat #1#2{%
+ \noindent #1#2%
+ \global\setflag \zixplain = {\emptyargp{#2}}%
+ \if \zixplain :\space \fi}
+
+\def \indexruninentryiiformat #1#2{%
+ \if \notp{\zixplain};\space \fi
+ \global\setflag \zixplain = \false
+ #1#2}
+
+\def \indexruninentryiiiformat #1#2{%
+ \error{runiniii}{It makes no sense to have level-3 entries in a run-in index}}
+
+\def \indexrunindeferrediformat #1{%
+ . #1}
+
+\def \indexrunincarryoveriformat #1{%
+ \noindent #1 \tie{\emph{(continued)}}\par}
+
+\def \indexrunincarryoveriiformat #1{%
+ \relax}
diff --git a/macros/plain/contrib/zztex/tex/zzio.tex b/macros/plain/contrib/zztex/tex/zzio.tex
new file mode 100644
index 0000000000..04a3fbbfac
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzio.tex
@@ -0,0 +1,84 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX I/O Facilities
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 9 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Terminal & Log I/O
+% -------- - --- ---
+
+% \message writes to the terminal and the log file, without newlines.
+% This macro adds a newline feature:
+
+\def \messagenl #1{% {text}
+ {\newlinechar = `\_%
+ \message{#1}}}
+
+% This macro writes a line to the log file, with a newline at the end.
+
+\def \writelog {\immediate\write -1}
+
+% \ask combines a prompt using \messagenl with a read from the terminal.
+
+\def \ask #1#2{% {\result-macro}{question}
+ {\messagenl{_#2}%
+ \endlinechar = -1
+ \global\read 16 to #1}}
+
+% Including Files
+% --------- -----
+
+
+\def \include #1{% {file}
+ {\checkfile{\zifile}{#1}%
+ \if \zifile
+ \gdef \znext {\input #1\relax}%
+ \else
+ \warning{noinclfile}{File `#1' does not exist}%
+ \ask{\newfile}{Enter a new file name, or a period (.) to skip it.}%
+ \stringeql{\znext}{\newfile}{.}%
+ \if \znext
+ \xdef \znext {}%
+ \else
+ \xdef \znext {\noexpand\include{\newfile}}%
+ \fi
+ \fi}%
+ \znext
+ \endgraf}
+
+\def \zportionid {}
+
+\def \includeportion #1#2{% {file}{portion-id}
+ \gdef \zportionid {#2}%
+ \include{#1}%
+ \gdef \zportionid {}}
+
+\def \portion #1{% {portion-id}
+ \stringeql{\znext}{#1}{\zportionid}%
+ \if \znext}
+
+\let \endportion = \fi
+
+\def \includeifexists #1{% {file}
+ \checkfile{\zifile}{#1}%
+ \if \zifile
+ \input #1\relax
+ \endgraf
+ \fi}
+
+% Utilities
+% ---------
+
+
+\def \checkfile #1#2{% {\result-flag}{file}
+ \openin \zreada #2\relax
+ \setflag #1= {\notp{\eofp{\zreada}}}%
+ \closein \zreada}
diff --git a/macros/plain/contrib/zztex/tex/zzlist.tex b/macros/plain/contrib/zztex/tex/zzlist.tex
new file mode 100644
index 0000000000..197090d153
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzlist.tex
@@ -0,0 +1,163 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX List Facilities
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 12 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% List Block
+% ---- -----
+
+
+\defineblock{\list}{\endlist}{\false}{}
+\resetinvcontext{\list}
+
+%~block list Type, Level
+% \abovepenalty = integer % Penalty above list.
+% \aboveskip = glue % Space b/b above list.
+% \setflag \allowitemtag = flag % Allow \tag command on item.
+% \belowpenalty = integer % Penalty below list.
+% \belowskip = glue % Space b/b below list.
+% \bodyfont = {...} % Font for text.
+% \def \endpartext {...} % Text at end of each paragraph.
+% \interitemskip = skip % Extra space between items.
+% \itemnumber = integer % Number of first item.
+% \def \labelformat ##1{...} % Item label formatter.
+% \labelshift = dimen % Horizontal shift of label.
+% \def \labeltext {...} % Label text or \arg if \item{...}.
+% \labelwidth = dimen % Width of label or \naturalwidth.
+% \leftindent = glue % Left indentation.
+% \parindent = glue % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \rightindent = glue % Right indentation.
+% \def \tagcomptext {...} % Composite text for tag, if not label.
+% \width = dimen % Width of text.
+%~end
+
+\defineskip{\interitemskip}{0pt}
+\definedimen{\labelshift}{0pt}
+\definedimen{\labelwidth}{0pt}
+
+\definecount{\nextitemnumber}{0}
+
+
+\def \list #1{% {type}
+ \endgraf
+ \beginblockscope{list}%
+ \global\increment \listdepth
+ \abovepenalty = \breakgood %~default hard
+ \setflag \allowitemtag = \false %~default soft
+ \belowpenalty = \breakgood %~default hard
+ \def \endpartext {}% %~default hard
+ \itemnumber = 1 %~default with
+ \def \tagcomptext {}% %~default soft
+ \processdesign{\list}{#1\romannumeral\listdepth}%
+ \global\increment \listnumber
+ \decrement \itemnumber
+ \listformat
+ \def \par {\endpartext \endgraf}%
+ \settaginfo{}{}} % No tag info so far.
+
+\def \endlist {%
+ \par
+ \futurelet\nexttoken \zendlist}
+
+\def \zendlist {%
+ \closeifinblock{\item}{\enditem}%
+ \endlistformat
+ \if \onep{\listdepth}%
+ \global\nextitemnumber = \itemnumber
+ \global\increment \nextitemnumber
+ \fi
+ \global\decrement \listdepth
+ \endblockscope{list}%
+ \parnext}
+
+\def \listformat {%
+ \the\bodyfont
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \setparrag{\parrag}%
+ \advance \interitemskip by \baselineskip}
+
+\def \endlistformat{%
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+
+% This macro helps with a list design that involves measuring some text.
+
+\def \setmeasuredlabel #1#2#3{% {extra-indent}{template}{formatter}
+ \def \labelformat ##1{#3}%
+ \measuretextwidth{\labelwidth}{#2}%
+ \labelshift = -\labelwidth
+ \leftindent = \labelwidth
+ \advance \leftindent by #1\relax}
+
+\def \adjustinteritemskip #1{% {amount} %^modifier
+ \with{\advance\interitemskip by #1}}
+
+%~ This modifier on |\list| is used when a list immediately follows
+%~ an |\item| command; that is, when an item is a sublist.
+%~ It eliminates the vertical space above the sublist.
+
+\def \immediatesublist {% %^modifier
+ \with{\abovepenalty = \breaknever
+ \aboveskip = 0pt}}
+
+% Item Block
+% ---- -----
+
+% The \item block is subordinate to the \list block, and thus inherits all
+% of its design parameters from \list.
+
+
+\defineblock{\item}{\enditem}{\false}{}
+
+%~block item
+% \difficulty = integer % Level of difficulty.
+%~end
+
+\def \item {% [{label}]
+ \blockmustbein{\item}{\list}%
+ \closeifinblock{\item}{\enditem}%
+ % Don't bother with block scope.
+ \difficulty = 0 %~default with
+ \zprocesswith % Instead of \processdesign.
+ \increment \itemnumber
+ \bbskipabove{\breakgood}{\interitemskip}%
+ \def \zarg {\arg}%
+ \if \tokeqlp{\labeltext}{\zarg}%
+ \def \znext {\itemformat}%
+ \else
+ \def \znext {\itemformat{\labeltext}}%
+ \fi
+ \znext}
+
+\def \enditem {%
+ \par}
+
+\def \itemformat #1{% {label}
+ \noindent
+ \kern \labelshift
+ \if \dimeqlp{\labelwidth}{\naturalwidth}%
+ {\labelformat{#1}}%
+ \else
+ \hbox to \labelwidth{\labelformat{#1}}%
+ \fi
+ \if \allowitemtag
+ \if \emptydefp{\tagcomptext}%
+ \settaginfo{#1}{???}%
+ \else
+ \settaginfo{\tagcomptext}{???}%
+ \fi
+ \fi
+ \ignorespaces}
diff --git a/macros/plain/contrib/zztex/tex/zzltrspc.tex b/macros/plain/contrib/zztex/tex/zzltrspc.tex
new file mode 100644
index 0000000000..7fcd6e5d72
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzltrspc.tex
@@ -0,0 +1,111 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: Letterspacing Facility
+%
+% Synopsis: This module provides a fairly comprehensive letterspacing
+% facility for ZzTeX.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 10 July 1997
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Letterspacing Commands
+% ------------- --------
+
+
+\defineskip{\zlspamount}{0pt}
+\defineskip{\zlspace}{0pt}
+
+
+\def \letterspace #1#2{% {amount[,space]}{text}
+ {\zlspparse #1,,\zmark
+ \zletterspace{#2}}}
+
+\def \eletterspace #1#2{% {amount[,space]}{text}
+ \edef \znext {\noexpand\letterspace{#1}{#2}}%
+ \znext}
+
+\def \zlspparse #1,#2,#3\zmark{%
+ \zlspamount = #1\relax
+ \if \emptyargp{#2}%
+ \measurespacewidth{\zlspace}%
+ \advance \zlspace by \zlspamount
+ \else
+ \zlspace = #2\relax
+ \fi}
+
+% These commands can be used in letterspaced text, but must do nothing
+% when letterspacing is not in progress.
+
+\let \lsp = \relax
+\let \nolsp = \relax
+\def \lspspace {\space}%
+\def \zlspoff {\relax}%
+\def \lspoff {\zlspoff}%
+\def \zlspon {\relax}%
+\def \lspon {\zlspon}%
+
+% Letterspacing Engine
+% ------------- ------
+
+
+\def \zletterspace #1{% {text}
+ \def \lsp {\nobreak\hskip \zlspamount}%
+ \def \lspspace {\hskip \zlspace}%
+ \def \zzlspoff {\zlspoff}%
+ \def \zzlspon {\zlspon}%
+ \setflag \zlsping = \true
+ \let \zlspprev = \relax
+ \setflag \zlspprevchar = \false
+ \let \zmark = \relax
+ {\zlspa #1\zmark}}
+
+\def \zlspa {\futurelet\zlspcur \zlspb}
+
+\def \zlspb {%
+ \let \znext = \zlspc
+ \if \tokeqlp{\zlspcur}{\zmark}%
+ \let \znext = \relax
+ \else\if \cateqlp{\noexpand\zlspcur}{\zspacetoken}%
+ \if \zlsping \aftergroup\lspspace \else \aftergroup\space \fi
+ \else\if \cateqlp{\noexpand\zlspcur}{\bgroup}%
+ \aftergroup{%
+ \else\if \cateqlp{\noexpand\zlspcur}{\egroup}%
+ \aftergroup}%
+ \else\if \tokeqlp{\zlspcur}{\zzlspoff}%
+ \setflag \zlsping = \false
+ \else\if \tokeqlp{\zlspcur}{\zzlspon}%
+ \setflag \zlsping = \true
+ \else
+ \let \znext = \zlspd
+ \fi\fi\fi\fi\fi\fi
+ \znext}
+
+\def \zlspc {% Discard current token.
+ \let \zlspprev = \zlspcur
+ \setflag \zlspprevchar = \false
+ \afterassignment\zlspa \let\zlspcur = }
+
+\long\def \zlspd #1{% Process current token.
+ \let \zlspprev = \zlspcur
+ \if \cateqlp{\noexpand#1}{\relax}%
+ \setflag \zlspprevchar = \false
+ \aftergroup#1%
+ \else\if \cateqlp{\noexpand#1}{\noexpand~}%
+ \setflag \zlspprevchar = \false
+ \if \zlsping \aftergroup\lspspace \else \aftergroup\space \fi
+ \else\if \orp{\andp{\codeeqlp{\zlspprev}{-}}{\codeeqlp{\zlspcur}{-}}}
+ {\orp{\andp{\codeeqlp{\zlspprev}{`}}{\codeeqlp{\zlspcur}{`}}}
+ {\andp{\codeeqlp{\zlspprev}{'}}{\codeeqlp{\zlspcur}{'}}}}%
+ \setflag \zlspprevchar = \true
+ \aftergroup#1%
+ \else
+ \if \andp{\zlspprevchar}{\zlsping}\aftergroup\lsp \fi
+ \setflag \zlspprevchar = \true
+ \aftergroup#1%
+ \fi\fi\fi
+ \zlspa}
diff --git a/macros/plain/contrib/zztex/tex/zzlucida.tex b/macros/plain/contrib/zztex/tex/zzlucida.tex
new file mode 100644
index 0000000000..6bfc5e5554
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzlucida.tex
@@ -0,0 +1,140 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Lucida Math Font Support
+%
+% Synopsis: This module contains various definitions and redefinitions
+% necessary to use the Lucida math fonts.
+%
+% Note: This module assumes the user is generating PostScript output.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 27 June 1992
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Type Styles
+% ---- ------
+
+\setstyleskewchar{\msy}{"7F}
+\setstyleskewchar{\msy}{"30}
+
+% Redefine Math Characters
+% -------- ---- ----------
+
+
+\zmchar \Gamma \classvarfam \mexfam {D0}
+\zmchar \Delta \classvarfam \mexfam {D1}
+\zmchar \Theta \classvarfam \mexfam {D2}
+\zmchar \Lambda \classvarfam \mexfam {D3}
+\zmchar \Xi \classvarfam \mexfam {D4}
+\zmchar \Pi \classvarfam \mexfam {D5}
+\zmchar \Sigma \classvarfam \mexfam {D6}
+\zmchar \Upsilon \classvarfam \mexfam {D7}
+\zmchar \Phi \classvarfam \mexfam {D8}
+\zmchar \Psi \classvarfam \mexfam {D9}
+\zmchar \Omega \classvarfam \mexfam {DA}
+
+\zmchar {`=} \classrel \msyfam {83}
+\zmchar {`+} \classbinop \msyfam {82}
+
+\definemathdelimiter {`/} \classord \mitfam {3D} \mexfam {0E}
+
+\zmchar {`(} \classopen \mitfam {84}
+\definemathdelimiter {`(} \classord \mitfam {84} \mexfam {00}
+\zmchar {`)} \classclose \mitfam {85}
+\definemathdelimiter {`)} \classord \mitfam {85} \mexfam {01}
+
+\zmchar {`[} \classopen \mitfam {86}
+\definemathdelimiter {`[} \classord \mitfam {86} \mexfam {02}
+\zmchar {`]} \classclose \mitfam {87}
+\definemathdelimiter {`]} \classord \mitfam {87} \mexfam {03}
+
+\zmchar \angle \classord \msyfam {8B}
+\zmchar \bowtie \classrel \mitfam {F6}
+\zmchar \cong \classrel \msyfam {9B}
+\zmchar \doteq \classrel \msyfam {C9}
+\zmchar \models \classrel \msyfam {EE}
+
+ \if \zusemar
+\zmchar \hbar \classord \mitfam {9D}
+\zmchar \hookleftarrow \classrel \marfam {3C}
+\zmchar \hookrightarrow \classrel \marfam {3E}
+\zmchar \leftrightharpoons \classrel \marfam {79}
+\zmchar \mapsto \classrel \marfam {2C}
+\zmchar \neq \classrel \marfam {94}
+\zmchar \rightleftharpoons \classrel \marfam {7A}
+ \fi
+
+% New Math Characters
+% --- ---- ----------
+
+
+ \if \zusemar
+\zmchar \notapprox \classrel \marfam {98}
+\zmchar \notasymp \classrel \marfam {F3}
+\zmchar \notcong \classrel \marfam {99}
+\zmchar \noteq \classrel \marfam {94}
+\zmchar \notequiv \classrel \marfam {95}
+\zmchar \notgeq \classrel \marfam {9D}
+\zmchar \notgreater \classrel \marfam {9B}
+\zmchar \notin \classrel \marfam {1D}
+\zmchar \notleq \classrel \marfam {9C}
+\zmchar \notless \classrel \marfam {9A}
+\zmchar \notmid \classrel \marfam {F6}
+\zmchar \notmodels \classrel \marfam {F9}
+\zmchar \notni \classrel \marfam {1F}
+\zmchar \notparallel \classrel \marfam {F7}
+\zmchar \notprec \classrel \marfam {E5}
+\zmchar \notpreceq \classrel \marfam {E7}
+\zmchar \notsim \classrel \marfam {96}
+\zmchar \notsimeq \classrel \marfam {97}
+\zmchar \notsqsubseteq \classrel \marfam {D4}
+\zmchar \notsqsupseteq \classrel \marfam {D5}
+\zmchar \notsubset \classrel \marfam {C6}
+\zmchar \notsubseteq \classrel \marfam {C8}
+\zmchar \notsucc \classrel \marfam {E6}
+\zmchar \notsucceq \classrel \marfam {E8}
+\zmchar \notsupset \classrel \marfam {C7}
+\zmchar \notsupseteq \classrel \marfam {C9}
+\zmchar \notvdash \classrel \marfam {F8}
+ \fi
+
+% Redefine General Tools
+% -------- ------- -----
+
+
+\def \big #1{{\hbox{$\left#1\vbox to 8.2pt{}\right.\zmnosp$}}}
+\def \Big #1{{\hbox{$\left#1\vbox to 10.8pt{}\right.\zmnosp$}}}
+\def \bigg #1{{\hbox{$\left#1\vbox to 13.42pt{}\right.\zmnosp$}}}
+\def \Bigg #1{{\hbox{$\left#1\vbox to 16.03pt{}\right.\zmnosp$}}}
+\def \biggg #1{{\hbox{$\left#1\vbox to 17.72pt{}\right.\zmnosp$}}}
+\def \Biggg #1{{\hbox{$\left#1\vbox to 21.25pt{}\right.\zmnosp$}}}
+
+\def \bigggl {\mathopen\biggg}
+\def \Bigggl {\mathopen\Biggg}
+\def \bigggr {\mathclose\biggg}
+\def \Bigggr {\mathclose\Biggg}
+
+\def \joinrel {\mathrel{\mkern -4mu}}
+
+\def \mathstrut {\vphantom{f}}
+
+\def \matrix #1{%
+ \null\nonscript\,%
+ \vcenter{\normalbaselines
+ \ialign{\hfil $##$\hfil&& \quad \hfil $##$\hfil \crcr
+ \mathstrut\crcr
+ \noalign{\kern -0.9\baselineskip}%
+ #1\crcr
+ \mathstrut\crcr
+ \noalign{\kern -0.9\baselineskip}}}%
+ \nonscript\,}
+
+\def \zroot #1#2{% {\style}{radicand}
+ \setbox\zboxa = \hbox{$#1\sqrt{#2}$}%
+ \tdimena = \ht\zboxa
+ \advance \tdimena by -\dp\zboxa
+ \mkern 5mu \raise .6\tdimena \copy\zrootbox \mkern -8mu \box\zboxa}
diff --git a/macros/plain/contrib/zztex/tex/zzmath.tex b/macros/plain/contrib/zztex/tex/zzmath.tex
new file mode 100644
index 0000000000..9a39dd2f0b
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmath.tex
@@ -0,0 +1,1919 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Mathematics Facilities
+%
+% Synopsis: This file provides the mathematics facilities of
+% ZzTeX. All of the Plain TeX math stuff is included.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 14 November 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Math Version
+% ---- -------
+
+
+\definecount{\zmathver}{0}
+
+
+\def \mathversion #1{%
+ \global\zmathver = #1\relax
+ \input zzmathv#1\relax}
+
+% Alternate Math Fonts
+% --------- ---- -----
+
+
+\outer\def \ComputerModernmathfonts {%
+ \input zzcmmath\relax}
+
+\outer\def \Lucidamathfonts #1{% {arrows?}
+ \setflag \zusemar = #1\relax
+ \input zzlucida\relax}
+
+\outer\def \MathTimefonts {%
+ \input zzmtime\relax}
+
+% Spacing
+% -------
+
+
+% Note major uses of each kind of space:
+% thin: around large operators; after punctuation
+% medium: around binary operators
+% thick: around relational operators
+
+\def \setmathspaces #1#2#3{% {thin}{medium}{thick}
+ \global\thinmuskip = #1\relax
+ \global\medmuskip = #2\relax
+ \global\thickmuskip = #3\relax}
+
+\def \mthickspace {\mkern 2\thinmuskip}
+
+\def \mthinspace {\mkern \thinmuskip}
+\def \mnegthinspace {\mkern -\thinmuskip}
+
+\def \mspace #1{\mkern #1\relax}% {mu}
+
+% Math mode \, \; \! are in ZZHMODE.
+
+\def \setTeXmathspaces {%
+ \setmathspaces{3mu}{4mu plus 2mu minus 4mu}{5mu plus 5mu}}
+
+% Character Definition
+% --------- ----------
+
+
+% These are the math character classes:
+
+\chardef \classord = 0 % An ordinary symbol (\alpha). %^math_class
+\chardef \classlargeop = 1 % A large operator (\sum).. %^math_class
+\chardef \classbinop = 2 % A binary operator (+). %^math_class
+\chardef \classrel = 3 % A relation (=). %^math_class
+\chardef \classopen = 4 % An opening fence ([). %^math_class
+\chardef \classclose = 5 % A closing fence (]). %^math_class
+\chardef \classpunc = 6 % A punctuation character (,). %^math_class
+\chardef \classvarfam = 7 % A character that varies with \fam (\Gamma). %^math_class
+\chardef \classactive = 8 % An active character ('). %^math_class
+
+
+\def \definemathaccent #1#2#3#4{% {name}{class}{family}{hex-code}
+ {\zcalcmathcode{#2}{#3}{#4}%
+ \xdef #1{\mathaccent \the\tcounta\relax}}%
+ \ignorespaces}
+
+\def \definemathchar #1#2#3#4{% {name}{class}{family}{hex-code}
+ {\zcalcmathcode{#2}{#3}{#4}%
+ \zdefmathch#1\zmark
+ \if \znext
+ \global\mathcode #1= \tcounta
+ \else
+ \global\mathchardef #1= \tcounta
+ \fi}%
+ \ignorespaces}
+
+\def \definemathdelimiter #1#2#3#4#5#6{% {name}{class}{fam1}{hex1}{fam2}{hex2}
+ {\zcalcmathcode{#2}{#3}{#4}%
+ \multiply \tcounta by 16
+ \advance \tcounta by #5
+ \multiply \tcounta by 256
+ \advance \tcounta by "#6\relax
+ \zdefmathch#1\zmark
+ \if \znext
+ \global\delcode #1= \tcounta
+ \else
+ \xdef #1{\delimiter\the\tcounta\relax}%
+ \fi}%
+ \ignorespaces}
+
+\def \definemathjoinedsymbol #1#2#3#4#5{% {name}{atom}{char1}{char2}{sep}
+ \gdef #1{#2{{#3}\mspace{#5mu}{#4}}}}
+
+\def \definemathlabeledarrow #1#2#3#4{% {name}{atom}{label}{arrow}
+ \gdef #1{#2{\mathop{#4}\limits^{#3}}}}
+
+\def \definemathstackedsymbol #1#2#3#4#5{% {name}{atom}{char1}{char2}{sep}
+ \gdef #1{#2{\mathpalette\zstksym{{#3}{#4}{#5}}}}}
+
+
+\def \zcalcmathcode #1#2#3{% {class}{family}{hex-code}
+ \tcounta = #1
+ \multiply \tcounta by 16
+ \advance \tcounta by #2
+ \multiply \tcounta by 256
+ \advance \tcounta by "#3\relax}
+
+\def \zdefmathch #1#2\zmark{%
+ \setflag\znext = {\if `\noexpand#1\true \else \false \fi}}
+
+\definedimen{\muwidth}{0pt}
+
+\def \zstksym #1#2{% {style}{{char1}{char2}{sep}}
+ \zstksymb #1#2}
+
+\def \zstksymb #1#2#3#4{% {style}{char1}{char2}{sep}
+ \vcenter{\baselineskip = 0pt
+ \lineskiplimit = -\maxdimen
+ \setbox \zboxa = \hbox{$#1\mkern 1mu$}%
+ \muwidth = \wd\zboxa
+ \ialign{\hfil ##\hfil\cr
+ \raise #4\muwidth \hbox{$#1#2$}\cr
+ $#1#3$\cr}}}
+
+% Character Styles
+% --------- ------
+
+
+\definecount{\zmstyfam}{0}
+
+
+\def \setmathdigitstyle #1{% {style}
+ {\tcounta = "\the\classvarfam0
+ \advance \tcounta by \name{#1fam}%
+ \multiply \tcounta by 256
+ \advance \tcounta by `\0%
+ \tcountb = `0
+ \loop
+ \global\mathcode \tcountb = \tcounta
+ \increment \tcounta
+ \increment \tcountb
+ \if \lssp{\tcountb}{`\:}\repeat}}
+
+\def \setmathletterstyle #1{% {\style}
+ {\tcounta = "\the\classvarfam0
+ \advance \tcounta by \name{#1fam}%
+ \multiply \tcounta by 256
+ \advance \tcounta by `\A%
+ \tcountb = `A
+ \loop
+ \global\mathcode \tcountb = \tcounta
+ \increment \tcounta
+ \increment \tcountb
+ \if \lssp{\tcountb}{`\[}\repeat
+ \advance \tcounta by 6
+ \tcountb = `\a
+ \loop
+ \global\mathcode \tcountb = \tcounta
+ \increment \tcounta
+ \increment \tcountb
+ \if \lssp{\tcountb}{`\{}\repeat}%
+ \if \zcommonencoding
+ \def \znext {#1}%
+ \def \zit {\it}%
+ \if \tokeqlp{\znext}{\zit}\setstyleskewchar{#1}{7}\fi
+ \fi}
+
+\def \setmathucgreekstyle #1{% {style}
+ {\zmstyfam = \name{#1fam}%
+\definemathchar \Alpha \classvarfam \rmfam {41}
+\definemathchar \Beta \classvarfam \rmfam {42}
+\definemathchar \Gamma \classvarfam \zmstyfam {00}
+\definemathchar \Delta \classvarfam \zmstyfam {01}
+\definemathchar \Epsilon \classvarfam \rmfam {45}
+\definemathchar \Zeta \classvarfam \rmfam {5A}
+\definemathchar \Eta \classvarfam \rmfam {48}
+\definemathchar \Theta \classvarfam \zmstyfam {02}
+\definemathchar \Iota \classvarfam \rmfam {49}
+\definemathchar \Kappa \classvarfam \rmfam {4B}
+\definemathchar \Lambda \classvarfam \zmstyfam {03}
+\definemathchar \Mu \classvarfam \rmfam {4D}
+\definemathchar \Nu \classvarfam \rmfam {4E}
+\definemathchar \Xi \classvarfam \zmstyfam {04}
+\definemathchar \Omicron \classvarfam \rmfam {4F}
+\definemathchar \Pi \classvarfam \zmstyfam {05}
+\definemathchar \Rho \classvarfam \rmfam {50}
+\definemathchar \Sigma \classvarfam \zmstyfam {06}
+\definemathchar \Tau \classvarfam \rmfam {54}
+\definemathchar \Upsilon \classvarfam \zmstyfam {07}
+\definemathchar \Phi \classvarfam \zmstyfam {08}
+\definemathchar \Chi \classvarfam \rmfam {58}
+\definemathchar \Psi \classvarfam \zmstyfam {09}
+\definemathchar \Omega \classvarfam \zmstyfam {0A}}}
+
+\def \zmtextstyle {\rm}
+\def \zmtextfam {\rmfam}
+
+\def \setmathtextstyle #1{% {style}
+ \gdef \zmtextstyle {#1}%
+ \xdef \zmtextfam {\name{#1fam}}}
+
+\def \zmfunstyle {\rm}
+
+\def \setmathfunctionstyle #1{% {style}
+ \gdef \zmfunstyle {#1}}
+
+\def \zmvarstyle {\it}
+
+\def \setmathmvarstyle #1{% {style}
+ \gdef \zmvarstyle {#1}}
+
+\def \setmathpunctuationstyle #1{% {style}
+ {\zmstyfam = \name{#1fam}%
+ \definemathchar {`.} \classord \zmstyfam {2E}
+ \definemathchar {`,} \classpunc \zmstyfam {2C}
+ \definemathchar {`;} \classpunc \zmstyfam {3B}}}
+
+% Characters
+% ----------
+
+
+\let \zmchar = \definemathchar
+
+
+% Letters:
+
+% INITEX does the following for each letter:
+%
+% \definemathchar{letter}{\classvarfam}{\mit}{xx}
+%
+% This can be changed using the \setmathletterstyle command above.
+
+
+% Figures (digits):
+
+% INITEX does the following for each digit:
+%
+% \definemathchar{digit}{\classvarfam}{\rm}{xx}
+%
+% This can be changed using the \setmathdigitstyle command above.
+
+
+% Uppercase Greek letters:
+
+% This can be changed using the \setmathucgreekstyle command above.
+
+\setmathucgreekstyle{\rm}
+
+
+% Lowercase Greek letters:
+
+\zmchar \alpha \classord \mitfam {0B}
+\zmchar \beta \classord \mitfam {0C}
+\zmchar \gamma \classord \mitfam {0D}
+\zmchar \delta \classord \mitfam {0E}
+\zmchar \epsilon \classord \mitfam {0F}
+\zmchar \zeta \classord \mitfam {10}
+\zmchar \eta \classord \mitfam {11}
+\zmchar \theta \classord \mitfam {12}
+\zmchar \iota \classord \mitfam {13}
+\zmchar \kappa \classord \mitfam {14}
+\zmchar \lambda \classord \mitfam {15}
+\zmchar \mu \classord \mitfam {16}
+\zmchar \nu \classord \mitfam {17}
+\zmchar \xi \classord \mitfam {18}
+\zmchar \omicron \classord \mitfam {6F}
+\zmchar \pi \classord \mitfam {19}
+\zmchar \rho \classord \mitfam {1A}
+\zmchar \sigma \classord \mitfam {1B}
+\zmchar \tau \classord \mitfam {1C}
+\zmchar \upsilon \classord \mitfam {1D}
+\zmchar \phi \classord \mitfam {1E}
+\zmchar \chi \classord \mitfam {1F}
+\zmchar \psi \classord \mitfam {20}
+\zmchar \omega \classord \mitfam {21}
+
+\zmchar \varepsilon \classord \mitfam {22}
+\zmchar \vartheta \classord \mitfam {23}
+\zmchar \varpi \classord \mitfam {24}
+\zmchar \varrho \classord \mitfam {25}
+\zmchar \varsigma \classord \mitfam {26}
+\zmchar \varphi \classord \mitfam {27}
+
+
+% Ordinary symbols:
+
+\zmchar {`.} \classord \rmfam {2E}
+\zmchar {`/} \classord \mitfam {3D}
+\zmchar \zmbackslash \classord \msyfam {6E}
+\zmchar {`|} \classord \msyfam {6A}
+\zmchar \aleph \classord \msyfam {40}
+\zmchar \bot \classord \msyfam {3F}
+\zmchar \clubsuit \classord \msyfam {7C}
+\zmchar \diamondsuit \classord \msyfam {7D}
+\zmchar \ell \classord \mitfam {60}
+\zmchar \emptyset \classord \msyfam {3B}
+\zmchar \exists \classord \msyfam {39}
+\zmchar \flat \classord \mitfam {5B}
+\zmchar \forall \classord \msyfam {38}
+\zmchar \heartsuit \classord \msyfam {7E}
+\zmchar \Im \classord \msyfam {3D}
+\zmchar \imath \classord \mitfam {7B}
+\zmchar \infinity \classord \msyfam {31}
+\let \infty = \infinity
+\zmchar \jmath \classord \mitfam {7C}
+\zmchar \nabla \classord \msyfam {72}
+\zmchar \natural \classord \mitfam {5C}
+\zmchar \neg \classord \msyfam {3A}
+\let \lnot = \neg
+\zmchar \partial \classord \mitfam {40}
+\zmchar \prime \classord \msyfam {30}
+\zmchar \Re \classord \msyfam {3C}
+\zmchar \sharp \classord \mitfam {5D}
+\zmchar \spadesuit \classord \msyfam {7F}
+\zmchar \surd \classord \msyfam {70}
+\zmchar \top \classord \msyfam {3E}
+\zmchar \triangle \classord \msyfam {34}
+\zmchar \wp \classord \mitfam {7D}
+
+
+% Large operations:
+
+\zmchar \bigcap \classlargeop \mexfam {54}
+\zmchar \bigcup \classlargeop \mexfam {53}
+\zmchar \bigodot \classlargeop \mexfam {4A}
+\zmchar \bigoplus \classlargeop \mexfam {4C}
+\zmchar \bigotimes \classlargeop \mexfam {4E}
+\zmchar \bigsqcup \classlargeop \mexfam {46}
+\zmchar \biguplus \classlargeop \mexfam {55}
+\zmchar \bigvee \classlargeop \mexfam {57}
+\zmchar \bigwedge \classlargeop \mexfam {56}
+\zmchar \coprod \classlargeop \mexfam {60}
+\zmchar \intop \classlargeop \mexfam {52}
+\zmchar \ointop \classlargeop \mexfam {48}
+\zmchar \prod \classlargeop \mexfam {51}
+\zmchar \smallint \classlargeop \msyfam {73}
+\zmchar \sum \classlargeop \mexfam {50}
+
+
+% Binary operations:
+
+\zmchar {`*} \classbinop \msyfam {03}
+\zmchar {`+} \classbinop \rmfam {2B}
+\zmchar {`-} \classbinop \msyfam {00}
+\zmchar \amalg \classbinop \msyfam {71}
+\zmchar \ast \classbinop \msyfam {03}
+\zmchar \bigcirc \classbinop \msyfam {0D}
+\zmchar \bigtriangledown \classbinop \msyfam {35}
+\zmchar \bigtriangleup \classbinop \msyfam {34}
+\zmchar \zmbullet \classbinop \msyfam {0F}
+\zmchar \cap \classbinop \msyfam {5C}
+\zmchar \cdot \classbinop \msyfam {01}
+\zmchar \circ \classbinop \msyfam {0E}
+\let \compose = \circ
+\zmchar \cup \classbinop \msyfam {5B}
+\zmchar \zmdagger \classbinop \msyfam {79}
+\zmchar \zmddagger \classbinop \msyfam {7A}
+\zmchar \diamond \classbinop \msyfam {05}
+\zmchar \div \classbinop \msyfam {04}
+\zmchar \mp \classbinop \msyfam {07}
+\zmchar \odot \classbinop \msyfam {0C}
+\zmchar \ominus \classbinop \msyfam {09}
+\zmchar \oplus \classbinop \msyfam {08}
+\zmchar \oslash \classbinop \msyfam {0B}
+\zmchar \otimes \classbinop \msyfam {0A}
+\zmchar \pm \classbinop \msyfam {06}
+\zmchar \setminus \classbinop \msyfam {6E}
+\zmchar \sqcap \classbinop \msyfam {75}
+\zmchar \sqcup \classbinop \msyfam {74}
+\zmchar \star \classbinop \mitfam {3F}
+\zmchar \times \classbinop \msyfam {02}
+\let \cross = \times
+\zmchar \triangleleft \classbinop \mitfam {2F}
+\zmchar \triangleright \classbinop \mitfam {2E}
+\zmchar \uplus \classbinop \msyfam {5D}
+\zmchar \vee \classbinop \msyfam {5F}
+\let \lor = \vee
+\zmchar \wedge \classbinop \msyfam {5E}
+\let \land = \wedge
+\zmchar \wr \classbinop \msyfam {6F}
+
+
+% Relations:
+
+\zmchar {`:} \classrel \rmfam {3A}
+\zmchar {`<} \classrel \mitfam {3C}
+\zmchar {`=} \classrel \rmfam {3D}
+\zmchar {`>} \classrel \mitfam {3E}
+\zmchar \approx \classrel \msyfam {19}
+\zmchar \asymp \classrel \msyfam {10}
+\zmchar \dashv \classrel \msyfam {61}
+\zmchar \equiv \classrel \msyfam {11}
+\zmchar \frown \classrel \mitfam {5F}
+\zmchar \geq \classrel \msyfam {15}
+\let \ge = \geq
+\let \gets = \leftarrow
+\zmchar \gg \classrel \msyfam {1D}
+\zmchar \in \classrel \msyfam {32}
+\zmchar \Leftarrow \classrel \msyfam {28}
+\zmchar \leftarrow \classrel \msyfam {20}
+\zmchar \leftharpoondown \classrel \mitfam {29}
+\zmchar \leftharpoonup \classrel \mitfam {28}
+\zmchar \Leftrightarrow \classrel \msyfam {2C}
+\zmchar \leftrightarrow \classrel \msyfam {24}
+\zmchar \leq \classrel \msyfam {14}
+\let \le = \leq
+\zmchar \lhook \classrel \mitfam {2C}
+\zmchar \ll \classrel \msyfam {1C}
+\zmchar \mapstochar \classrel \msyfam {37}
+\zmchar \mid \classrel \msyfam {6A}
+\let \given = \mid
+\zmchar \nearrow \classrel \msyfam {25}
+\zmchar \ni \classrel \msyfam {33}
+\zmchar \not \classrel \msyfam {36}
+\zmchar \nwarrow \classrel \msyfam {2D}
+\let \owns = \ni
+\zmchar \parallel \classrel \msyfam {6B}
+\zmchar \perp \classrel \msyfam {3F}
+\zmchar \prec \classrel \msyfam {1E}
+\zmchar \preceq \classrel \msyfam {16}
+\zmchar \propto \classrel \msyfam {2F}
+\zmchar \rhook \classrel \mitfam {2D}
+\zmchar \Rightarrow \classrel \msyfam {29}
+\zmchar \rightarrow \classrel \msyfam {21}
+\zmchar \rightharpoondown \classrel \mitfam {2B}
+\zmchar \rightharpoonup \classrel \mitfam {2A}
+\zmchar \searrow \classrel \msyfam {26}
+\zmchar \sim \classrel \msyfam {18}
+\zmchar \simeq \classrel \msyfam {27}
+\zmchar \smile \classrel \mitfam {5E}
+\zmchar \subset \classrel \msyfam {1A}
+\zmchar \subseteq \classrel \msyfam {12}
+\zmchar \succ \classrel \msyfam {1F}
+\zmchar \succeq \classrel \msyfam {17}
+\zmchar \supset \classrel \msyfam {1B}
+\zmchar \supseteq \classrel \msyfam {13}
+\zmchar \swarrow \classrel \msyfam {2E}
+\zmchar \sqsubseteq \classrel \msyfam {76}
+\zmchar \sqsupseteq \classrel \msyfam {77}
+\let \to = \rightarrow
+\zmchar \vdash \classrel \msyfam {60}
+
+
+% Openers:
+
+\zmchar {`(} \classopen \rmfam {28}
+\zmchar {`[} \classopen \rmfam {5B}
+\zmchar {`\{} \classopen \msyfam {66}
+
+
+% Closers:
+
+\zmchar {`!} \classclose \rmfam {21}
+\zmchar {`)} \classclose \rmfam {29}
+\zmchar {`?} \classclose \rmfam {3F}
+\zmchar {`]} \classclose \rmfam {5D}
+\zmchar {`\}} \classclose \msyfam {67}
+
+
+% Punctuation:
+
+\zmchar {`,} \classpunc \rmfam {2C}
+\zmchar {`;} \classpunc \rmfam {3B}
+\zmchar \cdotp \classpunc \msyfam {01}
+\zmchar \maps \classpunc \rmfam {3A}
+\let \colon = \maps
+\zmchar \ldotp \classpunc \mitfam {3A}
+
+
+% Active characters:
+
+\zmchar {` } \classactive \rmfam {00}
+\zmchar {`'} \classactive \rmfam {00}
+
+{\catcode`\' = \catactive
+\gdef '{^\bgroup \zmprima}
+} % \catcode
+
+\def \zmprima {\prime \futurelet\znext \zmprimb}
+\def \zmprimb {%
+ \if \tokeqlp{\znext}{'}%
+ \let \znext = \zmprimc
+ \else \if \tokeqlp{\znext}{^}%
+ \let \znext = \zmprimd
+ \else
+ \let \znext = \egroup
+ \fi\fi
+ \znext}
+\def \zmprimc #1{\zmprima}
+\def \zmprimd #1#2{#2\egroup}
+
+% Delimiters
+% ----------
+
+% IniTeX does the following for each character:
+%
+% \delcode`x = -1
+
+\definemathdelimiter{`(}{\classord}{\rmfam}{28}{\mexfam}{00}
+\definemathdelimiter{`)}{\classord}{\rmfam}{29}{\mexfam}{01}
+\definemathdelimiter{`/}{\classord}{\rmfam}{2F}{\mexfam}{0E}
+\definemathdelimiter{`<}{\classord}{\msyfam}{68}{\mexfam}{0A}
+\definemathdelimiter{`>}{\classord}{\msyfam}{69}{\mexfam}{0B}
+\definemathdelimiter{`[}{\classord}{\rmfam}{5B}{\mexfam}{02}
+\definemathdelimiter{`]}{\classord}{\rmfam}{5D}{\mexfam}{03}
+\definemathdelimiter{`|}{\classord}{\msyfam}{6A}{\mexfam}{0C}
+
+\definemathdelimiter{\Arrowvert}{\classord}{\mexfam}{3D}{\rmfam}{00}
+\definemathdelimiter{\arrowvert}{\classord}{\mexfam}{3C}{\rmfam}{00}
+\definemathdelimiter{\bracevert}{\classord}{\mexfam}{3E}{\rmfam}{00}
+\definemathdelimiter{\Downarrow}{\classrel}{\msyfam}{2B}{\mexfam}{7F}
+\definemathdelimiter{\downarrow}{\classrel}{\msyfam}{23}{\mexfam}{79}
+\definemathdelimiter{\langle}{\classopen}{\msyfam}{68}{\mexfam}{0A}
+\definemathdelimiter{\lceil}{\classopen}{\msyfam}{64}{\mexfam}{06}
+\definemathdelimiter{\lfloor}{\classopen}{\msyfam}{62}{\mexfam}{04}
+\definemathdelimiter{\lgroup}{\classopen}{\rmfam}{00}{\mexfam}{3A}
+\definemathdelimiter{\lmoustache}{\classopen}{\rmfam}{00}{\mexfam}{40}
+\definemathdelimiter{\rangle}{\classclose}{\msyfam}{69}{\mexfam}{0B}
+\definemathdelimiter{\rceil}{\classclose}{\msyfam}{65}{\mexfam}{07}
+\definemathdelimiter{\rfloor}{\classclose}{\msyfam}{63}{\mexfam}{05}
+\definemathdelimiter{\rgroup}{\classclose}{\rmfam}{00}{\mexfam}{3B}
+\definemathdelimiter{\rmoustache}{\classclose}{\rmfam}{00}{\mexfam}{41}
+\definemathdelimiter{\Uparrow}{\classrel}{\msyfam}{2A}{\mexfam}{7E}
+\definemathdelimiter{\uparrow}{\classrel}{\msyfam}{22}{\mexfam}{78}
+\definemathdelimiter{\Updownarrow}{\classrel}{\msyfam}{6D}{\mexfam}{77}
+\definemathdelimiter{\updownarrow}{\classrel}{\msyfam}{6C}{\mexfam}{3F}
+\definemathdelimiter{\Vert}{\classord}{\msyfam}{6B}{\mexfam}{0D}
+\definemathdelimiter{\vert}{\classord}{\msyfam}{6A}{\mexfam}{0C}
+\definemathdelimiter{\zmbackslash}{\classord}{\msyfam}{6E}{\mexfam}{0F}
+\definemathdelimiter{\zmlbrace}{\classopen}{\msyfam}{66}{\mexfam}{08}
+\definemathdelimiter{\zmrbrace}{\classclose}{\msyfam}{67}{\mexfam}{09}
+
+% Accents
+% -------
+
+
+\definemathaccent{\acute}{\classvarfam}{\rmfam}{13}
+\definemathaccent{\bar}{\classvarfam}{\rmfam}{16}
+\definemathaccent{\breve}{\classvarfam}{\rmfam}{15}
+\definemathaccent{\check}{\classvarfam}{\rmfam}{14}
+\definemathaccent{\ddot}{\classvarfam}{\rmfam}{7F}
+\definemathaccent{\dot}{\classvarfam}{\rmfam}{5F}
+\definemathaccent{\grave}{\classvarfam}{\rmfam}{12}
+\definemathaccent{\zmhat}{\classvarfam}{\rmfam}{5E}
+\definemathaccent{\zmtilde}{\classvarfam}{\rmfam}{7E}
+\definemathaccent{\ring}{\classvarfam}{\rmfam}{17}
+\definemathaccent{\widetilde}{\classord}{\mexfam}{65}
+\definemathaccent{\widehat}{\classord}{\mexfam}{62}
+\definemathaccent{\vec}{\classord}{\mitfam}{7E}
+
+\def \widebar #1{% {math} %~ Wide bar accent. %^math_accent
+ \mathpalette\zwidebar{#1}}
+
+\def \zwidebar #1#2{% {style}{math}
+ \rlap{\measuretextwidth{\tdimena}{$#1#2$}%
+ \kern .2\tdimena
+ $\overline{\vphantom{#1#2}\kern .6\tdimena}$}%
+ #2}
+
+% Defined Characters
+% ------- ----------
+
+
+\def \angle {%
+ {\vbox{\ialign{$\scriptstyle##$\cr
+ \not \mathrel{\mkern 14mu}\cr
+ \noalign{\nointerlineskip}%
+ \mkern 2.5mu \leaders \hrule height .34pt \hfill
+ \mkern 2.5mu\cr}}}}
+
+\definemathjoinedsymbol{\bowtie}{\mathrel}{\triangleright}{\triangleleft}{-3}
+
+\definemathstackedsymbol{\cong}{\mathrel}{\sim}{=}{6}
+
+\def \degree {^\circ}
+
+\let \degrees = \degree
+
+\def \defeq{%
+ \mathrel{\mathop{=}\limits^{\mathscriptscriptstyle{\roman{def}}}}}
+
+\definemathstackedsymbol{\Deltaeq}{\mathrel}{\mathscriptscriptstyle{\Delta}}{=}{9}
+
+\definemathstackedsymbol{\doteq}{\mathrel}{.}{=}{9}
+
+\definemathstackedsymbol{\gel}{\mathrel}{\zge}{<}{11}
+
+\definemathstackedsymbol{\zge}{\mathrel}{>}{=}{7.5}
+
+\definemathstackedsymbol{\gl}{\mathrel}{>}{<}{5.5}
+
+\def \hbar {\mathord{h \llap{$\mathchar"16 \mkern 3.5mu$}}}
+
+\definemathjoinedsymbol{\hookleftarrow}{\mathrel}{\leftarrow}{\rhook}{-3}
+
+\definemathjoinedsymbol{\hookrightarrow}{\mathrel}{\lhook}{\rightarrow}{-3}
+
+\def \int {\intop\nolimits}
+
+\def \iint {\zint2}
+
+\def \iiint {\zint3}
+
+\def \iiiint {\zint4}
+
+\def \idotsint {\zint0}
+
+\def \zint #1{%
+ \mkern -9mu \mathchoice{\mkern -5mu}{}{}{}%
+ \mathop{%
+ \mkern 9mu \mathchoice{\mkern 5mu}{}{}{}%
+ \intop
+ \ifcase #1%
+ \mkern -4mu \cdots \mkern -4mu
+ \or \relax \or
+ \zintkern
+ \or
+ \zintkern \intop \zintkern
+ \or
+ \zintkern \intop \zintkern \intop \zintkern
+ \fi}%
+ \intop\nolimits}
+
+\def \zintkern {\mkern -8mu \mathchoice{\mkern -3mu}{}{}{}}
+
+\let \join = \bowtie
+
+\definemathstackedsymbol{\leftrightarrows}{\mathrel}{\leftarrow}{\rightarrow}{6}
+
+\definemathstackedsymbol{\leftrightharpoons}{\mathrel}{\leftharpoonup}{\rightharpoondown}{4}
+
+\definemathstackedsymbol{\ltgt}{\mathrel}{<}{>}{5.5}
+
+\definemathjoinedsymbol{\Longleftarrow}{\mathrel}{\Leftarrow}{\Relbar}{-3}
+
+\definemathjoinedsymbol{\longleftarrow}{\mathrel}{\leftarrow}{\relbar}{-3}
+
+\definemathjoinedsymbol{\Longleftrightarrow}{\mathrel}{\Leftarrow}{\Rightarrow}{-3}
+\let \iff = \Longleftrightarrow
+
+\definemathjoinedsymbol{\longleftrightarrow}{\mathrel}{\leftarrow}{\rightarrow}{-3}
+
+\def \longmapsto {\mapstochar \longrightarrow}
+
+\definemathjoinedsymbol{\Longrightarrow}{\mathrel}{\Relbar}{\Rightarrow}{-3}
+
+\definemathjoinedsymbol{\longrightarrow}{\mathrel}{\relbar}{\rightarrow}{-3}
+
+\definemathjoinedsymbol{\longrightleftarrow}{\mathrel}{\rightarrow}{\leftarrow}{-3}
+
+\def \oint {\ointop\nolimits}
+
+\def \mapsto {\mapstochar \rightarrow}
+
+\definemathjoinedsymbol{\models}{\mathrel}{|}{=}{-3}
+
+\def \neq {\not=}
+\let \ne = \neq
+
+\def \nexists {\mathord{\raise .2ex \hbox{$\not\mkern 1.5mu$}\exists}}
+
+\def \notin {\not\in}
+\let \nin = \notin
+
+\def \nparallel {\mathrel{\not\mkern 2mu\parallel}}
+
+\definemathstackedsymbol{\rightleftarrows}{\mathrel}{\rightarrow}{\leftarrow}{6}
+
+\definemathstackedsymbol{\rightleftharpoons}{\mathrel}{\rightharpoonup}{\leftharpoondown}{4}
+
+\definemathjoinedsymbol{\semijoin}{\mathrel}{\triangleright}{<}{-4}
+
+% Functions
+% ---------
+
+
+\def \definemathfunction #1#2#3{% {\name}{text}{limits}
+ \def #1{\mathop{\zmfunstyle #2}#3}}
+
+\definemathfunction{\ad}{ad}{\nolimits} % adjoint
+\definemathfunction{\Ai}{Ai}{\nolimits} % Airy function
+\definemathfunction{\arccos}{arccos}{\nolimits} % arc cosine
+\definemathfunction{\arccosh}{arccosh}{\nolimits} % hyperbolic arc cosine
+\definemathfunction{\arccot}{arccot}{\nolimits} % arc cotangent
+\definemathfunction{\arcsec}{arcsec}{\nolimits} % arc secant
+\definemathfunction{\arcsin}{arcsin}{\nolimits} % arc sine
+\definemathfunction{\arctan}{arctan}{\nolimits} % arc tangent
+\definemathfunction{\arg}{arg}{\nolimits} % argument
+\definemathfunction{\argmax}{arg\,max}{\displaylimits} % argument maximum
+\definemathfunction{\argmin}{arg\,min}{\displaylimits} % argument maximum
+\definemathfunction{\Bd}{Bd}{\nolimits} % Bound
+\definemathfunction{\cl}{cl}{\nolimits} % closure
+\definemathfunction{\codim}{codim}{\nolimits} % co-dimension
+\definemathfunction{\coker}{coker}{\nolimits} % cokernel
+\definemathfunction{\conj}{conj}{\nolimits} % conjugate
+\definemathfunction{\cos}{cos}{\nolimits} % cosine
+\definemathfunction{\cosec}{cos}{\nolimits} % cosecant
+\definemathfunction{\cosh}{cosh}{\nolimits} % hyperbolic cosine
+\definemathfunction{\cot}{cot}{\nolimits} % cotangent
+\definemathfunction{\coth}{coth}{\nolimits} % hyperbolic cotangent
+\definemathfunction{\csc}{csc}{\nolimits} % cosecant
+\definemathfunction{\csch}{csch}{\nolimits} % hyperbolic cosecant
+\definemathfunction{\curl}{curl}{\nolimits} % curl
+\definemathfunction{\deg}{deg}{\nolimits} % degree
+\definemathfunction{\det}{det}{\displaylimits} % determinant
+\definemathfunction{\diag}{diag}{\nolimits} % diagonal
+\definemathfunction{\dim}{dim}{\nolimits} % dimension
+\definemathfunction{\dist}{dist}{\nolimits} % distance
+\definemathfunction{\erf}{erf}{\nolimits} % error function
+\definemathfunction{\erfc}{erfc}{\nolimits} % error function comp.
+\definemathfunction{\exp}{exp}{\nolimits} % exponential
+\definemathfunction{\gcd}{gcd}{\displaylimits} % greatest common div.
+\definemathfunction{\GL}{GL}{\nolimits} % General Linear
+\definemathfunction{\glb}{glb}{\nolimits} % greatest lower bound
+\definemathfunction{\gr}{gr}{\nolimits} % group
+\definemathfunction{\grad}{grad}{\nolimits} % gradient
+\definemathfunction{\hom}{hom}{\nolimits} % homology
+\definemathfunction{\id}{id}{\nolimits} % identity
+\definemathfunction{\inf}{inf}{\displaylimits} % infinum
+\definemathfunction{\injlim}{inj\,lim}{\displaylimits} % injected limit
+\definemathfunction{\ker}{ker}{\nolimits} % kernel
+\definemathfunction{\lcm}{lcm}{\displaylimits} % least common mult.
+\definemathfunction{\length}{length}{\nolimits} % length
+\definemathfunction{\lg}{lg}{\nolimits} % natural logarithm
+\definemathfunction{\lim}{lim}{\displaylimits} % limit
+\definemathfunction{\liminf}{lim\,inf}{\displaylimits} % limit infinum
+\definemathfunction{\limsup}{lim\,sup}{\displaylimits} % limit supremum
+\definemathfunction{\ln}{ln}{\nolimits} % natural logarithm
+\definemathfunction{\Log}{Log}{\nolimits} % principal logarithm
+\definemathfunction{\log}{log}{\nolimits} % logarithm
+\definemathfunction{\lub}{lub}{\nolimits} % least upper bound
+\definemathfunction{\max}{max}{\displaylimits} % maximum
+\definemathfunction{\min}{min}{\displaylimits} % minimum
+\definemathfunction{\mod}{mod}{\nolimits} % modulus
+\definemathfunction{\Pr}{Pr}{\displaylimits} % Probability
+\definemathfunction{\Prob}{Prob}{\displaylimits} % Probability
+\definemathfunction{\projlim}{proj\,lim}{\displaylimits}% projected limit
+\definemathfunction{\rank}{rank}{\nolimits} % rank
+\definemathfunction{\sec}{sec}{\nolimits} % secant
+\definemathfunction{\sech}{sech}{\nolimits} % hyperbolic secant
+\definemathfunction{\sgn}{sgn}{\nolimits} % sign
+\definemathfunction{\sign}{sign}{\nolimits} % sign
+\definemathfunction{\sin}{sin}{\nolimits} % sine
+\definemathfunction{\sinc}{sinc}{\nolimits} % cardinal sine
+\definemathfunction{\sinh}{sinh}{\nolimits} % hyperbolic sine
+\definemathfunction{\SL}{SL}{\nolimits} % Special Linear
+\definemathfunction{\sup}{sup}{\displaylimits} % supremum
+\definemathfunction{\Szg}{Sz(g)}{\nolimits} % Suzuki group
+\definemathfunction{\tan}{tan}{\nolimits} % tangent
+\definemathfunction{\tanh}{tanh}{\nolimits} % hyperbolic tangent
+\definemathfunction{\tr}{tr}{\nolimits} % trace
+\definemathfunction{\trace}{trace}{\nolimits} % trace
+\definemathfunction{\wstar}{w*}{\nolimits} % weak star
+
+
+% For the occasional one-timer:
+
+\def \mathfunction #1{\mathop{\rm #1}\nolimits}
+
+\let \mfun = \mathfunction
+
+% Display/Text/Script Styles
+% ------------------- ------
+
+
+\def \mathdisplaystyle #1{{\displaystyle #1}}% {subequation}
+\def \mathtextstyle #1{{\textstyle #1}}
+\def \mathscriptstyle #1{{\scriptstyle #1}}
+\def \mathscriptscriptstyle #1{{\scriptscriptstyle #1}}
+
+\def \mathpalette #1#2{% {\macro}{text}
+ \mathchoice{#1\displaystyle{#2}}%
+ {#1\textstyle{#2}}%
+ {#1\scriptstyle{#2}}%
+ {#1\scriptscriptstyle{#2}}}
+
+\def \mtext #1{%
+ {\mathchoice{\hbox{\zmtextstyle #1}}
+ {\hbox{\zmtextstyle #1}}
+ {\hbox{\the\scriptfont\zmtextfam #1}}
+ {\hbox{\the\scriptscriptfont\zmtextfam #1}}}}
+
+\everymath = {\let\text=\mtext}%
+
+% This is specifically designed to work in math or in text.
+
+\def \mvar #1{{\zmvarstyle #1\if \textmodep \/\fi}}% {text}
+
+% General Tools
+% ------- -----
+
+
+\def \aboverule #1{\above #1\relax}% {rule-height}
+
+\def \abs #1{\left|#1\right|}% {expression}
+
+\def \big #1{{\hbox{$\left#1\vbox to 8.5pt{}\right.\zmnosp$}}}
+\def \Big #1{{\hbox{$\left#1\vbox to 11.5pt{}\right.\zmnosp$}}}
+\def \bigg #1{{\hbox{$\left#1\vbox to 14.5pt{}\right.\zmnosp$}}}
+\def \Bigg #1{{\hbox{$\left#1\vbox to 17.5pt{}\right.\zmnosp$}}}
+\def \zmnosp {\nulldelimiterspace = 0pt}
+
+\def \bigl {\mathopen\big}
+\def \Bigl {\mathopen\Big}
+\def \bigm {\mathrel\big}
+\def \Bigm {\mathrel\Big}
+\def \bigr {\mathclose\big}
+\def \Bigr {\mathclose\Big}
+\def \biggl {\mathopen\bigg}
+\def \Biggl {\mathopen\Bigg}
+\def \biggm {\mathrel\bigg}
+\def \Biggm {\mathrel\Bigg}
+\def \biggr {\mathclose\bigg}
+\def \Biggr {\mathclose\Bigg}
+
+\def \binomial #1#2{{{#1} \atopwithdelims() {#2}}}
+
+\let \binom = \binomial
+
+\def \bmod {\mathbin{\rm mod}}
+
+\def \bordermatrix #1{%
+ {\setbox \zboxa = \hbox{\mex B}%
+ \tdimena = \wd\zboxa
+ \setbox \zboxa = \vbox{%
+ \def \cr {\crcr \noalign{\kern 0pt \global\let \cr = \completerow}}%
+ \ialign{$##$\hfil \kern 2pt \kern \tdimena&
+ \thinspace \hfil $##$\hfil&&
+ \quad \hfil $##$\hfil \crcr
+ \omit \strut \hfil \crcr
+ \noalign{\kern -\baselineskip}%
+ #1\crcr
+ \omit \strut \cr}}%
+ \setbox \zboxc = \vbox{%
+ \unvcopy \zboxa \global\setbox \zboxb = \lastbox}%
+ \setbox \zboxc = \hbox{%
+ \unhbox \zboxb \unskip \global\setbox \zboxb = \lastbox}%
+ \setbox \zboxc = \hbox{%
+ $\kern \wd\zboxb \kern -\tdimena \left(\kern -\wd\zboxb
+ \global\setbox \zboxb = \vbox{\box\zboxb \kern 8pt}%
+ \vcenter{\kern -\ht\zboxb \unvbox\zboxa \kern -\baselineskip}\,%
+ \right)$}%
+ \null\;\vbox{\kern \ht\zboxb \box\zboxc}}}
+
+\def \brace {\atopwithdelims\{\}}
+
+\def \bracematrix #1{% {row...}
+ \left\{ \matrix{#1} \right\}}
+
+\def \brack {\atopwithdelims[]}
+
+\def \bracketmatrix #1{% {row...}
+ \left[ \matrix{#1} \right]}
+
+\def \bracketmatrixfl #1{% {row...}
+ \left[ \matrixfl{#1} \right]}
+
+\def \bracketmatrixfr #1{% {row...}
+ \left[ \matrixfr{#1} \right]}
+
+\def \cases #1{% {row...}
+ \left\{ \,%
+ \vcenter{\matrixbaselines
+ \ialign{$##$\hfil&
+ \quad {\rm ##}\hfil \crcr
+ #1\crcr}}%
+ \right.}
+
+% This version of \cases has math in both columns.
+
+\def \mcases #1{% {row...}
+ \left\{ \,%
+ \vcenter{\matrixbaselines
+ \ialign{$##$\hfil&
+ \quad $##$\hfil \crcr
+ #1\crcr}}%
+ \right.}
+
+\def \cdots {\mathinner{\cdotp\cdotp\cdotp}}
+
+\def \ddots {%
+ \if \newdots
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}
+ \hbox{\kern .4em .}
+ \hbox{\kern .8em .}}%
+ \else
+ \mathinner{\mkern 1mu \raise 7pt \vbox{\kern 7pt \hbox{.}}%
+ \mkern 2mu \raise 4pt \hbox{.}%
+ \mkern 2mu \raise 1pt \hbox{.}%
+ \mkern 1mu}%
+ \fi}
+
+\def \detmatrix #1{% {row...}
+ \left| \matrix{#1} \right|}
+
+\def \displayfrac #1#2{% {numerator}{denominator}
+ {\displaystyle \frac{#1}{#2}}}
+
+\def \displaylines #1{% {row...}
+ \openup \jot
+ \global\setflag \zdtop = \true
+ \everycr = {\noalign{\if \zdtop
+ \vskip -\lineskiplimit
+ \vskip \normallineskiplimit
+ \global\setflag \zdtop = \false
+ \else
+ \penalty \interdisplaylinepenalty
+ \fi}}%
+ \halign{\hbox to \displaywidth{$\tabskip = 0pt \everycr = {}%
+ \hfil \displaystyle ##\hfil$}\cr
+ #1\crcr}}
+
+\def \eqalign #1{% {row...}
+ \vcenter{%
+ \ialign{&\mathstrut \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil\cr
+ #1\crcr}}}
+
+\def \equalfill {%
+ $\mathord =\mkern -6mu
+ \cleaders \hbox{$\mkern -2mu \mathord =\mkern -2mu$}\hfill
+ \mkern -6mu \mathord =$}
+
+% All other fraction macros should use \frac.
+
+\def \frac #1#2{% {numerator}{denominator}
+ {{\mskip\fracbarhang #1\mskip\fracbarhang} \over
+ {\mskip\fracbarhang #2\mskip\fracbarhang}}}
+
+\def \fromunder #1{% {math}
+ \mathrel{\mathop{\longleftarrow}\limits^{#1}}}
+
+\def \hphantom {%
+ \setflag \zhphant = \true
+ \setflag \zvphant = \false
+ \zphanta}
+
+\def \joinrel {\mathrel{\mkern -3mu}}
+
+\def \largefrac #1#2{% {numerator}{denominator}
+ {\mathchoice{\mathdisplaystyle{\frac{#1}{#2}}}
+ {\mathdisplaystyle{\frac{#1}{#2}}}
+ {\mathtextstyle{\frac{#1}{#2}}}
+ {\mathscriptstyle{\frac{#1}{#2}}}}}
+
+\def \ldots {\mathinner{\ldotp\ldotp\ldotp}}
+
+\def \leftarrowfill {\zleftarrowfill{\textstyle}}
+\def \leftrightarrowfill {\zleftrightarrowfill{\textstyle}}
+\def \rightarrowfill {\zrightarrowfill{\textstyle}}
+\def \Rightarrowfill {\zRightarrowfill{\textstyle}}
+
+\def \zleftarrowfill #1{% {style}
+ \setbox\zboxa = \hbox{$#1-$}%
+ \ht\zboxa = 0pt
+ $#1\mathord\leftarrow \mkern -6mu
+ \cleaders \hbox{$#1\mkern -2mu \copy\zboxa \mkern -2mu$}\hfill
+ \mkern -6mu \box\zboxa$}
+
+\def \zleftrightarrowfill #1{% {style}
+ \setbox\zboxa = \hbox{$#1-$}%
+ \ht\zboxa = 0pt
+ $#1\mathord\leftarrow \mkern -6mu
+ \cleaders \hbox{$#1\mkern -2mu \box\zboxa \mkern -2mu$}\hfill
+ \mkern -6mu \mathord\rightarrow$}
+
+\def \zRightarrowfill #1{% {style}
+ \setbox\zboxa = \hbox{$#1=$}%
+ \ht\zboxa = 0pt
+ $#1\copy\zboxa \mkern -6mu
+ \cleaders \hbox{$#1\mkern -2mu \box\zboxa \mkern -2mu$}\hfill
+ \mkern -6mu \mathord\Rightarrow$}
+
+\def \zrightarrowfill #1{% {style}
+ \setbox\zboxa = \hbox{$#1-$}%
+ \ht\zboxa = 0pt
+ $#1\copy\zboxa \mkern -6mu
+ \cleaders \hbox{$#1\mkern -2mu \box\zboxa \mkern -2mu$}\hfill
+ \mkern -6mu \mathord\rightarrow$}
+
+\let \leqalignno = \eqalignno
+
+\def \mathstrut {\vphantom(}
+
+\def \matrix #1{% {row...}
+ \null\nonscript\,%
+ \vcenter{\matrixbaselines
+ \ialign{\hfil $##$\hfil&& \quad \hfil $##$\hfil \crcr
+ \mathstrut\crcr
+ \noalign{\kern -\baselineskip}%
+ #1\crcr
+ \mathstrut\crcr
+ \noalign{\kern -\baselineskip}}}%
+ \nonscript\,}
+
+\let \adjustmatrix = \noalign
+
+\def \matrixfl #1{% {row...}
+ \null\nonscript\,%
+ \vcenter{\matrixbaselines
+ \ialign{$##$\hfil && \quad $##$\hfil \crcr
+ \mathstrut\crcr
+ \noalign{\kern -\baselineskip}%
+ #1\crcr
+ \mathstrut\crcr
+ \noalign{\kern -\baselineskip}}}%
+ \nonscript\,}
+
+\def \matrixfr #1{% {row...}
+ \null\nonscript\,%
+ \vcenter{\matrixbaselines
+ \ialign{\hfil $##$&& \quad \hfil $##$\crcr
+ \mathstrut\crcr
+ \noalign{\kern -\baselineskip}%
+ #1\crcr
+ \mathstrut\crcr
+ \noalign{\kern -\baselineskip}}}%
+ \nonscript\,}
+
+\def \matrixbaselines {%
+ \baselineskip = \the\matrixspread\normalbaselineskip
+ \lineskiplimit = \normallineskiplimit
+ \lineskip = \normallineskip}
+
+\def \ontopof #1#2{{{#1} \atop {#2}}}% {numerator}{denominator}
+
+\def \openup {\afterassignment\zopenup \tdimena=}
+
+\def \zopenup {%
+ \advance \baselineskip by \tdimena
+ \advance \lineskiplimit by \tdimena
+ \advance \lineskip by \tdimena}
+
+\def \overbrace #1{%
+ \mathop{%
+ \vbox{\ialign{##\cr
+ \noalign{\kern 3pt}%
+ \downbracefill\cr
+ \noalign{\kern 3pt \nointerlineskip}%
+ $\hfil \displaystyle{#1}\hfil$\cr}}}\limits}
+
+\def \overleftarrow {\mathpalette\zoverleftarrow}
+\def \overleftrightarrow {\mathpalette\zoverleftrightarrow}
+\def \overRightarrow {\mathpalette\zoverRightarrow}
+\def \overrightarrow {\mathpalette\zoverrightarrow}
+
+\def \zoverleftarrow #1#2{% {style}{math}
+ \vbox{\ialign{##\cr
+ \zleftarrowfill{\scriptscriptstyle}\cr
+ \noalign{\nointerlineskip}%
+ $\hfil #1#2\hfil$\crcr}}}
+
+\def \zoverleftrightarrow #1#2{% {style}{math}
+ \vbox{\ialign{##\cr
+ \zleftrightarrowfill{\scriptscriptstyle}\cr
+ \noalign{\nointerlineskip}%
+ $\hfil #1#2\hfil$\crcr}}}
+
+\def \zoverRightarrow #1#2{% {style}{math}
+ \vbox{\ialign{##\cr
+ \zRightarrowfill{\scriptscriptstyle}\cr
+ \noalign{\nointerlineskip}%
+ $\hfil #1#2\hfil$\crcr}}}
+
+\def \zoverrightarrow #1#2{% {style}{math}
+ \vbox{\ialign{##\cr
+ \zrightarrowfill{\scriptscriptstyle}\cr
+ \noalign{\nointerlineskip}%
+ $\hfil #1#2\hfil$\crcr}}}
+
+\def \overset #1#2{
+ \mathbin{\mathop{#2}\limits^{#1}}}
+
+\def \parenmatrix #1{% {row...}
+ \left( \matrix{#1} \right)}
+
+\let \pmatrix = \parenmatrix
+
+\def \parenmatrixfl #1{% {row...}
+ \left( \matrixfl{#1} \right)}
+
+\def \parenmatrixfr #1{% {row...}
+ \left( \matrixfr{#1} \right)}
+
+\def \phantom {%
+ \setflag \zhphant = \true
+ \setflag \zvphant = \true
+ \zphanta}
+
+\def \zphanta {%
+ \if \mathmodep
+ \def \znext {\mathpalette\zphantb}%
+ \else
+ \let \znext = \zphantc
+ \fi
+ \znext}
+\def \zphantb #1#2{%
+ \setbox \zboxa = \hbox{$#1{#2}$}%
+ \zphantd}
+\def \zphantc #1{%
+ \setbox \zboxa = \hbox{#1}%
+ \zphantd}
+\def \zphantd {%
+ \setbox \zboxb = \hbox{}%
+ \if \zhphant \wd\zboxb = \wd\zboxa \fi
+ \if \zvphant \ht\zboxb = \ht\zboxa \dp\zboxb = \dp\zboxa \fi
+ \box \zboxb}
+
+\def \plainTeXmathdisplay {%
+ \global\everydisplay = {}}
+
+\def \pmod #1{\allowbreak \,({\rm mod}\,#1)}
+
+\def \Relbar {\mathrel =}
+\def \relbar {\mathrel{\smash -}}
+
+\definebox{\zrootbox}
+
+\def \nthroot #1{% {n}
+ \setbox\zrootbox = \hbox{$\scriptscriptstyle{#1}$}%
+ \mathpalette\zroot}
+
+\def \zroot #1#2{% {\style}{radicand}
+ \setbox\zboxa = \hbox{$#1\sqrt{#2}$}%
+ \tdimena = \ht\zboxa
+ \advance \tdimena by -\dp\zboxa
+ \mkern 5mu \raise .6\tdimena \copy\zrootbox \mkern -10mu \box\zboxa}
+
+\def \skew #1#2#3{% {amount}{accent}{char}
+ {\zmuskipa = #1mu
+ \divide \zmuskipa by 2
+ \mkern \zmuskipa
+ #2{\mkern -\zmuskipa{#3}\mkern \zmuskipa}%
+ \mkern -\zmuskipa}{}}
+
+\def \smallfrac #1#2{% {numerator}{denominator}
+ {\mathchoice{\mathtextstyle{\frac{#1}{#2}}}
+ {\mathscriptstyle{\frac{#1}{#2}}}
+ {\mathscriptscriptstyle{\frac{#1}{#2}}}
+ {\mathscriptscriptstyle{\frac{#1}{#2}}}}}
+
+\def \smash {%
+ \relax
+ \if \mathmodep
+ \def \znext {\mathpalette\zsmasha}%
+ \else
+ \let \znext = \zsmashb
+ \fi
+ \znext}
+
+\def \zsmasha #1#2{%
+ \setbox \zboxa = \hbox{$#1{#2}$}%
+ \zsmashc}
+\def \zsmashb #1{%
+ \setbox \zboxa = \hbox{#1}%
+ \zsmashc}
+\def \zsmashc {%
+ \ht\zboxa = 0pt
+ \dp\zboxa = 0pt
+ \box \zboxa}
+
+\def \sqrt {\radical"270370 }
+
+\let \sub = _
+\let \super = ^
+
+\def \Tounder #1{% {math}
+ \mathrel{\mathop{\Longrightarrow}\limits^{#1}}}
+
+\def \tounder #1{% {math}
+ \mathrel{\mathop{\longrightarrow}\limits^{#1}}}
+
+\def \underbrace #1{% {text}
+ \mathop{%
+ \vtop{\ialign{##\cr
+ $\hfil \displaystyle{#1}\hfil$\cr
+ \noalign{\kern 3pt \nointerlineskip}%
+ \upbracefill\cr
+ \noalign{\kern 3pt}}}}\limits}
+
+\def \underset #1#2{
+ \mathbin{\mathop{#2}\limits_{#1}}}
+
+\def \unit #1{% {text}
+ \if \mathmodep
+ {\nonscript\,\mtext{#1}}%
+ \else
+ \,#1%
+ \fi}
+
+\def \vdots {%
+ \if \newdots
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}
+ \hbox{.}
+ \hbox{.}}%
+ \else
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \kern 6pt
+ \hbox{.}
+ \hbox{.}
+ \hbox{.}}%
+ \fi}
+
+\def \vphantom {%
+ \setflag \zhphant = \false
+ \setflag \zvphant = \true
+ \zphanta}
+
+% Block Matrices
+% ----- --------
+
+
+\def \blockmatrix #1{% {rows}
+ \zblockmatrix{\false}{#1}}
+
+\def \blockmatrixvr #1{% {rows}
+ \zblockmatrix{\true}{#1}}
+
+\def \zblockmatrix #1#2{% {verticals?}{rows}
+ \left[
+ \vcenter{%
+ \defineatsigncommand @R{\colrule}%
+ \defineatsigncommand @N{\nocolrule}%
+ \offinterlineskip
+ \tdimena = \ht\strutbox \advance \tdimena by .2ex
+ \tdimenb = \dp\strutbox \advance \tdimenb by .4ex
+ \setbox \strutbox \hbox{\vrule width 0pt height \tdimena depth \tdimenb}%
+ \ialign{\hfil \strut \thirdspace $##$\thirdspace \hfil&&
+ \hspace{.35em}%
+ \vrule \if #1\colrule \else \nocolrule \fi
+ ##\relax
+ \hspace{.35em}&
+ \hfil \strut \thirdspace $##$\thirdspace \hfil\crcr
+ #2\crcr}}%
+ \right]}
+
+\def \rowrule {%
+ \noalign{%
+ \vskip .5ex
+ \hrule height .1ex\relax
+ \vskip .7ex}}
+
+\def \colrule {%
+ width .1ex }
+
+% Math Displays
+% ---- --------
+
+
+\defineblock{\mathdisplay}{\endmathdisplay}{\true}{}
+
+%~block mathdisplay
+% \abovepenalty = integer % Penalty above display.
+% \aboveskip = glue % Visual space above display.
+% \belowpenalty = integer % Penalty below display.
+% \belowskip = glue % Visual space below display.
+% \bodyfont = {...} % Font for display.
+% \def \comptextformat {...} % Composite number text formatter.
+% \diagramdiagarrowstyle = {...} % Style for diagonal arrows in diagrams.
+% \diagramgutter = dimen % Gutter between diagram columns.
+% \diagraminterrowskip = glue % Interrowskip for diagrams.
+% \diagramminarrow = dimen % Minimum length of arrow in diagram.
+% \hfuzz = dimen % Overhang allowed at end of line.
+% \interrowskip = glue % Extra visual space between equations.
+% \leftindent = dimen % Left indentation for \alignleft.
+% \matrixspread = {decimal} % Spread factor for matrices.
+% \def \numberformat {...} % Equation number formatter.
+% \position = {...} % Positioning options.
+% \rightindent = dimen % Right indentation for \alignright.
+% \textcolor = {...} % Color of text.
+%~end
+
+\definetoks{\diagramdiagarrowstyle}
+\definedimen{\diagramgutter}{0pt}
+\defineskip{\diagraminterrowskip}{0pt}
+\definedimen{\diagramminarrow}{0pt}
+
+% Positioning options are:
+% \alignleft Left aligned, with \leftindent.
+% \alignright Right aligned, with \rightindent.
+% \center Centered.
+% \numberleft Equation number on left.
+% \numberright Equation number on right.
+
+% These parameters are calculated:
+
+\definetoks{\mathdisplayeqno} % Text following \eqno marker.
+\definecount{\mathdisplayprevgraf}{-1} % Previous display's ending \prevgraf.
+\definecount{\mathdisplayprevpenalty}{0}% Previous display's \belowpenalty.
+\defineskip{\mathdisplayprevskip}{0pt} % Previous display's \belowskip.
+
+\declareeverypar{\global\mathdisplayprevgraf=-1}
+\zdeclareeveryvcontext{\zsavevcontext{\mathdisplayprevgraf=-1}}
+
+%~ This marker specifies that the following text is the equation number
+%~ for the math display.
+
+\definemarker{\eqno}
+
+
+\everydisplay = {\mathdisplay}
+
+\def \mathdisplay #1$${% equation $$
+ \advance \displayindent by \leftskip
+ \advance \displaywidth by -\leftskip
+ \advance \displaywidth by -\rightskip
+ % \beginblockscope is unnecessary.
+ \global\increment \mathdisplaydepth
+ \abovepenalty = 5000 %~default hard
+ \belowpenalty = \breakallowed %~default hard
+ \hfuzz = 1pt %~default hard
+ \leftindent = 0pt %~default soft
+ \matrixspread = {1.0} %~default soft
+ \rightindent = 0pt %~default soft
+ \textcolor = {}% %~default soft
+ \processdesign{\mathdisplay}{}%
+ % \mathdisplaynumber is incremented by \eqno, if appropriate.
+ \if \eqlp{\prevgraf}{\mathdisplayprevgraf}%
+ \aboveskip = -\belowskip
+ \advance \aboveskip by \interrowskip
+ \fi
+ \let \text = \mtext
+ \zmdparams
+ \settaginfo{}{}% % No tag info so far.
+ \if \notp{\emptytoksp{\textcolor}}\color{\the\textcolor}\fi
+ \mathdisplayformat{#1}%
+ \endmathdisplay}
+
+\def \endmathdisplay {%
+ \global\mathdisplayprevgraf = \prevgraf
+ \global\advance \mathdisplayprevgraf by 3
+ \global\mathdisplayprevpenalty = \belowpenalty
+ \global\mathdisplayprevskip = \belowskip
+ \global\decrement \mathdisplaydepth
+ \if \notp{\emptytoksp{\textcolor}}\endcolor \fi%
+ % \endblockscope is unnecessary.
+ $$}
+
+\definecount{\zmdhpos}{0}
+
+\def \zmdparams {%
+ \abovedisplayskip = \aboveskip
+ \abovedisplayshortskip = \aboveskip
+ \belowdisplayskip = \belowskip
+ \belowdisplayshortskip = \belowskip
+ \predisplaypenalty = \abovepenalty
+ \postdisplaypenalty = \belowpenalty
+ \zmdhpos = 0
+ \let \center = \relax
+ \def \alignleft {\zmdhpos = 1}%
+ \def \alignright {\zmdhpos = 2}%
+ \setflag \zmdnumleft = \false
+ \def \numberleft {\setflag \zmdnumleft = \true}%
+ \let \numberright = \relax
+ \the\position}
+
+\def \mathdisplayformat #1{% {display}
+ \the\bodyfont
+ \zmdparse#1\eqno\eqno\zmark
+ {\lineskiplimit = \maxdimen % Force \interrowskip between
+ \lineskip = \interrowskip % each row of multi-line display.
+ \ifcase \zmdhpos
+ \if \zmdnumleft % Centered display.
+ \hbox to \displaywidth {%
+ \rlap{\hspace{-1\leftskip}\zmdeqno}%
+ \hfil $\displaystyle \zmdeq$\hfil}%
+ \else
+ \hbox to \displaywidth {%
+ \hfil $\displaystyle \zmdeq$\hfil
+ \llap{\zmdeqno\hspace{-1\rightskip}}}%
+ \fi
+ \or
+ \if \zmdnumleft % Left-aligned display.
+ \hbox to \displaywidth {%
+ \hbox to \leftindent{\hspace{-1\leftskip}\zmdeqno\hss}%
+ $\displaystyle \zmdeq$\hfil}%
+ \else
+ \hbox to \displaywidth{%
+ \kern \leftindent $\displaystyle \zmdeq$\hfil
+ \llap{\zmdeqno\hspace{-1\rightskip}}}%
+ \fi
+ \or
+ \if \zmdnumleft % Right-aligned display.
+ \hbox to \displaywidth {%
+ \rlap{\hspace{-1\leftskip}\zmdeqno}%
+ \hfil $\displaystyle \zmdeq$\kern \rightindent}%
+ \else
+ \hbox to \displaywidth{%
+ \hfil $\displaystyle \zmdeq$%
+ \hbox to \rightindent{\hss\zmdeqno\hspace{-1\rightskip}}}%
+ \fi
+ \fi}}
+
+\def \zmdparse #1\eqno#2\eqno#3\zmark{% equation\eqno number\eqno ???\zmark
+ \def \zmdeq {#1}%
+ \if \andp{\emptyargp{#2}}{\emptyargp{#3}}%
+ \let \zmdeqno = \relax
+ \else
+ \def \zmdeqno {\zmdformeqno#2\tag\tag\zmark}%
+ \fi}
+
+% This macro is invoked to format equation numbers in both positions:
+% at the end of the display and at the end of \eqaligned rows.
+
+\def \zmdformeqno #1\tag#2\tag#3\zmark{% number\tag{xxx}\tag ???\zmark
+ \if \emptyargp{#1}%
+ \global\increment \mathdisplaynumber
+ \mathdisplayeqno = \expandafter{\number\mathdisplaynumber}%
+ \setcomptext{\mathdisplaycomptext}%
+ \else
+ \zmdexpliciteqno #1 \zmark
+ \fi
+ \settaginfo{\the\mathdisplaycomptext}{???}%
+ \hbox{\numberformat}%
+ \if \notp{\emptyargp{#3}}\zmdtageqno#2\zmark \fi}
+
+\def \zmdexpliciteqno #1#2 #3\zmark{%
+ \if \codeeqlp{#1}{!}%
+ \mathdisplayeqno = {#2}%
+ \mathdisplaycomptext = {#2}%
+ \else\if \codeeqlp{#1}{+}%
+ \global\increment \mathdisplaynumber
+ \mathdisplayeqno = \expandafter{\number\mathdisplaynumber #2}%
+ \setcomptext{\mathdisplaycomptext}%
+ \else\if \codeeqlp{#1}{,}%
+ \mathdisplayeqno = \expandafter{\number\mathdisplaynumber #2}%
+ \setcomptext{\mathdisplaycomptext}%
+ \else\if \codeeqlp{#1}{:}%
+ \global\increment \mathdisplaynumber
+ \mathdisplayeqno = {#2}%
+ \setcomptext{\mathdisplaycomptext}%
+ \else\if \codeeqlp{#1}{=}%
+ \zmdseteqno #2\zmark
+ \setcomptext{\mathdisplaycomptext}%
+ \else\if \codeeqlp{#1}{>}%
+ \zmdrefeqno #2;;\zmark
+%%% \mathdisplayeqno = {\ref{#2}}%
+%%% \mathdisplaycomptext = {\ref{#2}}%
+ \else
+ \mathdisplayeqno = {#1#2}%
+ \setcomptext{\mathdisplaycomptext}%
+ \fi\fi\fi\fi\fi\fi}
+
+\def \zmdseteqno #1;#2\zmark{%
+ \global\mathdisplaynumber = #1\relax
+ \mathdisplayeqno = \expandafter{\number\mathdisplaynumber #2}}
+
+\def \zmdrefeqno #1;#2;#3\zmark{%
+ \if \emptyargp{#2}%
+ \mathdisplayeqno = {\ref{#1}}%
+ \mathdisplaycomptext = {\ref{#1}}%
+ \else
+ \mathdisplayeqno = {\ref{#1}\,#2}%
+ \mathdisplaycomptext = {\ref{#1}\,#2}%
+ \fi}
+
+\def \zmdtageqno #1#2\zmark{%
+ \def \znext { }%
+ \if \znext#2\tag{#1}\else \tag{#1#2}\fi}
+
+\def \setmathdisplaynumber #1{%
+ \global\mathdisplaynumber = #1\relax
+ \global\decrement \mathdisplaynumber}
+
+%~ This modifier for |$$| is used when the display is the first thing
+%~ after a head, the first thing in a list item, the first thing in
+%~ a float, etc. It eliminates the vertical space above the display.
+
+\def \immediatemathdisplay {% %^modifier
+ \with{\abovepenalty = \breaknever
+ \aboveskip = 0pt}}
+
+% Aligned Equations
+% ------- ---------
+
+
+% This tool can only be used inside a math display.
+
+
+\defineskip{\zeqaltabskip}{0pt}
+\definedimen{\zeqnoshift}{0pt}
+
+\def \eqaligned #1{% {rows...}
+ \vcenter{%
+ \zeqalinit
+ \halign to \tdimena {%
+ \hfil $\displaystyle ##{}$\tabskip = 0pt&
+ $\displaystyle {}##$\hfil \tabskip = \zeqaltabskip&
+ \relax \zeqaleqno ##\zmark% \relax prevents expansion of \zeqaleqno.
+ \tabskip = \if \zmdnumleft \displaywidth \else 0pt \fi \cr
+ #1\crcr}}}
+
+\def \eqalignedpairs #1{% {rows...}
+ \vcenter{%
+ \zeqalinit
+ \halign to \tdimena {%
+ \hfil $\displaystyle ##{}$\tabskip = 0pt&
+ $\displaystyle {}##$\hfil&
+ \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil \tabskip = \zeqaltabskip&
+ \relax \zeqaleqno ##\zmark% \relax prevents expansion of \zeqaleqno.
+ \tabskip = \if \zmdnumleft \displaywidth \else 0pt \fi \cr
+ #1\crcr}}}
+
+\def \eqalignedtriples #1{% {rows...}
+ \vcenter{%
+ \zeqalinit
+ \halign to \tdimena {%
+ \hfil $\displaystyle ##{}$\tabskip = 0pt&
+ $\displaystyle {}##$\hfil&
+ \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil&
+ \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil \tabskip = \zeqaltabskip&
+ \relax \zeqaleqno ##\zmark% \relax prevents expansion of \zeqaleqno.
+ \tabskip = \if \zmdnumleft \displaywidth \else 0pt \fi \cr
+ #1\crcr}}}
+
+\def \eqalignedquadruples #1{% {rows...}
+ \vcenter{%
+ \zeqalinit
+ \halign to \tdimena {%
+ \hfil $\displaystyle ##{}$\tabskip = 0pt&
+ $\displaystyle {}##$\hfil&
+ \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil&
+ \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil&
+ \hfil $\displaystyle ##{}$&
+ $\displaystyle {}##$\hfil \tabskip = \zeqaltabskip&
+ \relax \zeqaleqno ##\zmark% \relax prevents expansion of \zeqaleqno.
+ \tabskip = \if \zmdnumleft \displaywidth \else 0pt \fi \cr
+ #1\crcr}}}
+
+\def \zeqalinit {%
+ \def \eqno {&\relax}% \relax prevents expansion of stuff after \eqno.
+ \tdimena = \displaywidth
+ \advance \tdimena by -\leftindent
+ \advance \tdimena by -\rightindent
+ \zeqaltabskip = \if \eqlp{\zmdhpos}{2}0pt \else \centerindent \fi
+ \if \zmdnumleft
+ \zeqnoshift = \leftskip \advance \zeqnoshift by \leftindent
+ \else
+ \zeqnoshift = \rightskip \advance \zeqnoshift by \rightindent
+ \fi
+ \tabskip = \if \eqlp{\zmdhpos}{1}0pt \else \centerindent \fi}
+
+\def \zeqaleqno \relax#1\zmark{% \relax [\eqno [text]][\tag]\zmark
+ \if \zmdnumleft
+ \kern -\displaywidth
+ \rlap{\zmdformeqno#1\tag\tag\zmark}%
+ \else
+ \llap{\zmdformeqno#1\tag\tag\zmark \hspace{-\zeqnoshift}}%
+ \fi}
+
+\let \adjustmathdisplay = \noalign
+
+% Diagrams
+% --------
+
+
+% This tool can only be used inside a math display.
+
+
+\def \diagram #1{% {rows...}
+ \zdiagcmds
+ \null\,%
+ \vcenter{%
+ \lineskip = \diagraminterrowskip
+ \lineskiplimit = \lineskip
+ \tabskip = -\diagramgutter
+ \halign{%
+ &\kern \diagramgutter \hfil $\displaystyle ##$\hfil \tabskip = 0pt \cr
+ #1\crcr}}%
+ \,}
+
+\def \zdiagcmds {%
+ \defineatsigncommand @>##1>##2>{\zdiagra{##1}{##2}}%
+ \defineatsigncommand @<##1<##2<{\zdiagla{##1}{##2}}%
+ \defineatsigncommand @X##1X##2X{\zdiaglra{##1}{##2}}%
+ \defineatsigncommand @=##1=##2={\zdiaghb{##1}{##2}}%
+ \defineatsigncommand @V##1V##2V{%
+ \zdiagva{c}{}{\hbox}{\big\downarrow}{##1}{##2}}%
+ \defineatsigncommand @A##1A##2A{%
+ \zdiagva{c}{}{\hbox}{\big\uparrow}{##1}{##2}}%
+ \defineatsigncommand @|##1|##2|{%
+ \zdiagva{c}{}{\hbox}{\big|}{##1}{##2}}%
+ \defineatsigncommand @H##1|##2|{%
+ \zdiagva{c}{}{\hbox}{\big\Vert}{##1}{##2}}%
+ \defineatsigncommand @1##11##21##31{%
+ \zdiagva{##1}{l}{r}{\the\diagramdiagarrowstyle \mathchar "7025}{##2}{##3}}%
+ \defineatsigncommand @3##13##23##33{%
+ \zdiagva{##1}{l}{r}{\the\diagramdiagarrowstyle \mathchar "7026}{##2}{##3}}%
+ \defineatsigncommand @5##15##25##35{%
+ \zdiagva{##1}{r}{l}{\the\diagramdiagarrowstyle \mathchar "702E}{##2}{##3}}%
+ \defineatsigncommand @7##17##27##37{%
+ \zdiagva{##1}{r}{l}{\the\diagramdiagarrowstyle \mathchar "702D}{##2}{##3}}%
+ \defineatsigncommand @"##1"##2"{\zdiagwd{##1}{##2}}}
+
+\def \zdiagra #1#2{%
+ {\setbox \zboxa = \hbox{$\scriptstyle \;{#1}\;\;\;$}%
+ \setbox \zboxb = \hbox{$\scriptstyle \;{#2}\;\;\;$}%
+ \setbox \zboxc = \hbox{$#2$}%
+ \tdimena = \diagramminarrow
+ \if \dimgtrp{\wd\zboxa}{\tdimena}\tdimena = \wd\zboxa \fi
+ \if \dimgtrp{\wd\zboxb}{\tdimena}\tdimena = \wd\zboxb \fi
+ \mathrel{\mathop{\hbox to \tdimena {\rightarrowfill}}%
+ \limits^{#1}\if \dimposp{\wd\zboxc}_{#2}\fi}}}
+
+\def \zdiagla #1#2{%
+ {\setbox \zboxa = \hbox{$\scriptstyle \;\;\;{#1}\;$}%
+ \setbox \zboxb = \hbox{$\scriptstyle \;\;\;{#2}\;$}%
+ \setbox \zboxc = \hbox{$#2$}%
+ \tdimena = \diagramminarrow
+ \if \dimgtrp{\wd\zboxa}{\tdimena}\tdimena = \wd\zboxa \fi
+ \if \dimgtrp{\wd\zboxb}{\tdimena}\tdimena = \wd\zboxb \fi
+ \mathrel{\mathop{\hbox to \tdimena {\leftarrowfill}}%
+ \limits^{#1}\if \dimposp{\wd\zboxc}_{#2}\fi}}}
+
+\def \zdiaglra #1#2{%
+ {\setbox \zboxa = \hbox{$\scriptstyle \;\;\;{#1}\;\;\;$}%
+ \setbox \zboxb = \hbox{$\scriptstyle \;\;\;{#2}\;\;\;$}%
+ \setbox \zboxc = \hbox{$#2$}%
+ \tdimena = \diagramminarrow
+ \if \dimgtrp{\wd\zboxa}{\tdimena}\tdimena = \wd\zboxa \fi
+ \if \dimgtrp{\wd\zboxb}{\tdimena}\tdimena = \wd\zboxb \fi
+ \mathrel{\mathop{\hbox to \tdimena {\leftrightarrowfill}}%
+ \limits^{#1}\if \dimposp{\wd\zboxc}_{#2}\fi}}}
+
+\def \zdiaghb #1#2{%
+ {\setbox \zboxa = \hbox{$\scriptstyle \;{#1}\;$}%
+ \setbox \zboxb = \hbox{$\scriptstyle \;{#2}\;$}%
+ \setbox \zboxc = \hbox{$#2$}%
+ \tdimena = \diagramminarrow
+ \if \dimgtrp{\wd\zboxa}{\tdimena}\tdimena = \wd\zboxa \fi
+ \if \dimgtrp{\wd\zboxb}{\tdimena}\tdimena = \wd\zboxb \fi
+ \mathrel{\mathop{\hbox to \tdimena {\equalfill}}%
+ \limits^{#1}\if \dimposp{\wd\zboxc}_{#2}\fi}}}
+
+\def \zdiagva #1#2#3#4#5#6{% {centering}{h-overlap}{t-overlap}
+ % {arrow}{left-label}{right-label}
+ \if \codeeqlp{#1}{h}%
+ \if \codeeqlp{#2}{l}%
+ \llap{$\scriptstyle{#5}\mkern 2mu{#4}$}%
+ \rlap{$\mkern 2mu \scriptstyle #6$}%
+ \else
+ \llap{$\scriptstyle{#5}\mkern 2mu$}%
+ \rlap{${#4}\mkern 2mu \scriptstyle{#6}$}%
+ \fi
+ \else\if \codeeqlp{#1}{t}%
+ \if \codeeqlp{#3}{l}%
+ \llap{$\scriptstyle{#5}\mkern 2mu{#4}$}
+ \rlap{$\mkern 2mu \scriptstyle #6$}%
+ \else
+ \llap{$\scriptstyle{#5}\mkern 2mu$}
+ \rlap{${#4}\mkern 2mu \scriptstyle #6$}%
+ \fi
+ \else
+ \llap{$\scriptstyle{#5}\mkern 2mu$}{#4}%
+ \rlap{$\mkern 2mu \scriptstyle #6$}%
+ \fi\fi}
+
+\def \zdiagwd #1#2{%
+ \setbox \zboxa = \hbox{$\scriptstyle #2$}%
+ \hbox to \wd\zboxa {\hfil $\scriptstyle #1$\hfil}}
+
+% Enunciation Definition
+% ----------- ----------
+
+
+\setlist \zenuntypelist = {}
+
+
+\def \defineenunciationtype #1#2{% {type}{association}
+ \if \emptyargp{#2}%
+ \if \withname\undefinedp{\enunciation#1number}%
+ \withname\definecount{\enunciation#1number}{0}%
+ \withname\declaresnapitem{\enunciation#1number}%
+ \fi
+ \else
+ \defineenunciationtype{#2}{}%
+ \edef \znext {%
+ \global\withname\let{\enunciation#1number}=\name{\enunciation#2number}}%
+ \znext
+ \fi
+ \append{#1}{\zenuntypelist}}
+
+%~ Use this command to define a new type of enunciation.
+
+\def \defineenunciation #1#2#3{% {type}{association}{design}
+ \defineenunciationtype{#1}{#2}%
+ \withname\def {\enunciation#1design}{#3}}
+
+
+% This is deprecated in favor of \defineenunciation.
+
+\def \defineenunciationtypedesign #1#2#3{% {type}{assocation}{design}
+ \defineenunciationtype{#1}{#2}%
+ \withname\def {\enunciation#1design}{#3}}
+
+\def \resetenunciationnumbers {%
+ \maplist{\global\name{\enunciation##1number}=0\relax}{\zenuntypelist}}
+
+% Enunciation Block
+% ----------- -----
+
+
+\defineblock{\enunciation}{\endenunciation}{\false}{}
+
+%~block enunciation Type
+% \abovepenalty = integer % Penalty above block
+% \aboveskip = glue % Space b/b above block.
+% \setflag \allowclubline = flag % True if club allowed below.
+% \setflag \allownesting = flag % True if blocks can be nested.
+% \attribution = {...} % Attribution text (no longer used).
+% \setflag \attributionarg = flag % True if \enunciation takes attribution argument.
+% \autoqed = {,,,} % Automatic QED at end.
+% \belowpenalty = integer % Penalty below block.
+% \belowskip = glue % Space b/b below block.
+% \bodyfont = {...} % Font for text.
+% \def \comptextformat {...} % Composite number text formatter.
+% \continue = integer % Continued or continuation.
+% \difficulty = integer % Level of difficulty.
+% \def \endformat {...} % End of enunciation formatter.
+% \def \labelformat ##1{...} % Enunciation label formatter.
+% \leftindent = glue % Left indentation.
+% \parindent = dimen % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \rightindent = glue % Right indentation.
+% \width = dimen % Width of text.
+%~end
+
+\definetoks{\attribution}
+\definecount{\attributiontype}{0} % 0: none; 1: attribution; 2: new title
+\definetoks{\autoqed}
+
+\setflag \zautoqeddone = \false
+
+
+\def \enunciation #1{% {type}{optional-attribution}
+ \beginblockscope{enunciation}%
+ \global\increment \enunciationdepth
+ \abovepenalty = \breakgood %~default hard
+ \setflag \allowclubline = \false %~default soft
+ \setflag \allownesting = \false %~default soft
+ \attribution = {}% %~default with
+ \setflag \attributionarg = \false %~default soft
+ \autoqed = {}% %~default soft
+ \belowpenalty = \breakgood %~default hard
+ \continue = 0 %~default with
+ \setflag \continuation = \false % Deprecated
+ \difficulty = 0 %~default with
+ \def \endformat {}% %~default soft
+ \processdesign{\enunciation}{#1}%
+ \zsetcontinue % Handle old \continuation.
+ \if \andp{\notp{\allownesting}}{\gtrp{\enunciationdepth}{1}}%
+ \error{blkcantnest}
+ {An enunciation cannot be nested inside itself}%
+ \fi
+ \if \attributionarg
+ \let \znext = \enunciationarg
+ \else
+ \let \znext = \enunciationb
+ \fi
+ \znext{#1}}
+
+\def \enunciationarg #1#2{% {type}{attribution}
+ \if \notp{\emptyargp{#2}}\attribution = {#2}\fi
+ \enunciationb{#1}}
+
+\def \enunciationb #1{% {type}
+ \attributiontype = 0\relax
+ \global\setflag \zautoqeddone = \false
+ \if \notp{\emptytoksp{\attribution}}%
+ \expandafter\zparseenunattr \the\attribution \zmark
+ \fi
+ \if \notp{\continuationp}%
+ \global\withname\increment{\enunciation#1number}%
+ \fi
+ \global\withname\enunciationnumber{\enunciation#1number}%
+ \setcomptext{\enunciationcomptext}%
+ \enunciationformat
+ \settaginfo{\the\enunciationcomptext}{???}%
+ \ignorespaces}
+
+\def \endenunciation {%
+ \futurelet\nexttoken \zendenunciation}
+
+\def \zendenunciation {%
+ \endenunciationformat
+ \global\decrement \enunciationdepth
+ \endblockscope{enunciation}%
+ \parnext}
+
+\def \enunciationformat {%
+ \endgraf
+ \the\bodyfont
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \setparrag{\parrag}%
+ \expandafter\labelformat\expandafter{\the\attribution}%
+ \if \notp{\allowclubline}\overrideclubpenalty{\breaknever}\fi}
+
+\def \endenunciationformat{%
+ \if \notp{\zautoqeddone}\the\autoqed \fi
+ \endgraf
+ \endformat
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+%~ This marker indicates that the enunciation title completely
+%~ replaces the default title.
+
+\definemarker{\title}
+
+\def \zparseenunattr #1#2\zmark{%
+ \def \znext {#1}%
+ \def \ztitle {\title}%
+ \if \tokeqlp{\znext}{\ztitle}%
+ \attribution = {#2}%
+ \attributiontype = 2\relax
+ \else
+ \attributiontype = 1\relax
+ \fi}
+
+%~ This command is used in enunciation design macros to select the
+%~ title format based on the |\enunciation| *attribution* argument.
+
+\long\def \attributiontypecase #1#2#3{% {format1}{format2}{format3}
+ \ifcase \attributiontype
+ #1% no attribution
+ \or
+ #2% normal attribution
+ \or
+ #3% title override
+ \fi}%
+
+% QED Definition
+% --- ----------
+
+
+%~ This command defines an end-of-enunciation dingbat for use
+%~ with enunciations.
+
+\def \defineeoedingbat #1#2#3{% {name}{text}{space}
+ \withname\gdef {#1dingbat}{#2}%
+ \gdef #1{\zformateoe{#2}#3\zmark}%
+ \withname\gdef {\no\expandafter\discardtok\string#1}{%
+ \global\setflag \zautoqeddone = \true}}
+
+\def \zformateoe #1#2#3\zmark{%
+ {\def \znext {#2}%
+ \def \zfr {\flushright}%
+ \if \tokeqlp{\znext}{\zfr}%
+ \if \vmodep
+ \rightline{#1}%
+ \else\if \mathmodep
+ \hskip #3{#1}%
+ \else
+ \hskip #3\retain \nobreak \hfill {#1}%
+ \fi\fi
+ \else
+ \if \vmodep
+ \rightline{#1}%
+ \else\if \mathmodep
+ \hskip #2#3{#1}%
+ \else
+ \unskip \hskip #2#3\hskip 0pt plus -1fill \retain \nobreak \hfill {#1}%
+ \fi\fi
+ \fi
+ \global\setflag \zautoqeddone = \true}}
+
+
+%~ This command is deprecated in favor of |\defineeoedingbat|.
+
+\def \defineqed #1#2#3#4{% {\name}{text}{space}{min-space}
+ \withname\gdef {#1dingbat}{#2}%
+ \gdef #1{\zformatqed{#2}{#3}{#4}}%
+ \withname\gdef{\no\expandafter\discardtok\string#1}{%
+ \global\setflag \zautoqeddone = \true}}
+
+\def \zformatqed #1#2#3{% {text}{space}{min-space}
+ {\def \znext {#2}%
+ \def \zfr {\flushright}%
+ \if \tokeqlp{\znext}{\zfr}%
+ \hspace{#3}\retain \nobreak \hfill {#1}%
+ \else
+ \if \vmodep
+ \noindent #1\par
+ \else
+ \hspace{#2}{#1}%
+ \fi
+ \fi
+ \global\setflag \zautoqeddone = \true}}
diff --git a/macros/plain/contrib/zztex/tex/zzmathv3.tex b/macros/plain/contrib/zztex/tex/zzmathv3.tex
new file mode 100644
index 0000000000..a30a797bc2
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmathv3.tex
@@ -0,0 +1,123 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Mathematics Facilities
+%
+% Synopsis: This file provides the mathematics facilities for "new math"
+% version 3, which supercedes version 2.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 7 June 2003
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Math Spaces
+% ---- ------
+
+
+\setmathspaces{4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}%
+
+% Math Font Selections
+% ---- ---- ----------
+
+
+\outer\def \ComputerModernmathfonts {%
+ \input zzcmmath\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \Lucidamathfonts #1{% {arrows?}
+ \setflag \zusemar = #1\relax
+ \input zzlucida\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \MathTimefonts #1{% {text face is Times?}
+ \input zzmtime\relax
+ \if #1%
+ \setmathpunctuationstyle{\mit}{\rm}%
+ \else
+ \setmathpunctuationstyle{\rm}{\rm}%
+ \fi}
+
+\outer\def \Stonemathfonts {%
+ \setmathpunctuationstyle{\rm}{\rm}}
+
+% Punctuation Style
+% ----------- -----
+
+
+% Here we deal with the style for comma, period, semicolon, and colon.
+% The default punctuation style for all four is \rm.
+
+
+% This macro defines the math characters \zmperiod, \zmcomma,
+% colon, and semicolon to use the specified style.
+% If the style is \mit, then it's different.
+
+\def \setmathpunctuationstyle #1#2{% {\style1}{\style2}
+ {\zmstyfam = \name{#1fam}%
+ \if \eqlp{\zmstyfam}{\mitfam}%
+ \definemathchar {`.} \classord \mitfam {3A}
+ \definemathchar {`,} \classpunc \mitfam {3B}
+ \else
+ \definemathchar {`.} \classactive \rmfam {00}
+ \definemathchar {`,} \classactive \rmfam {00}
+ \definemathchar {\zmperiod} \classord \zmstyfam {2E}
+ \definemathchar {\zmcomma} \classpunc \zmstyfam {2C}
+ \fi
+ \zmstyfam = \name{#2fam}%
+ \definemathchar {`;} \classpunc \zmstyfam {3B}
+ \definemathchar {`:} \classrel \zmstyfam {3A}}}
+
+% When period and comma are active in math, this is what they do.
+
+{
+\catcode `\. = \catactive
+\gdef .{\mathpalette\zmactperiod{}}
+
+\catcode `\, = \catactive
+\gdef ,{\mathpalette\zmactcomma{}}
+}
+
+\def \zmactperiod #1#2{%
+ \mathord{\hbox to .275em{\hfil $#1\zmperiod$\kern .06em\hfil}}}
+
+\def \zmactcomma #1#2{%
+ \mathpunct{\hbox to .331em{\kern .045em $#1\zmcomma$\hfil}}}
+
+% Dot-Related Commands
+% ----------- --------
+
+
+\def \cdotp {\mathpunct{\vcenter{\hbox{$.$}}}}
+
+\def \ldotp {\mathpunct{.}}
+
+\def \cdots {\mathinner{\cdotp\cdotp\cdotp}}
+
+\def \ddots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{\kern .4em .}%
+ \hbox{\kern .8em .}%
+ \vskip -.25ex}}
+
+\def \ldots {\mathinner{\ldotp\ldotp\ldotp}}
+
+\def \vdots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{.}%
+ \hbox{.}%
+ \vskip -.25ex}}
+
+% Colon Commands
+% ----- --------
+
+
+\def \maps {\mathpunct{:}}
+
+\let \colon = \maps
diff --git a/macros/plain/contrib/zztex/tex/zzmathv4.tex b/macros/plain/contrib/zztex/tex/zzmathv4.tex
new file mode 100644
index 0000000000..a5c5a0c411
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmathv4.tex
@@ -0,0 +1,129 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Mathematics Facilities
+%
+% Synopsis: This file provides the mathematics facilities for "new math"
+% version 4.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 September 2003
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Document Parameters
+% -------- ----------
+
+
+\delimitershortfall = 2pt
+
+% Math Spaces
+% ---- ------
+
+
+\setmathspaces{4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}%
+
+% Math Font Selections
+% ---- ---- ----------
+
+
+\outer\def \ComputerModernmathfonts {%
+ \input zzcmmath\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \Lucidamathfonts #1{% {arrows?}
+ \setflag \zusemar = #1\relax
+ \input zzlucida\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \MathTimefonts #1{% {text face is Times?}
+ \input zzmtime\relax
+ \if #1%
+ \setmathpunctuationstyle{\mit}{\rm}%
+ \else
+ \setmathpunctuationstyle{\rm}{\rm}%
+ \fi}
+
+\outer\def \Stonemathfonts {%
+ \setmathpunctuationstyle{\rm}{\rm}}
+
+% Punctuation Style
+% ----------- -----
+
+
+% Here we deal with the style for comma, period, semicolon, and colon.
+% The default punctuation style for all four is \rm.
+
+
+% This macro defines the math characters \zmperiod, \zmcomma,
+% colon, and semicolon to use the specified style.
+% If the style is \mit, then it's different.
+
+\def \setmathpunctuationstyle #1#2{% {\style1}{\style2}
+ {\zmstyfam = \name{#1fam}%
+ \if \eqlp{\zmstyfam}{\mitfam}%
+ \definemathchar {`.} \classord \mitfam {3A}
+ \definemathchar {`,} \classpunc \mitfam {3B}
+ \else
+ \definemathchar {`.} \classactive \rmfam {00}
+ \definemathchar {`,} \classactive \rmfam {00}
+ \definemathchar {\zmperiod} \classord \zmstyfam {2E}
+ \definemathchar {\zmcomma} \classpunc \zmstyfam {2C}
+ \fi
+ \zmstyfam = \name{#2fam}%
+ \definemathchar {`;} \classpunc \zmstyfam {3B}
+ \definemathchar {`:} \classrel \zmstyfam {3A}}}
+
+% When period and comma are active in math, this is what they do.
+
+{
+\catcode `\. = \catactive
+\gdef .{\mathpalette\zmactperiod{}}
+
+\catcode `\, = \catactive
+\gdef ,{\mathpalette\zmactcomma{}}
+}
+
+\def \zmactperiod #1#2{%
+ \mathord{\hbox to .275em{\hfil $#1\zmperiod$\kern .06em\hfil}}}
+
+\def \zmactcomma #1#2{%
+ \mathpunct{\hbox to .331em{\kern .045em $#1\zmcomma$\hfil}}}
+
+% Dot-Related Commands
+% ----------- --------
+
+
+\def \cdotp {\mathpunct{\vcenter{\hbox{$.$}}}}
+
+\def \ldotp {\mathpunct{.}}
+
+\def \cdots {\mathinner{\cdotp\cdotp\cdotp}}
+
+\def \ddots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{\kern .4em .}%
+ \hbox{\kern .8em .}%
+ \vskip -.25ex}}
+
+\def \ldots {\mathinner{\ldotp\ldotp\ldotp}}
+
+\def \vdots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{.}%
+ \hbox{.}%
+ \vskip -.25ex}}
+
+% Colon Commands
+% ----- --------
+
+
+\def \maps {\mathpunct{:}}
+
+\let \colon = \maps
diff --git a/macros/plain/contrib/zztex/tex/zzmathv5.tex b/macros/plain/contrib/zztex/tex/zzmathv5.tex
new file mode 100644
index 0000000000..e7a8f90b2d
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmathv5.tex
@@ -0,0 +1,129 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Mathematics Facilities
+%
+% Synopsis: This file provides the mathematics facilities for "new math"
+% version 5.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 September 2003
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Document Parameters
+% -------- ----------
+
+
+\delimitershortfall = 2pt
+
+% Math Spaces
+% ---- ------
+
+
+\setmathspaces{4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}%
+
+% Math Font Selections
+% ---- ---- ----------
+
+
+\outer\def \ComputerModernmathfonts {%
+ \input zzcmmath\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \Lucidamathfonts #1{% {arrows?}
+ \setflag \zusemar = #1\relax
+ \input zzlucida\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \MathTimefonts #1{% {text face is Times?}
+ \input zzmtime\relax
+ \if #1%
+ \setmathpunctuationstyle{\mit}{\rm}%
+ \else
+ \setmathpunctuationstyle{\rm}{\rm}%
+ \fi}
+
+\outer\def \Stonemathfonts {%
+ \setmathpunctuationstyle{\rm}{\rm}}
+
+% Punctuation Style
+% ----------- -----
+
+
+% Here we deal with the style for comma, period, semicolon, and colon.
+% The default punctuation style for all four is \rm.
+
+
+% This macro defines the math characters \zmperiod, \zmcomma,
+% colon, and semicolon to use the specified style.
+% If the style is \mit, then it's different.
+
+\def \setmathpunctuationstyle #1#2{% {\style1}{\style2}
+ {\zmstyfam = \name{#1fam}%
+ \if \eqlp{\zmstyfam}{\mitfam}%
+ \definemathchar {`.} \classord \mitfam {3A}
+ \definemathchar {`,} \classpunc \mitfam {3B}
+ \else
+ \definemathchar {`.} \classactive \rmfam {00}
+ \definemathchar {`,} \classactive \rmfam {00}
+ \definemathchar {\zmperiod} \classord \zmstyfam {2E}
+ \definemathchar {\zmcomma} \classpunc \zmstyfam {2C}
+ \fi
+ \zmstyfam = \name{#2fam}%
+ \definemathchar {`;} \classpunc \zmstyfam {3B}
+ \definemathchar {`:} \classrel \zmstyfam {3A}}}
+
+% When period and comma are active in math, this is what they do.
+
+{
+\catcode `\. = \catactive
+\gdef .{\mathpalette\zmactperiod{}}
+
+\catcode `\, = \catactive
+\gdef ,{\mathpalette\zmactcomma{}}
+}
+
+\def \zmactperiod #1#2{%
+ \mathord{\hbox to .275em{\hfil $#1\zmperiod$\hfil}}}
+
+\def \zmactcomma #1#2{%
+ \mathpunct{\hbox to .331em{\kern .045em $#1\zmcomma$\hfil}}}
+
+% Dot-Related Commands
+% ----------- --------
+
+
+\def \cdotp {\mathpunct{\vcenter{\hbox{$.$}}}}
+
+\def \ldotp {\mathpunct{.}}
+
+\def \cdots {\mathinner{\cdotp\cdotp\cdotp}}
+
+\def \ddots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{\kern .4em .}%
+ \hbox{\kern .8em .}%
+ \vskip -.25ex}}
+
+\def \ldots {\mathinner{\ldotp\ldotp\ldotp}}
+
+\def \vdots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{.}%
+ \hbox{.}%
+ \vskip -.25ex}}
+
+% Colon Commands
+% ----- --------
+
+
+\def \maps {\mathpunct{:}}
+
+\let \colon = \maps
diff --git a/macros/plain/contrib/zztex/tex/zzmathv6.tex b/macros/plain/contrib/zztex/tex/zzmathv6.tex
new file mode 100644
index 0000000000..c47f22ae2d
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmathv6.tex
@@ -0,0 +1,180 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Mathematics Facilities
+%
+% Synopsis: This file provides the mathematics facilities for "new math"
+% version 5.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 September 2003
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Document Parameters
+% -------- ----------
+
+
+\delimitershortfall = 2pt
+
+% Math Spaces
+% ---- ------
+
+
+\setmathspaces{4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}
+ {4mu plus .25mu minus .5mu}%
+
+% Math Font Selections
+% ---- ---- ----------
+
+
+\outer\def \ComputerModernmathfonts {%
+ \input zzcmmath\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \Lucidamathfonts #1{% {arrows?}
+ \setflag \zusemar = #1\relax
+ \input zzlucida\relax
+ \setmathpunctuationstyle{\mit}{\rm}}
+
+\outer\def \MathTimefonts #1{% {text face is Times?}
+ \input zzmtime\relax
+ \setmathucgreekstyles{\mit}{\boldgreekunavailable}%
+ \if #1%
+ \setmathpunctuationstyle{\mit}{\rm}%
+ \else
+ \setmathpunctuationstyle{\rm}{\rm}%
+ \fi}
+
+\outer\def \Stonemathfonts {%
+ \setmathpunctuationstyle{\rm}{\rm}}
+
+% Greek Letter Style
+% ----- ------ -----
+
+
+\def \zmucgreekstyler {}
+\def \zmucgreekstyleb {}
+
+
+% Note the "s" at the end of the name, versus \setmathucgreekstyle.
+
+\def \setmathucgreekstyles #1#2{% {regular-style}{bold-style}
+ \gdef \zmucgreekstyler {#1}%
+ \gdef \zmucgreekstyleb {#2}%
+\definemathchar \Alpha \classvarfam \rmfam {41}%
+\definemathchar \Beta \classvarfam \rmfam {42}%
+\zdefucgreekchar \Gamma {30}%
+\zdefucgreekchar \Delta {31}%
+\definemathchar \Epsilon \classvarfam \rmfam {45}%
+\definemathchar \Zeta \classvarfam \rmfam {5A}%
+\definemathchar \Eta \classvarfam \rmfam {48}%
+\zdefucgreekchar \Theta {32}%
+\definemathchar \Iota \classvarfam \rmfam {49}%
+\definemathchar \Kappa \classvarfam \rmfam {4B}%
+\zdefucgreekchar \Lambda {33}%
+\definemathchar \Mu \classvarfam \rmfam {4D}%
+\definemathchar \Nu \classvarfam \rmfam {4E}%
+\zdefucgreekchar \Xi {34}%
+\definemathchar \Omicron \classvarfam \rmfam {4F}%
+\zdefucgreekchar \Pi {35}%
+\definemathchar \Rho \classvarfam \rmfam {50}%
+\zdefucgreekchar \Sigma {36}%
+\definemathchar \Tau \classvarfam \rmfam {54}%
+\zdefucgreekchar \Upsilon {37}%
+\zdefucgreekchar \Phi {38}%
+\definemathchar \Chi \classvarfam \rmfam {58}%
+\zdefucgreekchar \Psi {39}%
+\zdefucgreekchar \Omega {7F}}
+
+\def \zdefucgreekchar #1#2{% {\name}{code}
+ \gdef #1{%
+ \if \eqlp{\fam}{-1}%
+ {\zmucgreekstyler \mathchar "70#2}%
+ \else\if \eqlp{\fam}{\bffam}%
+ {\zmucgreekstyleb \mathchar "70#2}%
+ \else
+ \error{invgrkstyle}{The current math family precludes using bold Greek}%
+ \fi\fi}}
+
+% Punctuation Style
+% ----------- -----
+
+
+% Here we deal with the style for comma, period, semicolon, and colon.
+% The default punctuation style for all four is \rm.
+
+
+% This macro defines the math characters \zmperiod, \zmcomma,
+% colon, and semicolon to use the specified style.
+% If the style is \mit, then it's different.
+
+\def \setmathpunctuationstyle #1#2{% {\style1}{\style2}
+ {\zmstyfam = \name{#1fam}%
+ \if \eqlp{\zmstyfam}{\mitfam}%
+ \definemathchar {`.} \classord \mitfam {3A}%
+ \definemathchar {`,} \classpunc \mitfam {3B}%
+ \else
+ \definemathchar {`.} \classactive \rmfam {00}%
+ \definemathchar {`,} \classactive \rmfam {00}%
+ \definemathchar {\zmperiod} \classord \zmstyfam {2E}%
+ \definemathchar {\zmcomma} \classpunc \zmstyfam {2C}%
+ \fi
+ \zmstyfam = \name{#2fam}%
+ \definemathchar {`;} \classpunc \zmstyfam {3B}%
+ \definemathchar {`:} \classrel \zmstyfam {3A}}}
+
+% When period and comma are active in math, this is what they do.
+
+{
+\catcode `\. = \catactive
+\gdef .{\mathpalette\zmactperiod{}}
+
+\catcode `\, = \catactive
+\gdef ,{\mathpalette\zmactcomma{}}
+}
+
+\def \zmactperiod #1#2{%
+ \mathord{\hbox to .275em{\hfil $#1\zmperiod$\hfil}}}
+
+\def \zmactcomma #1#2{%
+ \mathpunct{\hbox to .331em{\kern .045em $#1\zmcomma$\hfil}}}
+
+% Dot-Related Commands
+% ----------- --------
+
+
+\def \cdot {\mathbin{\vcenter{\hbox{$.$}}}}
+
+\def \cdotp {\mathpunct{\vcenter{\hbox{$.$}}}}
+
+\def \ldotp {\mathpunct{.}}
+
+\def \cdots {\mathinner{\cdotp\cdotp\cdotp}}
+
+\def \ddots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{\kern .4em .}%
+ \hbox{\kern .8em .}%
+ \vskip -.25ex}}
+
+\def \ldots {\mathinner{\ldotp\ldotp\ldotp}}
+
+\def \vdots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{.}%
+ \hbox{.}%
+ \vskip -.25ex}}
+
+% Colon Commands
+% ----- --------
+
+
+\def \maps {\mathpunct{:}}
+
+\let \colon = \maps
diff --git a/macros/plain/contrib/zztex/tex/zzmerge.tex b/macros/plain/contrib/zztex/tex/zzmerge.tex
new file mode 100644
index 0000000000..05ef863971
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmerge.tex
@@ -0,0 +1,70 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Merge Print
+%
+% Synopsis: This module provides a simple merge print facility for ZzTeX.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 17 October 2000
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Merge Fields
+% ----- ------
+
+
+\setlist \zmrgfields = {}
+\definecount{\zmrgcount}{0}
+
+\def \mergefields #1{%
+ \commalist{\zmrgfields}{#1}%
+ \zmrgcount = 0
+ \maplist{\increment \zmrgcount
+ \withname\edef {\zmrgfmap:##1}{\the\zmrgcount}}
+ {\zmrgfields}}
+
+% Merge Text
+% ----- ----
+
+
+\definetoks{\zmrgtoks}
+
+\long\def \mergetext #1\endmergetext{%
+ \zmrgtoks = {#1}}
+
+% Merge Print
+% ----- -----
+
+
+\definecount{\zmrgi}{0}
+
+
+\def \mergeprint {%
+ \zmrgi = 0
+ \zmrgprinta}
+
+\def \zmrgprinta #1{%
+ \if \lssp{\zmrgi}{\zmrgcount}%
+ \increment \zmrgi
+ \withname\def {\zmrgvmap:\the\zmrgi}{#1}%
+ \let \znext = \zmrgprinta
+ \else
+ \let \znext = \zmrgprintb
+ \fi
+ \znext}
+
+\def \zmrgprintb {%
+ \freshpage{\short\floats\any}%
+ \the\zmrgtoks}
+
+% Merge a Field
+% ----- - -----
+
+
+\def \merge #1{%
+ \edef \tcounta {\name{\zmrgfmap:#1}}%
+ \edef \znext {\name{\zmrgvmap:\the\tcounta}}%
+ \znext}
diff --git a/macros/plain/contrib/zztex/tex/zzmisc.tex b/macros/plain/contrib/zztex/tex/zzmisc.tex
new file mode 100644
index 0000000000..1813a3f572
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmisc.tex
@@ -0,0 +1,292 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Miscellaneous Facilities
+%
+% Synopsis: This module contains miscellaneous facilities that do not
+% seem to belong in any other file.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 26 August 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Character Categories
+% --------- ----------
+
+
+% The following list contains characters with category codes other
+% than endofline, ignored, space, letter, other, and invalid:
+
+\setlist \zcatlist = {}
+
+
+\def \establishcatcode #1#2{% {`\c}{\catname}
+ \zdelcat{#1}%
+ \catcode #1 = #2%
+ {\setflag \znext = \true
+ \if \eqlp{#2}{\catendofline}\setflag \znext = \false \fi
+ \if \eqlp{#2}{\catignored}\setflag \znext = \false \fi
+ \if \eqlp{#2}{\catspace}\setflag \znext = \false \fi
+ \if \eqlp{#2}{\catletter}\setflag \znext = \false \fi
+ \if \eqlp{#2}{\catother}\setflag \znext = \false \fi
+ \if \eqlp{#2}{\catinvalid}\setflag \znext = \false \fi
+ \if \znext \append{#1}{\zcatlist}\fi}}
+
+\def \zdelcat #1{%
+ {\setlist \znewcatlist = {}%
+ \maplist{\def \zcata {##1}\def \zcatb{#1}%
+ \if \notp{\tokeqlp{\zcata}{\zcatb}}\append{##1}{\znewcatlist}\fi}%
+ {\zcatlist}%
+ \setlist \zcatlist = \znewcatlist}}
+
+% Initialize the character list:
+
+\establishcatcode{`\^^L}{\catactive}
+\establishcatcode{`\#}{\catparameter}
+\establishcatcode{`\$}{\catmath}
+\establishcatcode{`\&}{\catalign}
+\establishcatcode{`\%}{\catcomment}
+\establishcatcode{`\@}{\catactive}
+\establishcatcode{`\\}{\catescape}
+\establishcatcode{`\^}{\catsuperscript}
+\establishcatcode{`\_}{\catsubscript}
+\establishcatcode{`\{}{\catbegin}
+\establishcatcode{`\}}{\catend}
+\establishcatcode{`\~}{\catactive}
+
+\def \uncatcode #1#2#3{% {allow-commands}{allow-at-commands}{allow-math}
+ \maplist{\catcode##1=\catother}{\zcatlist}%
+ \if #1%
+ \catcode`\\ = \catescape
+ \catcode`\{ = \catbegin
+ \catcode`\} = \catend
+ \fi
+ \if #2%
+ \catcode`\@ = \catactive
+ \fi
+ \if #3%
+ \catcode`\$ = \catmath
+ \catcode`\^ = \catsuperscript
+ \catcode`\_ = \catsubscript
+ \fi}
+
+\def \catcodemath {%
+ \catcode `\ = \catspace
+ \catcode `\$ = \catmath
+ \catcode `\^ = \catsuperscript
+ \catcode `\_ = \catsubscript}
+
+\def \catcoderange #1#2#3{% {first}{last}{\catname}
+ \tcounta = #1\relax
+ \tcountb = #2\relax \increment \tcountb
+ \loop
+ \ifnum \tcounta < \tcountb
+ \catcode \tcounta = #3%
+ \increment \tcounta
+ \repeat}
+
+% Make the upper half of the ASCII characters invalid.
+
+\catcoderange{"80}{"FF}{\catinvalid}
+
+% Conditional Text
+% ----------- ----
+
+
+\let \setif = \if
+\let \endsetif = \fi
+
+\def \ignore {%
+ \if \notp{\zemptyblockstackp}\todo{$\ignore command.}\fi
+ \setif \false}
+
+\let \endignore = \endsetif
+
+% Date & Time
+% ---- - ----
+
+
+% \year, \month, and \day are TeX parameters.
+
+\definecount{\weekday}{0}
+
+% \time is a TeX parameter, the number of minutes since midnight.
+
+\definecount{\hour}{0}
+\definecount{\minute}{0}
+
+
+\def \zdtinit {%
+ \zwdinit
+ \hour = \time
+ \divide \hour by 60
+ \minute = \time
+ \divide \minute by 60
+ \multiply \minute by -60
+ \advance \minute by \time}
+
+\def \zwdinit {%
+ \tcounta = \year
+ \if \lssp{\month}{3}\advance \tcounta by -1 \fi
+ \tcountb = \tcounta
+ \divide \tcountb by 100
+ \tcountc = \tcountb
+ \multiply \tcountc by -100
+ \advance \tcountc by \tcounta
+ \tcounta = \month
+ \if \lssp{\month}{3}\advance \tcounta by 9 \else \advance \tcounta by -3 \fi
+ \multiply \tcountb by 146097
+ \divide \tcountb by 4
+ \multiply \tcountc by 1461
+ \divide \tcountc by 4
+ \advance \tcountb by \tcountc
+ \multiply \tcounta by 153
+ \advance \tcounta by 2
+ \divide \tcounta by 5
+ \advance \tcountb by \tcounta
+ \advance \tcountb by \day
+ \advance \tcountb by -693902
+ \weekday = \tcountb
+ \divide \weekday by 7
+ \multiply \weekday by -7
+ \advance \weekday by \tcountb}
+
+
+\def \formattime {%
+ \number\hour:%
+ \if \lssp{\minute}{10}0\fi
+ \number\minute}
+
+% Fancy Names
+% ----- -----
+
+
+\def \AMSTeX {AMS\TeX}
+
+\def \BibTeX {Bib\TeX}
+
+\def \LaTeX {L\kern-.3em \raise .4ex \hbox{a}\kern-.05em \TeX}
+
+% Hiding Writes
+% ------ ------
+
+
+% These macros help to hide the \write's that are performed by commands
+% like \tag and \xpage.
+
+\definedimen{\zhidewriteskip}{0pt}
+
+\def \zbeginhidewrite {%
+ \zhidewriteskip = \lastskip
+ \begingroup
+ \if \hmodep \edef \zsf {\spacefactor=\the\spacefactor}\fi}
+
+\def \zendhidewrite {%
+ \if \hmodep \zsf \fi
+ \endgroup
+ \if \andp{\hmodep}{\dimposp{\zhidewriteskip}}\ignorespaces \fi}
+
+% Initialization File
+% -------------- ----
+
+
+\def \zloadinifile {%
+ \gdef \inicompositor {???}%
+ \gdef \iniinitials {???}%
+ \gdef \ininame {???}
+ \gdef \iniorganization {(none)}%
+ \checkfile{\zini}{zztex.ini}%
+ \if \zini
+ \writelog{(loading ini file)}%
+ \zloadinifilea
+ \else
+ \writelog{(no ini file)}%
+ \fi}
+
+\def \zloadinifilea {%
+ \begingroup
+ \catcode \endlinechar = \catcomment
+ \catcode `\; = \catcomment
+ \openin \zreada zztex.ini\relax
+ \setflag \zinireg = \false
+ \loop
+ \read \zreada to \zline
+ \if \notp{\emptydefp{\zline}}\expandafter\zloadinifileb \zline\zmark \fi
+ \if \notp{\eofp{\zreada}}\repeat
+ \closein \zreada
+ \endgroup}
+
+\def \zloadinifileb #1#2\zmark {%
+ \if \codeeqlp{#1}{[}%
+ \zloadinifilec #2\zmark
+ \else\if \zinireg
+ \zloadinifiled #1#2\zmark
+ \fi\fi}
+
+\def \zloadinifilec #1]#2\zmark {%
+ \stringeql{\zinireg}{#1}{registration}}
+
+\def \zloadinifiled #1=#2\zmark {%
+ \withname\gdef {\ini#1}{#2}}
+
+% Penalties
+% ---------
+
+
+% The following symbolic penalties should be used everywhere so they
+% can be adjusted without any recoding. The trailing spaces are
+% like \relax but don't screw up \ifnum.
+
+\def \breaknever {10000 } %~ Never break here. %^penalty
+\def \breakworst {500 } %~ Worst place to break. %^penalty
+\def \breakworse {300 } %~ Worse place to break. %^penalty
+\def \breakbad {100 } %~ Bad place to break. %^penalty
+\def \breakallowed {0 } %~ Break allowed here. %^penalty
+\def \breakgood {-100 } %~ Good place to break. %^penalty
+\def \breakbetter {-300 } %~ Better place to break. %^penalty
+\def \breakbest {-500 } %~ Best place to break. %^penalty
+\def \breakalways {-10000 } %~ Always break here. %^penalty
+
+
+\def \allowbreak {\penalty \breakallowed} %~ Allow page break here.
+\def \break {\penalty \breakalways} %~ Force page break here.
+\def \nobreak {\penalty \breaknever} %~ Disallow page break here.
+\let \unbreakable = \nobreak
+
+% Versions
+% --------
+
+
+% I have no idea what my intention was here.
+
+
+\def \defineversion #1#2{% {\name}{status}
+ \if #2%
+ \let \znext = \zletiftrue
+ \else
+ \let \znext = \zletiffalse
+ \fi
+ \withname\let {\end \expandafter\discardtok\string#1} = \fi
+ \znext{#1}}
+
+\def \zletiftrue #1{%
+ \let #1 = \iftrue}
+
+\def \zletiffalse #1{%
+ \let #1 = \iffalse}
+
+
+\defineversion{\ignore}{\false}
+
+% Translator Flags
+% ---------- -----
+
+
+\def \XTran<#1>{%
+ \error{xtran}{XTran flag: #1}}
+
+\def \ZzTran[#1]{%
+ \error{zztran}{ZzTran flag: #1}}
diff --git a/macros/plain/contrib/zztex/tex/zzmtime.tex b/macros/plain/contrib/zztex/tex/zzmtime.tex
new file mode 100644
index 0000000000..fd19871257
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzmtime.tex
@@ -0,0 +1,89 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX MathTime Font Support
+%
+% Synopsis: This module contains various definitions and redefinitions
+% necessary to use the MathTime fonts by The TeXplorators Corp.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 March 1993
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Type Styles
+% ---- ------
+
+\setstyleskewchar{\mit}{"2D}
+
+% Redefine Text Accents
+% -------- ---- -------
+
+
+\def \t #1{% %~ Tie-after accent. %^accent
+ {\edef \znext {\the\font}\the\textfont2 \accent "41 \znext #1}}
+
+% Redefine Math Characters
+% -------- ---- ----------
+
+
+\zmchar \Gamma \classord \mitfam {30}
+\zmchar \Delta \classord \mitfam {31}
+\zmchar \Theta \classord \mitfam {32}
+\zmchar \Lambda \classord \mitfam {33}
+\zmchar \Xi \classord \mitfam {34}
+\zmchar \Pi \classord \mitfam {35}
+\zmchar \Sigma \classord \mitfam {36}
+\zmchar \Upsilon \classord \mitfam {37}
+\zmchar \Phi \classord \mitfam {38}
+\zmchar \Psi \classord \mitfam {39}
+\zmchar \Omega \classord \mitfam {7F}
+
+\zmchar \varkappa \classord \mitfam {7E}
+
+\zmchar {`+} \classbinop \msyfam {43}
+\zmchar \compose \classbinop \msyfam {42}
+\zmchar \capprod \classbinop \msyfam {5A}
+\zmchar \cupprod \classbinop \msyfam {59}
+% Do not define \zmdagger and \zmddagger.
+\zmchar \setdiff \classbinop \msyfam {58}
+
+\zmchar \triangleleft \classbinop \msyfam {47}
+\zmchar \triangleright \classbinop \msyfam {46}
+
+\zmchar {`=} \classrel \msyfam {44}
+
+\zmchar {`(} \classopen \mitfam {2E}
+\definemathdelimiter {`(} \classord \mitfam {2E} \mexfam {00}
+
+\zmchar {`)} \classclose \mitfam {2F}
+\definemathdelimiter {`)} \classord \mitfam {2F} \mexfam {01}
+
+\def \hbar {\mathord{h \llap{$\mathchar"024E \mkern 3.5mu$}}}
+
+\def \acute {\zmtaccent{024B}{7013}} %~ Acute accent. %^math_accent
+\def \bar {\zmtaccent{024E}{7016}} %~ Bar accent. %^math_accent
+\def \breve {\zmtaccent{024D}{7015}} %~ Breve accent. %^math_accent
+\def \check {\zmtaccent{024C}{7014}} %~ Check accent. %^math_accent
+\def \ddot {\zmtaccent{0252}{????}} %~ Double dot accent. %^math_accent
+\def \dot {\zmtaccent{0250}{700B}} %~ Dot accent. %^math_accent
+\def \grave {\zmtaccent{024A}{7012}} %~ Grave accent. %^math_accent
+\def \zmhat {\zmtaccent{024F}{7007}} %~ Hat accent. %^math_accent
+\def \zmtilde {\zmtaccent{0251}{700F}} %~ Tilde accent. %^math_accent
+\def \vec {\mathaccent "0245\relax} %~ Vector accent. %^math_accent
+\def \widebar {\mathaccent "0253\relax} %~ Wide bar accent. %^math_accent
+
+\def \zmtaccent #1#2{%
+ \if \eqlp{\fam}{-1}%
+ \mathaccent "#1\relax
+ \else
+ \mathaccent "#2\relax
+ \fi}
+
+% Redefine General Tools
+% -------- ------- -----
+
+
+\zmchar \Relbar \classrel \msyfam {48}
diff --git a/macros/plain/contrib/zztex/tex/zznewmath.tex b/macros/plain/contrib/zztex/tex/zznewmath.tex
new file mode 100644
index 0000000000..583bb3d63a
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zznewmath.tex
@@ -0,0 +1,93 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Mathematics Facilities
+%
+% Synopsis: This file provides the mathematics facilities for "new math"
+% modes 1 and 2. It is loaded after the design file.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 16 October 2002
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Punctuation
+% -----------
+
+
+\if \eqlp{\newmath}{1}%
+
+\def \ldotp {\hbox to .42em{\hfil.\hfil}}
+
+\else\if \gtrp{\newmath}{1}%
+
+% This macro defines the math characters \zmperiod, \zmcomma,
+% colon, and semicolon to use the specified style.
+% If the style is \mit, then it's different.
+
+\def \setmathpunctuationstyle #1{% {style}
+ {\zmstyfam = \name{#1fam}%
+ \definemathchar {\zmperiod} \classord \zmstyfam {2E}
+ \definemathchar {\zmcomma} \classpunc \zmstyfam {2C}
+ \definemathchar {`;} \classpunc \zmstyfam {3B}
+ \definemathchar {`:} \classrel \zmstyfam {3A}}}
+
+% Now establish \rm as the default punctuation style.
+
+\setmathpunctuationstyle{\rm}
+
+% Period and comma must be active in math.
+
+\definemathchar {`.} \classactive \rmfam {00}
+
+\definemathchar {`,} \classactive \rmfam {00}
+
+% When period and comma are active in math, this is what they do.
+
+{
+\catcode `\. = \catactive
+\gdef .{\mathpalette\zmactperiod{}}
+
+\catcode `\, = \catactive
+\gdef ,{\mathpalette\zmactcomma{}}
+}
+
+\def \zmactperiod #1#2{%
+ \mathord{\hbox to .28em{\hfil $#1\zmperiod$\hfil}}}
+
+\def \zmactcomma #1#2{%
+ \mathpunct{\hbox to .33em{\hfil $#1\zmcomma$\kern .03em\hfil}}}
+
+% Now we can define all the dot-oriented math commands.
+
+\def \cdotp {\mathpunct{\vcenter{\hbox{$.$}}}}
+
+\def \ldotp {\mathpunct{.}}
+
+\def \cdots {\mathinner{\cdotp\cdotp\cdotp}}
+
+\def \ddots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{\kern .4em .}%
+ \hbox{\kern .8em .}%
+ \vskip -.25ex}}
+
+\def \ldots {\mathinner{\ldotp\ldotp\ldotp}}
+
+\def \vdots {%
+ \vbox{\baselineskip = 4pt \lineskiplimit = 0pt
+ \hbox{.}%
+ \hbox{.}%
+ \hbox{.}%
+ \vskip -.25ex}}
+
+% Make \maps and \colon do the right thing.
+
+\def \maps {\mathpunct{:}}
+
+\let \colon = \maps
+
+\fi\fi
diff --git a/macros/plain/contrib/zztex/tex/zznote.tex b/macros/plain/contrib/zztex/tex/zznote.tex
new file mode 100644
index 0000000000..412d46c98a
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zznote.tex
@@ -0,0 +1,522 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Notes Facilities
+%
+% Synopsis: This module defines various blocks that produce "notes", such
+% as footnotes.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 28 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Footnotes
+% ---------
+
+
+\defineblock{\footnote}{\endfootnote}{\true}{}
+
+% The footnote parameters are used at two different times: when the
+% \footnote macro appears, and when the page is output.
+
+% The \referencing parameter takes the following values:
+% 0: Produce neither a reference nor an intro number.
+% 1: Produce an intro number, but no reference.
+% 2: Produce both a reference and an intro number.
+
+%~block footnote
+% \aboveskip = glue % Space b/b above first footnote line.
+% \setflag \abutting = flag % True if note abutts previous one.
+% \bodyfont = {...} % Font for footnote text.
+% \def \comptextformat {...} % Composite number text formatter.
+% \internoteskip = glue % Extra space between footnotes.
+% \leftindent = glue % Left indentation.
+% \height = dimen % Maximum height on page.
+% \interlinepenalty = penalty % Penalty between footnote lines.
+% \def \noteintroformat {...} % Footnote intro formatter.
+% \def \noterefformat {...} % Footnote reference formatter.
+% \parindent = dimen % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \referencing = integer % How the footnote is referenced.
+% \rightindent = glue % Right indentation.
+% \rulecolor = {...} % Color of rule.
+% \rulewidth = dimen % Width of rule.
+% \ruleheight = dimen % Height of rule.
+% \ruleshift = dimen % Horizontal shift of rule.
+% \ruleskip = dimen % Space b/b below rule.
+% \def \spilloverride {...} % Override parameters on spillover.
+% \textcolor = {...} % Color of text.
+%~end
+
+\defineskip{\internoteskip}{0pt}
+\definecount{\referencing}{0}
+
+\defineinsert{\zfninsert}
+
+
+\def \footnote {% {text}
+ \blockcantbein{\footnote}{\footnote}%
+ \beginblockscope{footnote}%
+ \global\increment \footnotedepth
+ \setflag \abutting = \false %~default with
+ \referencing = 2 %~default with
+ \interlinepenalty = \breakworse %~default hard
+ \rulecolor = {black}% %~default soft
+ \ruleshift = 0pt %~default soft
+ \def \spilloverride {}% %~default soft
+ \textcolor = {black}% %~default soft
+ \processdesign{\footnote}{}%
+ \if \posp{\referencing}%
+ \global\increment \footnotenumber
+ \setcomptext{\footnotecomptext}%
+ \else
+ \footnotecomptext = {???}%
+ \fi
+ \settaginfo{\the\footnotecomptext}{???}%
+ \if \andp{\hmodep}{\eqlp{\referencing}{2}}%
+ {\edef \zsf {\spacefactor=\the\spacefactor}%
+ \/%
+ \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 1}\fi
+ \noterefformat
+ \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
+ \zsf}%
+ \fi
+ \footnoteinsert}
+
+\def \footnoteinsert {%
+ \the\bodyfont
+ \global\count\zfninsert = 1000
+ \global\dimen\zfninsert = \height
+ \global\skip\zfninsert = \aboveskip
+ \global\advance \skip\zfninsert by -\internoteskip
+ \global\advance \skip\zfninsert by -\ht\strutbox % of footnote text.
+ \insert \zfninsert \bgroup
+ \zpushvcontext
+ \color{\the\textcolor}%
+ \setindentation{\leftindent}{\rightindent}%
+ \setparrag{\parrag}%
+ \parfillskip = \normalparfillskip
+ \spaceskip = 0pt \xspaceskip = 0pt
+ \splittopskip = \ht\strutbox
+ \advance \splittopskip by \internoteskip
+ \splitmaxdepth = \dp\strutbox
+ \floatingpenalty = 20000\relax % Reference on same page as note.
+ \if \posp{\referencing}%
+ \noteintroformat
+ \else
+ \indent
+ \fi
+ \vbox to \splittopskip{}% % Strut in first line.
+ \bgroup
+ \aftergroup\endfootnote
+ \let \znext} % Eat open brace of footnote text.
+ % Absorb footnote text.
+ % \bgroup matches close brace.
+
+\def \endfootnote {%
+ \if \hmodep \strut \fi % Strut in last line.
+ \endgraf
+ \unskip
+ \endcolor
+ \zpopvcontext
+ \egroup % \insert
+ \global\decrement \footnotedepth
+ \endblockscope{footnote}}
+
+% This macro is invoked by the output routine to format footnotes.
+
+\def \zfootnoteformat #1{% {body-depth}
+ \beginblockscope{footnote}%
+ \ruleshift = 0pt
+ \def \spilloverride {}%
+ % We used to do the \processdesign here, but that does a \processwith
+ % that can end up processing some other block's pending \with. Oops.
+ \footnotedesign \relax % \processdesign{\footnote}{}
+ \if \notp{\emptydefp{\spilloverride}}%
+ \setbox \zboxa = \vtop{\unvcopy \zfninsert}%
+ \if \dimzerop{\ht\zboxa}\spilloverride \fi
+ \fi
+ \vskip \skip\zfninsert
+ \vskip -#1\relax
+ \if \andp{\dimposp{\ruleheight}}{\dimposp{\rulewidth}}%
+ \the\bodyfont
+ \tdimena = \ruleskip
+ \advance \tdimena by -\ht\strutbox
+ \advance \tdimena by -\internoteskip
+ \vskip -\tdimena
+ \vskip -\ruleheight
+ \nointerlineskip
+ \noindent \hspace{\ruleshift}%
+ \color{\the\rulecolor}\rule{height \ruleheight depth 0pt width \rulewidth}%
+ \endcolor\par
+ \vskip \tdimena
+ \fi
+ \unvbox \zfninsert
+ \endblockscope{footnote}}
+
+% Endnote
+% -------
+
+
+\defineblock{\endnote}{\endendnote}{\true}{}
+
+% The endnote parameters are used at two different times: when the
+% \endnote command appears, and when the \endnotes command is used
+% to typeset the notes.
+
+%~block endnote
+% \setflag \abutting = flag % True if note abutts previous one.
+% \def \comptextformat {...} % Composite number text formatter.
+% \endnoteclass = integer % Class of endnote.
+% \def \noterefformat {...} % Footnote reference formatter.
+% \referencing = integer % How the endnote is referenced.
+%~end
+
+\definecount{\endnoteclass}{0}
+\definetoks{\zendtoks}
+
+
+\def \endnote {% {text}
+ \blockcantbein{\endnote}{\endnote}%
+ \beginblockscope{endnote}%
+ \global\increment \endnotedepth
+ \setflag \abutting = \false %~default with
+ \endnoteclass = 0 %~default with
+ \referencing = 2 %~default with
+ \processdesign{\endnote}{}%
+ \global\increment \endnotenumber
+ \setcomptext{\endnotecomptext}%
+ \if \andp{\hmodep}{\eqlp{\referencing}{2}}%
+ {\edef \zsf {\spacefactor = \the\spacefactor}%
+ \/%
+ \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 1}\fi
+ \noterefformat
+ \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
+ \zsf}%
+ \fi
+ \afterassignment \endendnote
+ \zendtoks =}
+
+\def \endendnote {%
+ \edef \zendtext {\the\zendtoks}%
+ \edef \znext {\noexpand\xref{end}{\noexpand\folio}{\the\endnotecomptext}
+ {\expandafter\zdefof \meaning\zendtext\zmark}
+ {\the\divisionname,\the\endnoteclass}}%
+ \znext
+ \global\decrement \endnotedepth
+ \endblockscope{endnote}}
+
+% Endnotes
+% --------
+
+
+\defineblock{\endnotes}{\endendnotes}{\false}{}
+
+%~block endnotes
+% \setflag \abutting = flag % True if note abutts previous one.
+% \def \comptextformat {...} % Composite number text formatter.
+% \endnoteclass = integer % Class of endnote.
+% \def \noterefformat {...} % Footnote reference formatter.
+% \referencing = integer % How the endnote is referenced.
+%~end
+
+\definecount{\endnotepage}{0}
+\definetoks{\zenddivlist}
+\definetoks{\zenddiv}
+\definecount{\zendclass}{0}
+
+\def \endnotes #1{% {division-list}
+ \blockcantbein{\endnotes}{\endnotes}%
+ \blockmustbein{\endnotes}{\list}%
+ \beginblockscope{endnotes}%
+ \global\increment \endnotesdepth
+ \endnoteclass = 0 %~default with
+ \processdesign{\endnote}{}% % Use endnote block's design.
+ \global\increment \endnotesnumber
+ \zenddivlist = {#1}%
+ \zxloadcomp{\xrefloadendmode}%
+ \endendnotes}
+
+\def \endendnotes {%
+ \endgraf
+ \fakepar
+ \setlist \zendadjlist = {}%
+ \global\decrement \endnotesdepth
+ \endblockscope{endnotes}}
+
+% This macro is called for each endnote entry in the cross-reference file.
+
+\long\def \xrefend #1#2#3#4{%
+ \ifnum \xrefmode=\xrefloadendmode
+ \xrefendb{#1}{#2}{#3}{#4}%
+ \fi}
+
+\long\def \xrefendb #1#2#3#4{% {page}{number}{text}{division,class}
+ \def \znext ##1,##2,##3\zmark{%
+ \zenddiv={##1}\zendclass=##2}%
+ \znext #4,0,\zmark \relax
+ \if \eqlp{\zendclass}{\endnoteclass}%
+ \edef \znext {\noexpand\inclusionlist\noexpand\zendtest
+ {\the\zenddiv}{\the\zenddivlist}}%
+ \znext
+ \if \zendtest
+ \setbox \zboxa = \hbox{\zendclass=0#1}%
+ \endnotepage = \if \dimzerop{\wd\zboxa}#1\else 0 \fi
+ \let \xrefmode = \xrefrunmode
+ \zchkendadj{#2}%
+ \item{#2}#3\par
+ \let \xrefmode = \xrefloadendmode
+ \fi
+ \fi}
+
+% This macro allows the compositor to noninvasively adjust pages between
+% endnotes.
+
+\setlist \zendadjlist = {}
+
+\long\def \endnotesadjustment #1#2{% {division.number}{commands}
+ \append{{#1}{#2}}{\zendadjlist}}
+
+\long\def \zchkendadj #1{% {number}
+ \maplist{\zchkendadjb{#1}##1}{\zendadjlist}}
+
+\long\def \zchkendadjb #1#2#3{% {number}{division.number}{commands}
+ \stringeql{\znext}{\the\zenddiv.#1}{#2}%
+ \if \znext #3\relax \fi}
+
+% Margin Notes
+% ------ -----
+
+
+\defineblock{\marginnote}{\endmarginnote}{\true}{}
+
+%~block marginnote Type
+% \def \beginformat {...} % Beginning of text formatter.
+% \bodyfont = {...} % Font for note text.
+% \def \comptextformat {...} % Composite number text formatter.
+% \def \endformat {...} % End of text formatter.
+% \leftindent = glue % Left indentation.
+% \margingutter = dimen % Gutter for note in right margin.
+% \def \noteintroformat {...} % Note intro formatter.
+% \def \noterefformat {...} % Note reference formatter.
+% \parindent = dimen % Paragraph indent.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \position = {...} % Position (see below).
+% \referencing = integer % How the margin note is referenced.
+% \rightindent = glue % Right indentation.
+% \textcolor = {...} % Color of text.
+% \vshift = dimen % Vertical shift for note.
+% \width = dimen % Width of text in box.
+%~end
+
+\definedimen{\margingutter}{0pt}
+\definecount{\marginnotepage}{0}
+
+\definecount{\zdivmncounter}{0}
+\definedimen{\zmnshift}{0pt}
+\definetoks{\zmntoks}
+\definebox{\zmnbox}
+\definedimen{\zmnprevdepth}{0pt}
+
+
+\def \marginnote #1{% {type}
+ \blockcantbein{\marginnote}{\marginnote}%
+ \beginblockscope{marginnote}%
+ \global\increment \marginnotedepth
+ \global\increment \zdivmncounter
+ \whichpage{\marginnotepage}{zM:\the\divisionname-\the\zdivmncounter}%
+ \def \beginformat {}% %~default soft
+ \def \endformat {}% %~default soft
+ \leftindent = 0pt %~default soft
+ \referencing = 0 %~default soft
+ \rightindent = 0pt %~default soft
+ \textcolor = {black}% %~default soft
+ \vshift = 0pt %~default soft
+ \processdesign{\marginnote}{#1}%
+ \zparsemnpos{\the\position}%
+ \if \posp{\referencing}%
+ \global\increment \marginnotenumber
+ \setcomptext{\marginnotecomptext}%
+ \else
+ \marginnotecomptext = {???}%
+ \fi
+ \settaginfo{\the\marginnotecomptext}{???}%
+ \if \andp{\hmodep}{\eqlp{\referencing}{2}}%
+ {\edef \zsf {\spacefactor=\the\spacefactor}%
+ \/%
+ \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 1}\fi
+ \noterefformat
+ \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
+ \zsf}%
+ \fi
+ \afterassignment \endmarginnote
+ \zmntoks =}
+
+\def \endmarginnote {%
+ \setbox \zmnbox = \vtop{%
+ \zpushvcontext
+ \color{\the\textcolor}%
+ \the\bodyfont
+ \setindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}
+ \setparrag{\parrag}%
+ \beginformat
+ \if \posp{\referencing}\noteintroformat \fi
+ \the\zmntoks
+ \endgraf
+ \endformat
+ \endcolor
+ \zpopvcontext}%
+ \marginnoteformat
+ \global\decrement \marginnotedepth
+ \endblockscope{marginnote}}
+
+\def \marginnoteformat {%
+ \if \vmodep
+ \zmnprevdepth = \prevdepth
+ \nointerlineskip
+ \else
+ \vadjust
+ \fi
+ \bgroup
+ \moveright \zmnshift \vtop to 0pt{%
+ \vskip \vshift
+ \box \zmnbox
+ \vss
+ \tagpageonly{\uniquetag{zM}{\the\zdivmncounter}}}%
+ \egroup
+ \if \vmodep \prevdepth = \zmnprevdepth \fi}
+
+% This macro sets up variables that specify the position of a margin note
+% according to the \position design parameter:
+%
+% \ifevenpage Use next position only on even page.
+% \ifoddpage Use next position only on odd page.
+% \leftmargin Shift note to left margin.
+% \outsidemargin Shift note to outside margin.
+% \rightmargin Shift note to right margin.
+
+\definecount{\zmnhpos}{0}
+
+\def \zparsemnpos #1{% {options...}
+ \global\zmnhpos = 0
+ {\def \ifevenpage ##1{\if \evenp{\marginnotepage}##1\fi}%
+ \def \ifoddpage ##1{\if \oddp{\marginnotepage}##1\fi}%
+ \def \leftmargin {\global\zmnhpos=1\relax}%
+ \def \outsidemargin{\ifevenpage{\leftmargin}\ifoddpage{\rightmargin}}%
+ \def \rightmargin {\global\zmnhpos=2\relax}%
+ #1\relax}%
+ \ifcase \zmnhpos
+ \error{nomnpos}
+ {No horizontal position has been specified for a margin note}%
+ \or
+ \if \evenp{\marginnotepage}%
+ \zmnshift = -\evenlefttextmargin
+ \else
+ \zmnshift = -\oddlefttextmargin
+ \fi
+ \or
+ \calculate \zmnshift = {\textmeasure,+,\margingutter}%
+ \fi}
+
+% This macro is invoked at the beginning of each division.
+
+\def \zmndivinit {%
+ \global\zdivmncounter = 0\relax}
+
+% Proof Notes
+% ----- -----
+
+
+\defineblock{\proofnote}{\endproofnote}{\true}{}
+
+%~block proofnote
+% \bodyfont = {...} % Font for note text.
+% \evenshift = dimen % Horizontal shift for even pages.
+% \oddshift = dimen % Horizontal shift for odd pages.
+% \textcolor = {...} % Color of note.
+% \vshift = dimen % Vertical shift for note.
+% \width = dimen % Width of note.
+%~end
+
+\definedimen{\evenshift}{0pt}
+\definedimen{\oddshift}{0pt}
+
+\definecount{\zdivpncounter}{0}
+\definecount{\zpnpage}{0}
+
+
+\def \proofnote {% {text}
+ \blockcantbein{\proofnote}{\proofnote}%
+ \beginblockscope{proofnote}%
+ \global\increment \proofnotedepth
+ \global\increment \zdivpncounter
+ \whichpage{\zpnpage}{zP:\the\divisionname-\the\zdivpncounter}%
+ \parindent = 0pt
+ \parskip = 2pt
+ \textcolor = {black}% %~default soft
+ \vshift = 0pt %~default soft
+ \processdesign{\proofnote}{}%
+ \afterassignment \endproofnote
+ \zmntoks =}
+
+\def \endproofnote {%
+ \zcalcpnshift
+ \setbox \zmnbox = \vtop{%
+ \zpushvcontext
+ \color{\the\textcolor}%
+ \the\bodyfont
+ \settextwidth{\width}
+ \setparrag{.4\width}%
+ \def \endpartext {}% % Prevent end-of-paragraph text.
+ \the\zmntoks
+ \endgraf
+ \endcolor
+ \zpopvcontext}%
+ \proofnoteformat
+ \long\edef \znext {\noexpand\todo{.Proof note: \the\zmntoks}}%
+ \znext
+ \global\decrement \proofnotedepth
+ \endblockscope{proofnote}}
+
+\def \proofnoteformat {%
+ \if \vmodep
+ \zmnprevdepth = \prevdepth
+ \nointerlineskip
+ \else
+ \vadjust
+ \fi
+ \bgroup
+ \moveright \zmnshift \vtop to 0pt{%
+ \vskip -\parskip
+ \vskip \vshift
+ \box \zmnbox
+ \vss
+ \tagpageonly{\uniquetag{zP}{\the\zdivpncounter}}}%
+ \egroup
+ \if \vmodep \prevdepth = \zmnprevdepth \fi}
+
+\def \zcalcpnshift {%
+ \if \evenp{\zpnpage}%
+ \if \negp{\evenshift}%
+ \zmnshift = \evenshift
+ \else
+ \calculate \zmnshift = {\textmeasure,+,\evenshift}%
+ \fi
+ \else
+ \if \negp{\oddshift}%
+ \zmnshift = \oddshift
+ \else
+ \calculate \zmnshift = {\textmeasure,+,\oddshift}%
+ \fi
+ \fi}
+
+% This macro is invoked at the beginning of each division.
+
+\def \zpndivinit {%
+ \global\zdivpncounter = 0\relax}
diff --git a/macros/plain/contrib/zztex/tex/zzoverlay.tex b/macros/plain/contrib/zztex/tex/zzoverlay.tex
new file mode 100644
index 0000000000..e957ebd35e
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzoverlay.tex
@@ -0,0 +1,100 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Page Overlay Facilities
+%
+% Synopsis: This file provides the ability to overlay text and rules
+% on each page.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 29 March 2006
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Overlay & Proof Identification
+% ------- - ----- --------------
+
+
+\setflag \zoverlayset = \false
+\definetoks{\zoverlay}
+\zoverlay = {blind}
+\definetoks{\zproofid}
+\zproofid = {}
+
+\def \setpageoverlay #1{% {name}
+ \global\setflag \zoverlayset = \true
+ \global\zoverlay = {#1}}
+
+\def \proofidentification #1{% {text}
+ \zproofid = {#1}}
+
+\def \zproofidfile {%
+ \immediate\openout \zwritea = \jobname.zzq\relax
+ \immediate\write \zwritea {\the\zproofid}%
+ \immediate\closeout \zwritea}
+
+% Builtin Overlays
+% ------- --------
+
+
+\definedimen{\zoverlaythickness}{.4pt}
+
+
+\def \pageoverlayblind {}
+
+\def \pageoverlaytrimbox {%
+ \smashbox{%
+ \vbox to \trimheight{%
+ \topcornermarks{\trimwidth}{.5\trimheight}{\zoverlaythickness}%
+ \vss
+ \bottomcornermarks{\trimwidth}{.5\trimheight}{\zoverlaythickness}}}%
+ \zpagelengthmarks
+ \zslugline}
+
+\def \pageoverlaytrimmarks {%
+ \smashbox{%
+ \vbox to \trimheight{%
+ \topcornermarks{\trimwidth}{.75pc}{\zoverlaythickness}%
+ \vss
+ \bottomcornermarks{\trimwidth}{.75pc}{\zoverlaythickness}}}%
+ \zpagelengthmarks
+ \zslugline}
+
+% Page Length Marks
+% ---- ------ -----
+
+
+\def \zpagelengthmarks {%
+ \smashbox{%
+ \calculate \tdimena = {\headmargin,+,\typeareaheight,-,\footerheight}%
+ \vskip \tdimena
+ \hbox to \trimwidth{%
+ \llap{\vrule height \zoverlaythickness width .75pc}\hfil
+ \rlap{\vrule height \zoverlaythickness width .75pc}}}}
+
+% Slug Line
+% ---- ----
+
+
+\definedimen{\zslugindent}{.25in}
+
+
+\def \zslugline {%
+ \if \notp{\emptytoksp{\zproofid}}%
+ \kern \trimheight
+ \if \dimgtrp{\trimheight}{10.75in}\kern -.25in \fi
+ \kern -8pt
+ \hbox to \trimwidth{%
+ \hspace{\zslugindent}%
+ \zannofont
+ \the\zproofid \quad
+ \number\year/\number\month/\number\day\space \formattime \quad
+ p. \folio \hspace{5pt}%
+ \if \notp{\emptytoksp{\divisionname}}(\the\divisionname)\fi
+ \hfill
+ \inicompositor, \iniinitials \quad
+ \ZzTeX\ \ZzTeXversion
+ \hspace{\zslugindent}}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zzpage.tex b/macros/plain/contrib/zztex/tex/zzpage.tex
new file mode 100644
index 0000000000..a666c18094
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzpage.tex
@@ -0,0 +1,908 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Page Facilities
+%
+% Synopsis: This module contains all the user facilities for
+% specifying things about the page layout. It also
+% contains the output routines.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 7 March 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Tracing Page Makeup
+% ------- ---- ------
+
+
+\def \tracepagemakeup #1{%
+ \if \posp{\tracingpagemakeup}%
+ \writelog{ZzTeX page \the\pagenumber: #1}%
+ \fi}
+
+% Initialize Page Parameters
+% ---------- ---- ----------
+
+
+% Here we assume that the type area width is the same on both pages.
+
+\def \zpageinit {%
+ \gcalculate \trimplusbleedheight = {\standardbleed,+,\trimheight,+,%
+ \standardbleed}%
+ \gcalculate \trimplusbleedwidth = {\standardbleed,+,\trimwidth,+,%
+ \standardbleed}%
+ \gcalculate \typeareawidth = {\oddlefttextmargin,+,\textmeasure,+,%
+ \oddrighttextmargin}%
+ \gcalculate \evenoutermargin = {\trimwidth,-,\typeareawidth,-,%
+ \eveninnermargin}%
+ \gcalculate \evenbleedshift = {-\evenlefttextmargin,-,\evenoutermargin,-,%
+ \standardbleed}%
+ \gcalculate \oddoutermargin = {\trimwidth,-,\typeareawidth,-,%
+ \oddinnermargin}%
+ \gcalculate \oddbleedshift = {-\oddlefttextmargin,-,\oddinnermargin,-,%
+ \standardbleed}}
+
+% Page Number
+% ---- ------
+
+
+\countdef \pagenumber = 0
+
+\declaresnapitem{\pagenumber}
+
+\def \setpagenumber #1{% {number}
+ \global\pagenumber = #1\relax
+ \setcolumnnumber{1}}
+
+\def \evenpagep {\evenp{\pagenumber}}
+\def \oddpagep {\oddp{\pagenumber}}
+
+\def \folio {}
+
+\def \setfoliostyle #1{% {\style}
+ \ztoksa = \expandaftertwice{\name{#1folio}}%
+ \xdef \folio {\the\ztoksa}}
+
+\def \chapterpagefolio {\the\chaptercomptext-\number\pagenumber}
+\def \arabicfolio {\number\pagenumber}
+\let \decimalfolio = \arabicfolio
+\def \letterfolio {\ucletter\pagenumber}
+\def \partpagefolio {\the\partcomptext-\number\pagenumber}
+\def \romanfolio {\romannumeral\pagenumber}
+
+% Marks
+% -----
+
+
+% These macros hold the five parts of the current mark, each part having
+% three subparts. When a part is saved, the first subpart is expanded and
+% the second and third subparts are not.
+
+\definetoks{\zmarki} \zmarki = {{???}{???}{???}}
+\definetoks{\zmarkii} \zmarkii = {{???}{???}{???}}
+\definetoks{\zmarkiii} \zmarkiii = {{???}{???}{???}}
+\definetoks{\zmarkiv} \zmarkiv = {{???}{???}{???}}
+\definetoks{\zmarkv} \zmarkv = {{???}{???}{???}}
+
+
+\def \setmarkinfothree #1#2#3#4{% {part}{text1}{text2}{text3}
+ {\tcounta = #1\relax
+ \edef \znext {{#2}}%
+ \global\name{\zmark\romannumeral\tcounta} = \expandafter{\znext{#3}{#4}}%
+ \mark{\noexpand\or \the\zmarki \noexpand\or \the\zmarkii
+ \noexpand\or \the\zmarkiii \noexpand\or \the\zmarkiv
+ \noexpand\or \the\zmarkv}}%
+ \if \vmodep \repeatpenalty \fi} % In case glue follows the mark.
+
+\def \setmarkinfo #1#2#3{% {part}{text1}{text2}
+ \setmarkinfothree{#1}{#2}{#3}{???}}
+
+
+\let \firstnewmark = \firstmark
+\let \bottommark = \botmark
+
+\def \markinfo #1#2#3{% {mark}{part}{subpart}
+ \ifcase #3%
+ \relax
+ \or
+ \expandafter\zoneofthree
+ \ifcase #2\expandafter\relax #1\else {???}{???}{???}\fi
+ \or
+ \expandafter\ztwoofthree
+ \ifcase #2\expandafter\relax #1\else {???}{???}{???}\fi
+ \or
+ \expandafter\zthreeofthree
+ \ifcase #2\expandafter\relax #1\else {???}{???}{???}\fi
+ \else
+ \error{invsubpart}{The subpart `#3' is invalid}%
+ \fi}
+
+% Page Screen
+% ---- ------
+
+
+\def \fullpagescreen #1{% {color}
+ \if \inbackground
+ \vskip -\standardbleed
+ \moveleft \standardbleed \vbox{%
+ \colorrule{#1}{width \trimplusbleedwidth height \trimplusbleedheight}}%
+ \else
+ \hrule width 0pt
+ \vsinkfromtrim{-\standardbleed}
+ \smashbox{%
+ \colorparrule{#1}
+ {\if \evenp{\pagenumber}\evenbleedshift \else \oddbleedshift \fi}
+ {width \trimplusbleedwidth height 0pt depth \trimplusbleedheight}}%
+ \fi}
+
+% New Headers & Footers Scheme
+% --- ------- - ------- ------
+
+
+% Most of the definitions are in zzrunner.tex, but these need to be in
+% here so they can be used in design files.
+
+
+\def \headerblindformat {}
+
+\def \footerblindformat {}
+
+\def \headercornermarkformat {%
+ \line{\vrule height .5pt depth 0pt width 6pt \hfil
+ \vrule height .5pt depth 0pt width 6pt}%
+ \nointerlineskip
+ \line{\vrule height 6pt depth 0pt width .5pt \hfil
+ \vrule height 6pt depth 0pt width .5pt}%
+ \vfil}
+
+\def \footercornermarkformat {%
+ \vfil
+ \line{\vrule height 6pt depth 0pt width .5pt \hfil
+ \vrule height 6pt depth 0pt width .5pt}%
+ \nointerlineskip
+ \line{\vrule height .5pt width 6pt \hfil
+ \vrule height .5pt width 6pt}}
+
+% Old Headers & Footers Scheme
+% --- ------- - ------- ------
+
+
+\def \zcurheader{\normalheader}
+\def \zcurfooter{\normalfooter}
+
+\setflag \zoverrunners = \false
+\let \zsaveheader = \relax
+\let \zsavefooter = \relax
+
+
+\def \setrunners #1#2{% {header}{footer}
+ \if \zoverrunners
+ \gdef \zsaveheader {#1}%
+ \gdef \zsavefooter {#2}%
+ \else
+ \gdef \zcurheader {#1}%
+ \gdef \zcurfooter {#2}%
+ \fi}
+
+\def \overriderunners #1#2{% {header}{footer}
+ \if \notp{\zoverrunners}%
+ \global\let \zsaveheader = \zcurheader
+ \global\let \zsavefooter = \zcurfooter
+ \global\setflag \zoverrunners = \true
+ \fi
+ \gdef \zcurheader {#1}%
+ \gdef \zcurfooter {#2}}
+
+\def \blindrunners {%
+ \overriderunners{\blindheader}{\blindfooter}}
+
+\def \zsetrunnerstoks #1{% {tokens}
+ \expandafter\overriderunners \the#1}
+
+\def \zoverriderunnerstoks #1{% {tokens}
+ \expandafter\overriderunners \the#1}
+
+% The following macro is used to initialize the \runners parameter.
+
+\def \zoldrunners #1{%
+ \runners = {#1}}
+
+% The following macro is called from the output routine.
+
+\def \znextpagerunners {%
+ \if \zoverrunners
+ \global\let \zcurheader = \zsaveheader
+ \global\let \zcurfooter = \zsavefooter
+ \global\setflag \zoverrunners = \false
+ \fi}
+
+
+% The following macros provide some standard, simple header and footer
+% formats.
+
+\def \blindheader {}
+
+\def \blindfooter {}
+
+\def \cornermarkheader {\headercornermarkformat}
+
+\def \cornermarkfooter {\footercornermarkformat}
+
+% The following header and footer formats are provided by the design.
+% Just in case they are forgotten:
+
+\def \normalheader {%
+ \warning{noheadfoot}{No normal header format has been specified}}
+\def \normalfooter {%
+ \warning{noheadfoot}{No normal footer format has been specified}}
+\def \chapterheader {%
+ \warning{noheadfoot}{No chapter header format has been specified}}
+\def \chapterfooter {%
+ \warning{noheadfoot}{No chapter footer format has been specified}}
+
+% Multiple Columns
+% -------- -------
+
+
+% The following parameters are calculated by the \setpagecolumns command:
+
+\setflag \zdofullbreak = \false % True if doing a full break.
+\setflag \zusetypewidth = \false % True if using type area width.
+
+\definecount{\columncount}{0} % Number of columns on page.
+\definecount{\columnnumber}{0} % Current column number.
+% \hsize
+% \vsize
+
+
+% The \setpagecolumns command accepts the following options:
+%
+% \fullbreak
+% \shortbreak
+% \usetextmeasure
+% \usetextwidth
+% \usetypewidth
+
+\def \setpagecolumns #1#2#3{% {options}{columns}{gutter-width}
+ \endgraf
+ {\def \fullbreak {\global\setflag \zdofullbreak = \true}%
+ \def \shortbreak {\global\setflag \zdofullbreak = \false}%
+ \def \usetextmeasure {\global\setflag \zutw = \false}%
+ \def \usetextwidth {\global\setflag \zutw = \false}%
+ \def \usetypewidth {\global\setflag \zutw = \true}%
+ \global\setflag \zdofullbreak = \false
+ \global\setflag \zutw = \false
+ #1}%
+ \if \andp{\zusetypewidth}{\notp{\zutw}}%
+ \zejectcolpage
+ \else\if \onep{\columncount}%
+ \if \orp{\gtrp{#2}{1}}{\zutw}\penalty \zpenoneton \fi
+ \else\if \neqlp{#2}{\columncount}%
+ \zejectcolpage
+ \fi\fi\fi
+ \global\columncount = #2\relax
+ \global\setflag \zusetypewidth = \zutw
+ \tdimena = \if \zusetypewidth \typeareawidth \else \textmeasure \fi
+ \calculate \tdimenb = {-#3,*,\columncount,+,#3,+,\tdimena,/,\columncount}%
+ \settextwidth{\tdimenb}%
+ \global\hsize = \hsize % Make these two parameters global.
+ \global\parfillskip = \parfillskip
+ \setcolumnnumber{1}%
+ \tracepagemakeup{Columns: \the\columncount; width: \the\hsize; gutter: #3.}}
+
+\def \zejectcolpage {%
+ \if \zdofullbreak
+ \freshpage{\full\floats\any}%
+ \else
+ \freshpage{\short\floats\any}%
+ \fi
+ \global\vsize = \textareaheight} % Needed even if no page eject.
+
+
+\def \setcolumnnumber #1{% {number}
+ \global\columnnumber = #1\relax
+ \if \andp{\oddpagep}{\lastcolumnp}%
+ \global\brokenpenalty = \oddbrokenpenalty
+ \else
+ \global\brokenpenalty = \evenbrokenpenalty
+ \fi}
+
+\def \firstcolumnp {\eqlp{\columnnumber}{1}}
+\def \lastcolumnp {\eqlp{\columnnumber}{\columncount}}
+
+
+%-----------------------------------------------------------------------------
+%
+% This old command is deprecated, although it will work forever.
+
+
+\def \setcolumns #1#2#3{% {count}{gutter-width}{use-type-area}
+ \endgraf
+ \if \andp{\zusetypewidth}{\notp{#3}}%
+ \freshpage{\short\floats\any}%
+ \global\vsize = \textareaheight % Needed even if no page eject.
+ \else \if \eqlp{\columncount}{1}%
+ \if \orp{\gtrp{#1}{1}}{#3}%
+ \penalty \zpenoneton
+ \fi
+ \else \if \neqlp{#1}{\columncount}%
+ \freshpage{\short\floats\any}%
+ \global\vsize = \textareaheight % Needed even if no page eject.
+ \fi\fi\fi
+ \global\columncount = #1\relax
+ \global\setflag \zusetypewidth = #3\relax
+ {\zpageinit
+ \tdimena = #2\relax
+ \multiply \tdimena by \columncount
+ \advance \tdimena by -#2\relax
+ \if \zusetypewidth
+ \advance \tdimena by -\typeareawidth
+ \else
+ \advance \tdimena by -\textmeasure
+ \fi
+ \divide \tdimena by -\columncount
+ \settextwidth{\tdimena}%
+ \global\hsize = \hsize % Make these two parameters global.
+ \global\parfillskip = \parfillskip}%
+ \setcolumnnumber{1}%
+ \tracepagemakeup{Columns: \the\columncount; width: \the\hsize; gutter: #2.}}
+
+% Column Breaks
+% ------ ------
+
+
+\def \columnbreak #1{% {penalty}
+ \penalty #1\relax}
+
+\def \freshcolumn #1{% {options}
+ {\let \zfill = \relax
+ \let \full = \relax \def \short {\def \zfill {\vfill}}%
+ #1\relax%
+ \if \notp{\dimzerop{\lastskip}}\vskip -\lastskip \fi
+ \zfill
+ \penalty \zpenfreshcol}}
+
+\def \fullcolumnbreak {\freshcolumn{\full}}
+\def \shortcolumnbreak {\freshcolumn{\short}}
+
+\def \blankcolumn {%
+ \line{}%
+ \shortcolumnbreak}
+
+% Page Breaks
+% ---- ------
+
+
+%~ This command starts a new page. The options specify the
+%~ exact behavior:
+%~ & |\any|& Start an even or odd page.
+%~ & |\even|& Start an even page.
+%~ & |\floats|& Place all floats before new page.
+%~ & |\full|& Current page is bottomed out.
+%~ & |\nofloats|& No need to place all floats.
+%~ & |\odd|& Start an odd page.
+%~ & |\short|& Run current page short.
+%~ &.
+
+\def \freshpage #1{% {options} %^page_makeup
+ \if \vmodep
+ {\let \zfill = \vfill
+ \let \short = \relax \def \full {\let \zfill = \relax}%
+ \let \zflush = \zpenfreshpage
+ \let \nofloats = \relax \def \floats {\let \zflush = \zpenflushpage}%
+ \let \zpage = \relax
+ \let \any = \relax
+ \def \odd {\def \zpage {\if \evenpagep \blankpage \fi}}%
+ \def \even {\def \zpage {\if \oddpagep \blankpage \fi}}%
+ #1\relax%
+ \if \notp{\dimzerop{\lastskip}}\vskip -\lastskip \fi
+ \zfill
+ \if \notp{\lastcolumnp}%
+ \penalty \zpenfreshcol
+ \if \notp{\lastcolumnp}%
+ \loop
+ \blankcolumn
+ \if \notp{\lastcolumnp}\repeat
+ \fi
+ \line{}%
+ \vfill
+ \fi
+ \penalty \zflush
+ \zpage}%
+ \else
+ \error{pagepar}{Page break requested in the middle of a paragraph}%
+ \fi}
+
+%~ This command starts a new page, bottoming out the current page.
+
+\def \fullpagebreak {\freshpage{\full\nofloats\any}} %^page_makeup
+
+%~ This command starts a new page, leaving the current page short.
+%~ The argument specifies the number of lines short, or, if
+%~ specified as |\asap|, runs the page as short as possible.
+
+\def \shortpagebreak #1{% {lines} %^page_makeup
+ {\def \zarg {#1}\def \zasap {\asap}%
+ \if \tokeqlp{\zarg}{\zasap}%
+ \freshpage{\short\nofloats\any}%
+ \else
+ \kern -\dp\strutbox
+ \kern #1\baselineskip
+ \fullpagebreak
+ \fi}}
+
+\def \blankpage {%
+ \blindrunners
+ \pagehint{(blank)}%
+ \hrule width 0pt
+ \freshpage{\short\nofloats\any}}
+
+\def \blankleaf {%
+ \freshpage{\short\floats\odd}
+ \blankpage
+ \freshpage{\short\even}
+ \blankpage}
+
+% Overriding Text Area Height
+% ---------- ---- ---- ------
+
+
+\definedimen{\zortahsave}{0pt} % Saved normal text area height.
+\definecount{\zortahcount}{0} % Number of overridden pages.
+
+
+%~ This command changes the number of lines on the specified number
+%~ of pages, beginning with the current page. The nominal line count
+%~ is increased or decreased by the specified number of lines,
+%~ which should be coded with a plus or minus sign. A fractional
+%~ number of lines is allowed. It is best to change two pages (a spread)
+%~ with each command.
+
+\def \overridetextareaheight #1#2{% {pages}{lines} %^page_makeup
+ \if \posp{\zortahcount}%
+ \warning{overortah}{Text area height overridden during previous override}%
+ \zresetortah
+ \fi
+ {\global\zortahsave = \textareaheight
+ \global\zortahcount = #1\relax
+ \global\advance \textareaheight by #2\baselineskip
+ \global\vsize = \textareaheight
+ \if \dimneqlp{\pagegoal}{\maxdimen}%
+ \tdimena = \textareaheight
+ \advance \tdimena by -\zortahsave
+ \advance \tdimena by \pagegoal
+ \global\pagegoal = \tdimena
+ \fi}%
+ \tracepagemakeup{Overriding text area height: pages: #1, vsize: \the\vsize,
+ goal: \the\pagegoal.}}
+
+\def \zresetortah {%
+ \global\zortahcount = 0
+ \global\textareaheight = \zortahsave
+ \global\vsize = \textareaheight
+%%% \global\pagegoal = \vsize
+ \tracepagemakeup{Un-overriding text area height: vsize: \the\vsize.}}
+
+\def \zortahdivfinal {%
+ \if \posp{\zortahcount}%
+ \warning{divortah}{Text area height overridden across a division}%
+ \zresetortah
+ \fi}
+
+% Text Margins
+% ---- -------
+
+
+% The following two macros are really bogus, because TeX doesn't
+% always know what page it's on, except in the output routine.
+
+\def \thislefttextmargin {%
+ \if \evenpagep \evenlefttextmargin \else \oddlefttextmargin \fi}
+
+\def \thisrighttextmargin {%
+ \if \evenpagep \evenrighttextmargin \else \oddrighttextmargin \fi}
+
+\definedimen{\typeareashift}{0pt}
+\definecount{\ztaspage}{0}
+
+\def \determinetypeareashift #1{% {page}
+ \global\typeareashift = \if \evenp{#1}-\evenlefttextmargin \else
+ -\oddlefttextmargin \fi}
+
+% Layout Summary
+% ------ -------
+
+
+{\catcode`\_ = \catactive
+
+\gdef \zlayoutsummary {%
+ {\def _{\space}%
+ \writelog{}%
+ \writelog{Layout:}%
+ \writelog{}%
+ \tdimena = .013837\trimwidth
+ \tdimenb = .013837\trimheight
+ \writelog{Trim: \thefactor\tdimena"_x_\thefactor\tdimenb"}%
+ \tdimena = .013837\headmargin
+ \writelog{Head margin: \thefactor\tdimena"}%
+ \tdimena = .083333\typeareawidth
+ \tdimenb = .083333\typeareaheight
+ \writelog{Type area: \thefactor\tdimena pc_x_\thefactor\tdimenb pc}%
+ \tdimena = .013837\eveninnermargin
+ \tdimenb = .013837\oddinnermargin
+ \writelog{Inside margins: even \thefactor\tdimena", odd \thefactor\tdimenb"}%
+ \tdimena = .013837\evenoutermargin
+ \tdimenb = .013837\oddoutermargin
+ \writelog{Outside margins: even \thefactor\tdimena", odd \thefactor\tdimenb"}%
+ \tdimena = .083333\evenlefttextmargin
+ \tdimenb = .083333\oddlefttextmargin
+ \writelog{Left text margins: even \thefactor\tdimena pc,
+ odd \thefactor \tdimenb pc}%
+ \tdimena = .083333\evenrighttextmargin
+ \tdimenb = .083333\oddrighttextmargin
+ \writelog{Right text margins: even \thefactor\tdimena pc,
+ odd \thefactor\tdimenb pc}%
+ \tdimena = .083333\textmeasure
+ \tdimenb = .083333\textareaheight
+ \writelog{Text area: \thefactor\tdimena pc_x_\thefactor\tdimenb pc}%
+ \writelog{Top skip: \the\topskip, delta: \the\topdelta}%
+ \writelog{}}}
+
+}% \catcode
+
+% Debugging
+% ---------
+
+
+\def \zlogoutf {-1} % First page to log.
+\def \zlogoutl {-1} % Last page to log.
+
+
+\def \logoutput #1#2{% {first-page}{last-page}
+ \global\def \zlogoutf {#1}%
+ \global\def \zlogoutl {#2}}
+
+% Output Routine
+% ------ -------
+
+
+% The following definitions are for special penalties that control
+% page makeup:
+
+\def \zpennormal {-10000\relax} % Normal page break.
+\def \zpenoneton {-10001\relax} % Switch from 1 to n columns.
+\def \zpenfreshcol {-10002\relax} % Fresh column.
+\def \zpenfreshpage {-10003\relax} % Fresh page.
+\def \zpenflushpage {-10004\relax} % Fresh page, and flush floats.
+\def \zpenfloatpage {-10005\relax} % Page of floats scheduled.
+
+% We need to put the depth of box 255 in a convenient place.
+
+\definedimen{\zoutputcoldepth}{0pt}
+
+% We must save \mathdisplayprevgraf across the output routine.
+
+\definecount{\zsavemdpg}{0}
+
+% The following boxes hold parts of the page:
+
+\definebox{\zcolbox} % One column's worth.
+\definebox{\zbodybox} % The body, multiple columns' worth.
+\definebox{\zonetonbox} % Stuff preceding 1- to n-column switch.
+\setflag \zonetontype = \false % True if 1-to-n text uses type area width.
+
+% This toks register is invoked at the beginning of every column, so that
+% things like index carryovers can be performed.
+
+\definetoks{\everycolumn}
+\everycolumn = {\relax}
+
+
+\output = {\zoutput}
+
+\def \zoutput {%
+ \if \andp{\notp{\lssp{\pagenumber}{\zlogoutf}}}%
+ {\notp{\gtrp{\pagenumber}{\zlogoutl}}}%
+ \tracingoutput = 1
+ \showboxdepth = 1000 \showboxbreadth = 1000\relax
+ \fi
+ \tracepagemakeup{[Output routine invoked for column \the\columnnumber;
+ penalty: \the\outputpenalty.}%
+ \tracepagemakeup{Vsize: \the\vsize;
+ Box 255: \the\ht255+\the\dp255 \space x \the\wd255.}%
+ \zoutputcoldepth = \dp255\relax
+ \let \zsavewith = \zwith % Save these items across the
+ \let \zsavevariant = \zvariant % output routine in case they
+ \zsavemdpg = \mathdisplayprevgraf % are altered within it.
+ \normalbaselines
+ \let \par = \endgraf
+ \everyparagraph = {}%
+ \spaceskip = 0pt
+ \tcounta = \outputpenalty
+ \if \eqlp{\tcounta}{-'10000000000}\tcounta = \zpenflushpage \fi
+ \if \gtrp{\tcounta}{-10000}\tcounta = -10000\relax \fi
+ \negate \tcounta
+ \advance \tcounta by -10000\relax
+ \ifcase \tcounta
+ \zpagenormal \or
+ \zpageoneton \or
+ \zpagefreshcol \or
+ \zpagefreshpage \or
+ \zpageflushpage \or
+ \zpagefloatpage \else
+ \zzerror{Invalid page break penalty: \the\outputpenalty}%
+ \fi
+ \global\let \zvariant = \zsavevariant
+ \global\let \zwith = \zsavewith
+ \global\mathdisplayprevgraf = \zsavemdpg
+ \tracepagemakeup{Output routine complete.]}}
+
+\def \zpagenormal {%
+ \tracepagemakeup{Process normal column.}%
+ \zcolumnsave
+ \if \lastcolumnp
+ \zpagecontents
+ \setcolumnnumber{1}%
+ \else
+ \tcounta = \columnnumber \increment \tcounta
+ \setcolumnnumber{\tcounta}%
+ \fi
+ \zfloatinit
+ \zschedulefloats{\zfloatcount}{\true}{\false}%
+ \if \gtrp{\zfloatcount}{99}%
+ \zfltpage{\zpenfloatpage}%
+ \else
+ \zeverycol
+ \fi}
+
+\def \zpageoneton {%
+ \tracepagemakeup{Process 1- to n-column transition.}%
+ \zonetoncolumnbody
+ \global\setflag \zonetontype = \zusetypewidth
+ \global\advance \vsize by -\ht\zonetonbox
+ \global\advance \vsize by -\dp\zonetonbox
+ \tracepagemakeup{Space remaining on page: \the\vsize.}}
+
+\def \zpagefreshcol {%
+ \tracepagemakeup{Process `fresh column' request.}%
+ \zpagenormal}
+
+\def \zpagefreshpage {%
+ \tracepagemakeup{Process `fresh page' request.}%
+ \zpagenormal}
+
+\def \zpageflushpage {%
+ \tracepagemakeup{Process `fresh page, flush floats' request.}%
+ \zcolumnsave
+ \if \lastcolumnp
+ \zpagecontents
+ \setcolumnnumber{1}%
+ \else
+ \tcounta = \columnnumber \increment \tcounta
+ \setcolumnnumber{\tcounta}%
+ \fi
+ \zfloatinit
+ \zschedulefloats{\zfloatcount}{\true}{\true}%
+ \if \posp{\zfloatcount}%
+ \zfltpage{\zpenflushpage}%
+ \else
+ \zeverycol
+ \fi}
+
+\def \zpagefloatpage {%
+ \tracepagemakeup{Process page of floats.}%
+ \zcolumnsave
+ \if \lastcolumnp
+ \zpagecontents
+ \setcolumnnumber{1}%
+ \else
+ \tcounta = \columnnumber \increment \tcounta
+ \setcolumnnumber{\tcounta}%
+ \fi
+ \zfloatinit
+ \zschedulefloats{\zfloatcount}{\true}{\false}%
+ \if \gtrp{\zfloatcount}{99}%
+ \zfltpage{\zpenfloatpage}%
+ \fi}
+
+\def \zfltpage #1{% {penalty}
+ \if \notp{\emptytoksp{\zfltrunners}}%
+ \zoverriderunnerstoks{\zfltrunners}%
+ \fi
+ {\leftskip = 0pt \rightskip = 0pt
+ \line{}}%
+ \kern -\topskip % Why bother to do this?
+ \nobreak \vfill
+ \penalty #1}
+
+\def \zeverycol {%
+ {\zadjtitle = \zadjtitlemark % \adjusttitle should adjust mark.
+ \def \zadjloc {\mark}%
+ \the\everycolumn}}
+
+% Page Makeup: Column
+% ---- ------- ------
+
+
+\def \zcolumnsave {%
+ \zcolumnbody
+ \if \firstcolumnp
+ \global\setbox \zbodybox = \hbox to \zbodyboxwidth {\box\zcolbox \hss}%
+ \ztoksa = \expandafter{\topmark}%
+ \xdef \topmarki {\the\ztoksa}%
+ \ztoksa = \expandafter{\firstnewmark}%
+ \xdef \firstnewmarki {\the\ztoksa}%
+ \ztoksa = \expandafter{\bottommark}%
+ \xdef \bottommarki {\the\ztoksa}%
+ \else
+ \global\setbox \zbodybox = \hbox to \zbodyboxwidth {%
+ \unhbox\zbodybox \hfill \box\zcolbox}%
+ \fi}
+
+\def \zbodyboxwidth {%
+ \if \zusetypewidth \typeareawidth \else \textmeasure \fi}
+
+\def \zcolumnbody {%
+ \tracepagemakeup{Wrapping up the column; hsize: \the\hsize.}%
+ {\vbadness = 10000\relax
+ \global\setbox \zcolbox = \vbox to \vsize {%
+ \setindentation{0pt}{0pt}%
+ \boxmaxdepth = \maxdepth
+ \if \notp{\voidboxp{\ztopcolinsert}}\unvbox \ztopcolinsert \fi
+ \unvbox 255 % Page built by TeX.
+ \if \risingfootnotes
+ \if \notp{\voidboxp{\zfninsert}}\zfootnoteformat{\zoutputcoldepth}\fi
+ \fi
+ \if \risingbottomfloats
+ \if \notp{\voidboxp{\zbotcolinsert}}\unvbox \zbotcolinsert \fi
+ \fi
+ \if \raggedbottom
+ \kern -\zoutputcoldepth \vfill
+ \fi
+ \if \notp{\risingfootnotes}%
+ \if \notp{\voidboxp{\zfninsert}}\zfootnoteformat{\zoutputcoldepth}\fi
+ \fi
+ \if \notp{\risingbottomfloats}%
+ \if \notp{\voidboxp{\zbotcolinsert}}\unvbox \zbotcolinsert \fi
+ \fi}}}
+
+% This is a special version of \zcolumnbody for the 1- to n-column
+% transition.
+
+\def \zonetoncolumnbody {%
+ \global\setbox \zonetonbox = \vbox{%
+ \setindentation{0pt}{0pt}%
+ \boxmaxdepth = \maxdepth
+ \if \notp{\voidboxp{\ztopcolinsert}}\unvbox \ztopcolinsert \fi
+ \unvbox 255 % Page built by TeX.
+ \vskip \baselineskip
+ \vskip -\topskip
+ % Ignore footnotes.
+ % Ignore bottom style.
+ % Ignore bottom floats.
+ % Don't produce text area bottom rule.
+ }}
+
+% Page Makeup: Page
+% ---- ------- ----
+
+
+\def \zpagecontents {%
+ \tracepagemakeup{Shipping out the final page.}%
+ \shipout \vbox to \trimheight {%
+ \parskip = 0pt \parindent = 0pt
+ \setindentation{0pt}{0pt}%
+ \zpageheadmargin
+ \nointerlineskip
+ \zpagetypearea
+ \vfil
+ \nointerlineskip
+ \zpageoverlay}%
+ \if \posp{\zortahcount}% % If overriding text area height:
+ \global\decrement \zortahcount
+ \if \zerop{\zortahcount}\zresetortah \fi
+ \fi
+ \tcounta = \pagenumber \increment \tcounta
+ \setpagenumber{\tcounta}%
+ \global\vsize = \textareaheight % In case it was reset for this page.
+ \znextpagerunners}
+
+\def \zpagelengthmarks {%
+ \tdimena = \headmargin
+ \advance \tdimena by \typeareaheight
+ \advance \tdimena by -\footerheight
+ \vskip \tdimena
+ \vbox to 0pt{%
+ \hbox to \trimwidth{%
+ \llap{\vrule height .5pt width .75pc}\hfil
+ \rlap{\vrule height .5pt width .75pc}}%
+ \vss}
+ \vskip -\tdimena
+ \nointerlineskip}
+
+\setflag \inbackground = \false
+
+\def \zpageheadmargin {%
+ \vbox to \headmargin {%
+ \hrule height 0pt width \trimwidth
+ \nointerlineskip
+ \smashbox{%
+ \setflag \inbackground = \true
+ \zcurback}%
+ \nointerlineskip
+ \vfil
+ \zmakeuprule{\trimwidth}{.5pt}}}
+
+\def \zpagetypearea {%
+ \if \evenpagep
+ \negate \eveninnermargin
+ \advance \eveninnermargin by \trimwidth
+ \advance \eveninnermargin by -\evenlefttextmargin
+ \advance \eveninnermargin by -\textmeasure
+ \advance \eveninnermargin by -\evenrighttextmargin
+ \fi
+ \moveright \if \oddpagep \oddinnermargin \else \eveninnermargin \fi
+ \vbox to \typeareaheight {%
+ \zadjtitle = \zadjtitlemark % \adjusttitle should adjust mark.
+ \def \zadjloc {\mark}%
+ \zpageheader
+ \nointerlineskip
+ \ztextandmargins
+ \zmakeuprule{\typeareawidth}{.5pt}%
+ \vss % Allows text area height to vary.
+ \vbox to \footerheight{%
+ \vss
+ \zpagefooter}}}
+
+\def \zpageheader {%
+ \vbox to \headerheight {%
+ \hsize = \typeareawidth
+ \zoutputbeginblack
+ \zcurheader
+ \zoutputendblack
+ \vfil
+ \zmakeuprule{\typeareawidth}{.5pt}}}
+
+\def \ztextandmargins {%
+ \hbox to \typeareawidth {%
+ \if \notp{\zusetypewidth}%
+ \hbox to \thislefttextmargin{\hss}%
+ \fi
+ \vbox{%
+ \boxmaxdepth = \maxdepth
+ \if \andp{\zusetypewidth}{\notp{\zonetontype}}%
+ \moveright \thislefttextmargin
+ \fi
+ \box\zonetonbox
+ \nointerlineskip
+ \vbox{\box\zbodybox}}%
+ \hss}}
+
+\def \zpagefooter {%
+ \hsize = \typeareawidth
+ \zoutputbeginblack
+ \zcurfooter
+ \zoutputendblack
+ \if \PDFhyperlinks \PDFmark{P:\folio}\fi}
+
+% This macro invokes the page overlay after positioning to the
+% upper-left corner of the trim.
+
+\def \zpageoverlay {%
+ \vbox to 0pt{%
+ \offinterlineskip
+ \kern -\trimheight
+ \name{\pageoverlay\the\zoverlay}%
+ \vss}}
+
+\def \zmakeuprule #1#2{% {width}{height}
+ \if \DVIWindoinuse
+ \colorspecial{ifview color push rgb 0 1 0}%
+ \tdimena = #1\tcounta = \tdimena
+ \tdimena = #2\tcountb = \tdimena
+ \special{viewrule: \the\tcounta\space \the\tcountb}%
+ \colorspecial{ifview color pop}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zzplain.tex b/macros/plain/contrib/zztex/tex/zzplain.tex
new file mode 100644
index 0000000000..a24aa80139
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzplain.tex
@@ -0,0 +1,71 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+% Module: ZzTeX Plain TeX Compatibility
+%
+% Synopsis: This module contains definitions necessary for
+% compatibility with Plain TeX. The only goal is to
+% allow ZzTeX to run on top of Plain TeX.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 24 July 1991
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\if \definedp{\dospecials}
+ \let \znext = \relax
+\else
+ \let \znext = \endinput
+\fi
+\znext
+
+\def \zplainerror {%
+ \error{plaintex}{Cannot use this Plain TeX feature in ZzTeX}}
+
+% Definitions
+% -----------
+
+
+\catcode`\@ = \catletter
+\zremovePlaindef \p@
+\definedimen{\p@}{1pt}
+\zremovePlaindef \z@
+\definedimen{\z@}{0pt}
+\zremovePlaindef \z@skip
+\defineskip{\z@skip}{0pt plus 0pt minus 0pt}
+\catcode`\@ = \catactive
+
+\let \beginsection = \zplainerror
+
+\let \bye = \zplainerror
+
+\let \eject = \zplainerror
+
+\let \leavevmode = \ensurepar
+
+\let \normalbottom = \zplainerror
+
+\let \raggedright = \zplainerror
+
+\let \supereject = \zplainerror
+
+\let \ttraggedright = \zplainerror
+
+% Eliminate Fonts
+% --------- -----
+
+ \tcounta = 0
+ \loop
+ \zclearfam{\tcounta}%
+ \increment \tcounta
+ \if \lssp{\tcounta}{16}\repeat
+
+ \let \rm = \relax
+ \let \mit = \relax
+ \let \it = \relax
+ \let \sl = \undefined \let \slfam = \undefined
+ \let \bf = \relax
+ \let \tt = \relax
diff --git a/macros/plain/contrib/zztex/tex/zzprog.tex b/macros/plain/contrib/zztex/tex/zzprog.tex
new file mode 100644
index 0000000000..10b655bf0c
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzprog.tex
@@ -0,0 +1,228 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZZTeX Programming Constructs
+%
+% Synopsis: This module contains definitions for ZZTeX's programming
+% constructs. These constructs provide various extensions
+% to TeX's sometimes meager repertoire of programming
+% features.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 27 March 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Token Hackery
+% ----- -------
+
+
+% We need a name for a space token.
+
+\def \\{\let \zspacetoken = } \\ % Now \zspacetoken is a space token.
+
+% This macro discards the next token.
+
+\def \discardtok #1{}% token
+
+% This macro removes the `pt' following a dimension.
+
+{\catcode `\p = \catother \catcode `\t = \catother
+
+\gdef \zremovedu #1pt{#1}
+
+} % \catcode
+
+% Using that macro, we can define a macro that "converts" a dimen register
+% into a factor.
+
+\def \thefactor #1{\expandafter\zremovedu \the#1}
+
+% This macro extracts the contents of a macro and returns it as plain text.
+% Usage: \expandafter\zdefof \meaning\macro\zmark
+
+\def \zdefof #1:->#2\zmark{#2}
+
+% Control Sequence Names
+% ------- -------- -----
+
+
+\def \name #1{% {\tokens}
+ \csname \expandafter\discardtok \string#1\endcsname}
+
+\def \withname #1#2{% {\command}{\tokens}
+ \expandafter#1\csname \expandafter\discardtok \string#2\endcsname}
+
+% Macro Expansion
+% ----- ---------
+
+
+\def \expandaftertwice {\expandafter\expandafter\expandafter}
+\def \expandafterthrice {\expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter}
+
+\def \zoneoftwo #1#2{#1}% {first}{second}
+\def \ztwooftwo #1#2{#2}% {first}{second}
+
+\def \zoneofthree #1#2#3{#1}% {first}{second}{third}
+\def \ztwoofthree #1#2#3{#2}% {first}{second}{third}
+\def \zthreeofthree #1#2#3{#3}% {first}{second}{third}
+
+\def \zoneoffour #1#2#3#4{#1}% {first}{second}{third}{fourth}
+\def \ztwooffour #1#2#3#4{#2}% {first}{second}{third}{fourth}
+\def \zthreeoffour #1#2#3#4{#3}% {first}{second}{third}{fourth}
+\def \zfouroffour #1#2#3#4{#4}% {first}{second}{third}{fourth}
+
+% Flags (Booleans)
+% ----- ----------
+
+% The boolean literals \true and \false are appropriate for use with
+% the \if command, which tests the codes of the next two characters.
+
+\def \true {TT}
+\def \false {FL}
+
+\def \setflag #1=#2{\edef #1{#2}}% \flag = boolean
+
+% IF and Predicates
+% -- --- ----------
+
+% A "predicate" is a macro that returns \true or \false as its value.
+% Such values are suitable for use with the \if conditional. For example:
+%
+% \if \oddp{\x} <then-clause> \else <else-clause> \fi
+
+% A predicate can be used with \setflag as follows:
+%
+% \setflag \flag = {<predicate>}
+
+% Here are the predicates for TeX's repertoire of conditional
+% commands. These might be more appropriately interspersed with
+% other definitions in this module, but what the heck.
+% Some additional "obvious" predicates are defined.
+
+
+\def \eqlp #1#2{\ifnum #1 = #2\true \else \false \fi}
+\def \neqlp #1#2{\ifnum #1 = #2\false \else \true \fi}
+\def \lssp #1#2{\ifnum #1 < #2\true \else \false \fi}
+\def \gtrp #1#2{\ifnum #1 > #2\true \else \false \fi}
+\def \zerop #1{\ifnum #1 = 0\true \else \false \fi}
+\def \onep #1{\ifnum #1 = 1\true \else \false \fi}
+\def \posp #1{\ifnum #1 > 0\true \else \false \fi}
+\def \negp #1{\ifnum #1 < 0\true \else \false \fi}
+\def \oddp #1{\ifodd #1\true \else \false \fi}
+\def \evenp #1{\ifodd #1\false \else \true \fi}
+\def \rangep #1#2#3{\if \orp{\lssp{#1}{#2}}{\gtrp{#1}{#3}}\false \else
+ \true \fi}
+\def \tensp #1{\rangep{#1}{10}{19}}
+
+\def \dimeqlp #1#2{\ifdim #1 = #2\true \else \false \fi}
+\def \dimneqlp #1#2{\ifdim #1 = #2\false \else \true \fi}
+\def \dimlssp #1#2{\ifdim #1 < #2\true \else \false \fi}
+\def \dimgtrp #1#2{\ifdim #1 > #2\true \else \false \fi}
+\def \dimzerop #1{\ifdim #1 = 0pt\true \else \false \fi}
+\def \dimposp #1{\ifdim #1 > 0pt\true \else \false \fi}
+\def \dimnegp #1{\ifdim #1 < 0pt\true \else \false \fi}
+
+\def \vmodep {\ifvmode \true \else \false \fi}
+\def \hmodep {\ifhmode \true \else \false \fi}
+\def \mathmodep {\ifmmode \true \else \false \fi}
+\def \textmodep {\ifmmode \false \else \true \fi}
+\def \innermodep {\ifinner \true \else \false \fi}
+
+\long\def \codeeqlp #1#2{\if #1#2\true \else \false \fi}
+
+\long\def \cateqlp #1#2{\ifcat #1#2\true \else \false \fi}
+
+\long\def \tokeqlp #1#2{\ifx #1#2\true \else \false \fi}
+\long\def \xtokeqlp #1#2{\expandafter\ifx #1#2\true \else \false \fi}
+
+\long\def \definedp #1{%
+ \expandafter\ifx \csname \expandafter\discardtok \string#1\endcsname
+ \relax \false \else \true \fi}
+
+\long\def \undefinedp #1{%
+ \expandafter\ifx \csname \expandafter\discardtok \string#1\endcsname
+ \relax \true \else \false \fi}
+\def \zempty {}
+\def \emptydefp #1{\ifx #1\zempty \true \else \false \fi}% {\name}
+
+\let \emptylistp = \emptydefp
+
+\long\def \emptyargp #1{% {#n}
+ \zempargp #1\zempargq\zmark}
+\long\def \zempargp #1#2\zmark{%
+ \ifx #1\zempargq \true \else \false \fi}
+\def \zempargq {\zempargq}
+
+\def \emptytoksp #1{% {\tokenreg}
+ \expandafter\zemptoksp \the#1\zmark}
+
+\long\def \zemptoksp #1\zmark{\emptyargp{#1}}
+
+\def \voidboxp #1{\ifvoid #1\true \else \false \fi}
+\def \hboxp #1{\ifhbox #1\true \else \false \fi}
+\def \vboxp #1{\ifvbox #1\true \else \false \fi}
+
+\def \eofp #1{\ifeof #1\true \else \false \fi}
+
+
+% Flags can also be used as predicates, as in:
+%
+% \if \flaga <then-clause> \else <else-clause> \fi
+
+
+% Now here we have predicates for the common logical operators.
+
+\def \notp #1{\if #1\false \else \true \fi}
+
+\def \andp #1#2{\if #1#2\else \false \fi}% {boolean1}{boolean2}
+
+\def \orp #1#2{\if #1\true \else #2\fi}% {boolean1}{boolean2}
+
+% Pseudo-Predicates
+% -----------------
+
+
+\def \stringeql #1#2#3{% {\return-flag}{string1}{string2}
+ \edef \zstra {#2}%
+ \edef \zstrb {#3}%
+ \edef #1{\ifx \zstra\zstrb \true \else \false \fi}}
+
+
+\def \gluevaries #1#2{% {\return-flag}{glue}
+ \zskipa = #2\relax
+ \tdimena = \zskipa
+ \stringeql{#1}{\the\zskipa}{\the\tdimena}%
+ \edef #1{\if #1\false \else \true \fi}}
+
+% Arithmetic
+% ----------
+
+
+\def \negate #1{\multiply #1 by -1\relax}% {\register}
+
+\def \increment #1{\advance #1 by 1\relax}% {\count}
+
+\def \decrement #1{\advance #1 by -1\relax}% {\count}
+
+% Looping
+% -------
+
+
+\def \loop #1\repeat{% body [actions] \if condition [actions] \repeat
+ \def \zloopbody {#1}%
+ \zloop}
+
+\def \zloop {%
+ \zloopbody
+ %\if condition
+ \let \zloopnext = \zloop
+ \else
+ \let \zloopnext = \relax
+ \fi
+ \zloopnext}
+
+\let \repeat = \fi \ No newline at end of file
diff --git a/macros/plain/contrib/zztex/tex/zzps.tex b/macros/plain/contrib/zztex/tex/zzps.tex
new file mode 100644
index 0000000000..f90d6e7ab9
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzps.tex
@@ -0,0 +1,251 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX PostScript Facilities
+%
+% Synopsis: This module contains any and all facilities that rely on
+% PostScript output.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 21 January 1994
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Extra Encoded Characters
+% ----- ------- ----------
+
+
+\def \PSbackslash {\char 134\relax}
+\def \PSbar {\char 138\relax}
+\def \PSbullet {\char 142\relax}
+\def \PSbraceleft {\char 137\relax}
+\def \PSbraceright {\char 139\relax}
+\def \PScent {\char 148\relax}
+\def \PScopyright {\char 145\relax}
+\def \PScurrency {\char 149\relax}
+\def \PSdagger {\char 140\relax}
+\def \PSddagger {\char 141\relax}
+\def \PSdollar {\char 131\relax}
+\def \PSgreater {\char 133\relax}
+\def \PSless {\char 132\relax}
+\def \PSordfeminine {\char 155\relax}
+\def \PSordmasculine {\char 156\relax}
+\def \PSparagraph {\char 143\relax}
+\def \PSperthousand {\char 157\relax}
+\def \PSpolishL {\char "A1\relax}
+\def \PSpolishl {\char "A2\relax}
+\def \PSregistered {\char 146\relax}
+\def \PSsection {\char 144\relax}
+\def \PSsterling {\char 158\relax}
+\def \PStrademark {\char 147\relax}
+\def \PSunderscore {\char 136\relax}
+\def \PSudquote {\char 135\relax}
+\def \PSusquote {\char 160\relax}
+\def \PSyen {\char 159\relax}
+
+% Import EPS File
+% ------ --- ----
+
+
+% The illustration \special is compatible with DVIPSONE, and with TeXtures
+% if clip? is false.
+% The scale is interpreted as follows:
+% <= 33.333: normal scale, 1.0 = 100%
+% > 33.333: TeX scale factor, 1000 = 100%
+
+\def \specialimportartfile #1#2#3{% {name}{scale}{clip?}
+ \special{illustration #1 scaled #2
+ \if #3clip\fi}}
+
+% This macro is a better variant of the preceding one. The scale
+% argument is a true scale specified in points.
+
+\def \specialplaceepsfile #1#2#3{% {name}{scale}{clip?}
+ {\tdimena = #2%
+ \if \dimgtrp{\tdimena}{33.333pt}% % Compensate for bizarre
+ \multiply \tdimena by 1000\relax % design of scaled option.
+ \fi
+ \special{illustration #1 scaled \thefactor\tdimena
+ \if #3\space clip\fi}}}
+
+% This macro is used to import an EPS file for a glyph. The scale
+% is specified as a percentage IN POINTS.
+
+\def \specialplaceglyph #1#2#3{% {name}{percentage}{clip?}
+ {\tdimena = #2%
+ \divide \tdimena by 100
+ \special{illustration #1 scaled \thefactor\tdimena
+ \if #3\space clip\fi}}}
+
+% Read EPS Bounding Box
+% ---- --- -------- ---
+
+
+\definedimen{\zbbxorigin}{0pt}
+\definedimen{\zbbyorigin}{0pt}
+
+
+{\catcode`\%=\catother
+\gdef \zpercent {%}
+} % \catcode
+
+\edef \zboundingbox {\zpercent\zpercent BoundingBox}
+\def \zatend {atend}
+\definecount{\zbbstate}{0}
+
+
+\def \zreadepsbb #1#2#3{% {\width}{\height}{file}
+ \def \zbbinfo {}%
+ \begingroup
+ \zsetepscatcodes
+ \openin \zreada #3\relax
+ \zbbstate = 0
+ \loop
+ \read \zreada to \zline
+ \ifeof \zreada
+ \zbbstate = 2
+ \else
+ \expandafter\zcheckbb \zline:.\zmark
+ \fi
+ \ifnum \zbbstate < 2 \repeat
+ \closein \zreada
+ \endgroup
+ \zsetbbsizes{#1}{#2}{#3}}
+
+\def \zsetepscatcodes {%
+ \catcoderange{0}{"1F}{\catcomment}%
+ \catcode `\^^I = \catspace
+ \catcode \endlinechar = \catendofline
+ \uncatcode{\false}{\false}{\false}%
+ \catcode `\: = \catother
+ \catcoderange{"7E}{"FF}{\catcomment}}
+
+\long \def \zcheckbb #1:#2#3\zmark{%
+ \def \znext {#1}%
+ \ifx \znext \zboundingbox
+ \zcheckatend #2#3()\zmark
+ \fi}
+
+\long \def \zcheckatend #1(#2)#3\zmark{%
+ \def \znext {#2}%
+ \ifx \znext \zatend
+ \zbbstate = 1
+ \else
+ \gdef \zbbinfo {#1}%
+ \ifnum \zbbstate = 0 \zbbstate = 2\fi
+ \fi}
+
+\def \zsetbbsizes #1#2#3{%
+ \if \emptydefp{\zbbinfo}%
+ \warning{missbb}{Art file `#3' has no bounding box}%
+ #1 = 20pc #2 = 10pc
+ \else
+ \expandafter \zcalcbb \zbbinfo \zmark{#1}{#2}%
+ \fi}
+
+\def \zcalcbb #1 #2 #3 #4 #5\zmark#6#7{%
+ \calculate #6= {#3pt,-,#1pt,+,1pt}%
+ \calculate #7= {#4pt,-,#2pt,+,1pt}%
+ \global\zbbxorigin = #1pt
+ \global\zbbyorigin = #2pt\relax}
+
+% Rotate Boxes
+% ------ -----
+
+
+\def \rotatebox #1#2{% {\box}{degrees}
+ \special{CTM: push rotate #2}%
+ \box #1%
+ \special{CTM: pop}}
+
+\def \rotatetext #1#2{% {text}{degrees}
+ \setbox \zboxa = \hbox{#1}%
+ \rotatebox{\zboxa}{#2}}
+
+% Colors
+% ------
+
+
+\def \colorspecial #1{%
+ \if \allowcolor
+ \special{#1}%
+ \fi}
+
+% These commands are called in the output routine to make sure that
+% everything added in the output routine is black.
+
+\def \zoutputbeginblack {%
+ \colorspecial{color push gray 0}}
+
+\def \zoutputendblack {%
+ \colorspecial{color pop}}
+
+% Color Block
+% ---- ------
+
+
+\defineblock{\color}{\endcolor}{\false}{}
+
+%~block color Type
+% \colorspec = {...} % Color specifier.
+%~end
+
+\definetoks{\colorspec}
+
+
+\def \color #1{% {type}
+ \beginblockscope{color}%
+ \global\increment \colordepth
+ \processdesign{\color}{#1}%
+ \global\increment \colornumber
+ \colorspecial{color push}%
+ \the\colorspec\zmark
+ \if \vmodep \vpenalty{\breaknever}\fi}
+
+\def \endcolor {%
+ \global\decrement \colordepth
+ \endblockscope{color}%
+ \colorspecial{color pop}}
+
+
+\def \setcolor #1{%
+ \begingroup
+ \processdesign{\color}{#1}%
+ \the\colorspec\zmark
+ \endgroup}
+
+% Color specifiers:
+
+\def \cmykcolor #1 #2 #3 #4\zmark{% c m y k\zmark
+ \colorspecial{color cmyk #1 #2 #3 #4}}
+
+\def \graycolor #1\zmark{% gray\zmark
+ \colorspecial{color gray #1}}
+
+\def \rgbcolor #1 #2 #3\zmark{% r g b\zmark
+ \colorspecial{color rgb #1 #2 #3}}
+
+% Built-in colors:
+
+\def \colorblackdesign {%
+ \colorspec = {\graycolor 0}}
+
+\def \colorwhitedesign {%
+ \colorspec = {\graycolor 1}}
+
+\def \colorproofnotereddesign {%
+ \colorspec = {\rgbcolor .5 0 0}}
+
+% A useful shorthand:
+
+\def \colortext #1#2{% {color}{text}
+ \color{#1}#2\endcolor}
+
+% TeXtures
+% --------
+
+
+\def \TeXtures {%
+ \input zztures\relax}
diff --git a/macros/plain/contrib/zztex/tex/zzreg.tex b/macros/plain/contrib/zztex/tex/zzreg.tex
new file mode 100644
index 0000000000..c50f9e74d8
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzreg.tex
@@ -0,0 +1,437 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Register Facilities
+%
+% Synopsis: This module provides facilities for defining and manipulating
+% TeX registers.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 13 August 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Register Definition
+% -------- ----------
+
+
+% The following constant specifies the number of the first insert register
+% set. Such a set is composed of a count, dimen, skip, and box.
+
+\chardef \zfirstinsert = 245
+
+% Establish counters to keep track of the most recently allocated
+% registers. The registers are initialized to the first available
+% register.
+
+\count10 = 20 % Count registers.
+\count11 = 0 % Dimen registers.
+\count12 = 0 % Skip registers.
+\count13 = 0 % Muskip registers.
+\count14 = 1 % Box registers (Plain TeX uses box 0).
+\count15 = 0 % Toks registers.
+\count16 = 0 % Read streams.
+\count17 = 0 % Write streams.
+\count18 = 0 % Math families.
+\count19 = \zfirstinsert % Insertion register sets.
+
+
+% There is one macro for each type of register, used to allocate one.
+
+\def \definecount #1#2{% {\name}{initial}
+ \zalloc{\count}{10}{\zfirstinsert}{\countdef}{#1}%
+ #1 = #2}
+
+\def \definedimen #1#2{% {\name}{initial}
+ \zalloc{\dimen}{11}{\zfirstinsert}{\dimendef}{#1}%
+ #1 = #2}
+
+\def \defineskip #1#2{% {\name}{initial}
+ \zalloc{\skip}{12}{\zfirstinsert}{\skipdef}{#1}%
+ #1 = #2}
+
+\def \definemuskip #1#2{% {\name}{initial}
+ \zalloc{\muskip}{13}{255}{\muskipdef}{#1}% Muskip 255 is scratch.
+ #1 = #2}
+
+\def \definebox #1{% {\name}
+ \zalloc{\box}{14}{\zfirstinsert}{\chardef}{#1}}
+
+\def \definetoks #1{% {\name}
+ \zalloc{\toks}{15}{256}{\toksdef}{#1}%
+ #1 = {}}
+
+\def \defineread #1{% {\name}
+ \zalloc{\read}{16}{16}{\chardef}{#1}}
+
+\def \definewrite #1{% {\name}
+ \zalloc{\write}{17}{16}{\chardef}{#1}}
+
+% Families are not defined directly by the user, but via \definetypestyle.
+
+\def \zdeffam #1{% {\name}
+ \if \lssp{\count18}{15}%
+ \zalloc{\fam}{18}{16}{\chardef}{#1}%
+ \else
+ \global\chardef #1=\count18
+ \fi}
+
+\def \defineinsert #1{% {\name}
+ \zalloc{\insert}{19}{255}{\chardef}{#1}} % Registers 255 are scratch.
+
+
+\def \zalloc #1#2#3#4#5{% {type}{counter}{limit}{\def-er}{\name}
+ \if \eqlp{\count#2}{#3}%
+ \error{noregsleft}{All `\string#1' registers have been allocated}%
+ \fi
+ \if \definedp{#5}%
+ \error{dupreg}{The register `\string#5' is already defined}%
+ \fi
+ \global#4 #5=\count#2
+ \global\increment {\count#2}}
+
+% Register Statistics
+% -------- ----------
+
+
+{\catcode`\_ = \catactive
+
+\gdef \zregstats {%
+ {\def _{\space}%
+ \writelog{}%
+ \writelog{Register Statistics:}%
+ \writelog{}%
+ \writelog{Type_____Used / Total}%
+ \writelog{----_____------------}%
+ \zrsone{Count_}{10}{\zfirstinsert}{}%
+ \zrsone{Dimen_}{11}{\zfirstinsert}{}%
+ \zrsone{Skip__}{12}{\zfirstinsert}{}%
+ \zrsone{Muskip}{13}{255}{}%
+ \zrsone{Box___}{14}{\zfirstinsert}{}%
+ \zrsone{Toks__}{15}{256}{}%
+ \zrsone{Read__}{16}{16}{}%
+ \zrsone{Write_}{17}{16}{}%
+ \zrsone{Family}{18}{256}{(15 for math)}%
+ \zrsone{Insert}{19}{255}{(starts at \the\zfirstinsert)}%
+ \writelog{}}}
+
+\gdef \zrsone #1#2#3#4{% {name}{counter}{ex-limit}{comment}
+ \tcounta = #3
+ \advance \tcounta by -1
+ \writelog{#1___\the\count#2 _/_\the\tcounta_#4}}
+
+} % \catcode
+
+% Constant Registers
+% -------- ---------
+
+
+\definecount{\maxcount}{2147483647}
+\definecount{\mincount}{-\maxcount}
+\zremovePlaindef \maxdimen
+\definedimen{\maxdimen}{16383.99999pt}
+\definedimen{\mindimen}{-\maxdimen}
+\definedimen{\naturalwidth}{\mindimen}
+
+\defineskip{\centerindent}{0pt plus 10000pt}
+\let \centering = \centerindent
+
+\defineskip{\normalparfillskip}{0pt plus 1fil}
+
+\definebox{\voidbox} % Permanently void box register.
+
+% Temporary Internal Registers
+% --------- -------- ---------
+
+
+\definecount{\tcounta}{0}
+\definecount{\tcountb}{0}
+\definecount{\tcountc}{0}
+
+\definedimen{\tdimena}{0pt}
+\definedimen{\tdimenb}{0pt}
+\definedimen{\tdimenc}{0pt}
+\definedimen{\tdimend}{0pt}
+
+\defineskip{\zskipa}{0pt}
+\defineskip{\zskipb}{0pt}
+\defineskip{\zskipc}{0pt}
+
+\definemuskip{\zmuskipa}{0mu}
+\definemuskip{\zmuskipb}{0mu}
+\definemuskip{\zmuskipc}{0mu}
+
+\definebox{\zboxa}
+\definebox{\zboxb}
+\definebox{\zboxc}
+
+\definetoks{\ztoksa}
+\definetoks{\ztoksb}
+\definetoks{\ztoksc}
+
+\defineread{\zreada}
+
+\definewrite{\zwritea}
+
+% Manipulating Boxes
+% ------------ -----
+
+
+\def \shiftboxbaseline #1#2{% {\box}{amount}
+ {\tdimena = #2%
+ \tdimenb = \ht#1%
+ \advance \tdimenb by \tdimena
+ \ht#1= \tdimenb
+ \tdimenb = \dp#1%
+ \advance \tdimenb by -\tdimena
+ \dp#1= \tdimenb}}
+
+% Lists
+% -----
+
+
+% These macros support the manipulation of lists in the following format:
+%
+% \:{<element-0>}\:{<element-1>}\: ...
+%
+% All lists are global!
+
+% We need two toks registers, which will be used just for lists.
+
+\definetoks{\zlta}
+\definetoks{\zltb}
+
+
+\def \setlist #1=#2{% \listname = {value}
+ \zlta = \expandafter{#2}%
+ \xdef #1{\the\zlta}}
+
+\long\def \append #1#2{% {item}{\list-name}
+ {\zlta = {\:{#1}}%
+ \zltb = \expandafter{#2}%
+ \xdef #2{\the\zltb\the\zlta}}}
+
+\long\def \appendlf #1#2{% {\list-name}{item}
+ {\zlta = {\:{#2}}%
+ \zltb = \expandafter{#1}%
+ \xdef #1{\the\zltb\the\zlta}}}
+
+\long\def \prepend #1#2{% {item}{\list-name}
+ {\zlta = {\:{#1}}%
+ \zltb = \expandafter{#2}%
+ \xdef #2{\the\zlta\the\zltb}}}
+
+\let \push = \prepend
+
+\def \pop #1#2{% {\return-macro}{\list-name}
+ \expandafter\zpop #2\zmark#1#2}
+
+\long\def \zpop \:#1#2\zmark#3#4{%
+ \def #3{#1}%
+ \gdef #4{#2}}
+
+\def \listtop #1#2{% {\return-macro}{\list-name}
+ \expandafter\zlisttop #2\zmark#1}
+
+\long\def \zlisttop \:#1#2\zmark#3{%
+ \def #3{#1}}
+
+\definecount{\zmapldepth}{0}
+
+\def \maplist #1#2{% {body}{\listname}
+ \increment \zmapldepth
+ \withname\let{\zmapl\romannumeral\zmapldepth}=\:%
+ \long\def \:##1{#1}%
+ #2%
+ \expandafter\let
+ \expandafter\:\csname zmapl\romannumeral\zmapldepth\endcsname
+ \decrement \zmapldepth}
+
+\def \maplistlf #1#2{% {\listname}{body}
+ \increment \zmapldepth
+ \withname\let{\zmapl\romannumeral\zmapldepth}=\:%
+ \long\def \:##1{#2}%
+ #1%
+ \expandafter\let
+ \expandafter\:\csname zmapl\romannumeral\zmapldepth\endcsname
+ \decrement \zmapldepth}
+
+\def \exitmaplist {\def \:##1{}}
+
+\def \listlength #1#2{% {\result-count}{\list}
+ #1= 0
+ \maplist{\increment #1}{#2}}
+
+\def \member #1#2#3{% {\result-flag}{item}{\list}
+ \setflag #1= \false
+ \maplist{\stringeql{#1}{##1}{#2}\if #1\exitmaplist \fi}
+ {#3}}
+
+\def \commalist #1#2{% {\result-name}{comma-list}
+ \setlist #1={}%
+ \expandafter\zcomma #2,\zmark#1}
+
+\def \zcomma #1,#2\zmark#3{%
+ \if \notp{\emptyargp{#1}}\append{#1}{#3}\fi
+ \if \notp{\emptyargp{#2}}%
+ \def \znext {\zcomma #2\zmark#3}%
+ \else
+ \let \znext = \relax
+ \fi
+ \znext}
+
+\def \inclusionlist #1#2#3{% {\result}{item}{inclusion-list}
+ \zincla {#1}{#2}#3\zmark}
+
+\let \all = \relax
+\let \allbut = \relax
+\def \zallname {\all}
+\def \zallbutname {\allbut}
+
+\def \zincla #1#2#3#4\zmark{% {\result}{item}{token1}{tokens...}
+ \def \znext {#3}%
+ \if \tokeqlp{\znext}{\zallname}%
+ \setflag #1= \true
+ \else \if \tokeqlp{\znext}{\zallbutname}%
+ \commalist{\zincllist}{#4}%
+ \member{#1}{#2}{\zincllist}%
+ \setflag #1= {\notp{#1}}%
+ \else
+ \commalist{\zincllist}{#3#4}%
+ \member{#1}{#2}{\zincllist}%
+ \fi\fi}
+
+% New Expression Evaluation
+% --- ---------- ----------
+
+
+% These macros provide a rudimentary expression evaluation facility.
+% The accumulator can be a count, dimen, or skip register. The expression
+% is in the form {operand0,op1,operand1,op2,operand2,...}.
+%
+% WARNING: The \register cannot be used in the expression except possibly
+% as the first operand.
+
+
+\definedimen{\zcalct}{0pt}
+
+
+\def \calculate #1=#2{% \register = {expression}
+ \let \zaccum = #1%
+ \zcalca =,#2,;,,\zmark}
+
+\def \gcalculate #1=#2{% \register = {expression}
+ \let \zaccum = #1%
+ \zcalca =,#2,;,,\zmark
+ \global \zaccum = \zaccum}
+
+\def \zcalca #1,#2,#3\zmark{%
+ \def \znext{\zcalca #3\zmark}%
+ \if #1=\zaccum = #2% % Assignment
+ \else\if #1+\advance \zaccum #2% % Addition
+ \else\if #1-\advance \zaccum -#2% % Subtraction
+ \else\if #1*\multiply \zaccum #2% % Multiplication
+ \else\if #1/\divide \zaccum #2% % Division
+ \else\if #1N\if \dimlssp{#2}{\zaccum}\zaccum = #2\fi % Minimum
+ \else\if #1P\divide \zaccum 100 % Percentage
+ \expandafter\zaccum #2\zaccum
+ \else\if #1R\zcalct = #2% % Ratio
+ \divide \zcalct by 4096
+ \divide \zaccum by \zcalct
+ \multiply \zaccum by 16\relax
+ \else\if #1S\zaccum = \thefactor#2\zaccum % Scale
+ \else\if #1X\if \dimgtrp{#2}{\zaccum}\zaccum = #2\fi % Maximum
+ \else\if #1;\let \znext = \relax % Done
+ \else
+ \error{invoper}{Invalid operator `#1' in expression}%
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \znext}
+
+% Calculating Values
+% ----------- ------
+
+%%%\defineskip{\zcaccum}{0pt}
+%%%\setflag \zexprpos = \true
+%%%
+%%%\def \calculate #1=#2{% {\reg} = {expression}
+%%% \commalist{\zexprlist}{#2}%
+%%% \zcaccum = 0pt
+%%% \def \zoper {+}%
+%%% \setflag \zexprpos = \true
+%%% \maplist{\zcalc{##1}}{\zexprlist}%
+%%% #1=\zcaccum}
+%%%
+%%%\def \gcalculate #1=#2{% {\reg} = {expression}
+%%% \commalist{\zexprlist}{#2}%
+%%% \zcaccum = 0pt
+%%% \def \zoper {+}%
+%%% \setflag \zexprpos = \true
+%%% \maplist{\zcalc{##1}}{\zexprlist}%
+%%% \global #1=\zcaccum}
+%%%
+%%%\def \zcalc #1{% {token}
+%%% \if \zexprpos
+%%% \zcalcb{#1}%
+%%% \setflag \zexprpos = \false
+%%% \else
+%%% \def \zoper {#1}%
+%%% \setflag \zexprpos = \true
+%%% \fi}
+%%%
+%%%\def \zcalcb #1{% {operand}
+%%% \if \codeeqlp{\zoper}{+}% % Add.
+%%% \advance \zcaccum by #1%
+%%% \else\if \codeeqlp{\zoper}{-}% % Subtract.
+%%% \advance \zcaccum by -#1%
+%%% \else\if \codeeqlp{\zoper}{*}% % Multiply.
+%%% \multiply \zcaccum by #1%
+%%% \else\if \codeeqlp{\zoper}{/}% % Divide.
+%%% \divide \zcaccum by #1%
+%%% \else\if \codeeqlp{\zoper}{P}%
+%%% \divide \zcaccum by 100
+%%% \expandafter \zcaccum #1\zcaccum
+%%% \else\if \codeeqlp{\zoper}{R}% % Compute ratio (in points).
+%%% \zcalct = #1%
+%%% \divide \zcalct by 4096
+%%% \divide \zcaccum by \zcalct
+%%% \multiply \zcaccum by 16\relax
+%%% \else\if \codeeqlp{\zoper}{S}% % Scale (in points).
+%%% \zcaccum = \thefactor#1\zcaccum
+%%% \else
+%%% \error{invoper}{Invalid operator `\zoper' in expression}%
+%%% \fi\fi\fi\fi\fi\fi\fi}
+
+% The Vertical Context
+% --- -------- -------
+
+
+% This is in here because we need registers. Otherwise it would be
+% in ZZTEX.TEX
+
+
+\definecount{\zvcontextdepth}{0}
+
+\definetoks{\zeveryvcontext}
+\global\zeveryvcontext = {}
+
+
+\def \zdeclareeveryvcontext #1{%
+ \global\zeveryvcontext = \expandafter{\the\zeveryvcontext #1}}
+
+\def \zpushvcontext {%
+ \global\increment \zvcontextdepth
+ \withname\gdef{\zvcontextstack\romannumeral\zvcontextdepth}{}%
+ \the\zeveryvcontext}
+
+\def \zpopvcontext {%
+ {\globaldefs = 1\relax
+ \name{\zvcontextstack\romannumeral\zvcontextdepth}}%
+ \global\decrement \zvcontextdepth}
+
+\def \zsavevcontext #1{%
+ {\ztoksa = \expandafterthrice{%
+ \name{\zvcontextstack\romannumeral\zvcontextdepth}}%
+ \withname\xdef{\zvcontextstack\romannumeral\zvcontextdepth}%
+ {\the\ztoksa #1}}}
diff --git a/macros/plain/contrib/zztex/tex/zzrunner.tex b/macros/plain/contrib/zztex/tex/zzrunner.tex
new file mode 100644
index 0000000000..c0427cbddc
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzrunner.tex
@@ -0,0 +1,98 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Running Head/Foot Scheme
+%
+% Synopsis: The new running head/foot scheme is an improvement over the
+% original scheme.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 26 November 1997
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Data Structures
+% ---- ----------
+
+
+\def \zdefrun {normal}
+
+\setlist \zrunlist = {}
+
+\setflag \zoverrun = \false
+
+\def \zcurback {%
+ \if \definedp \backgroundnormalformat \backgroundnormalformat \fi}
+\def \zcurheader {\headernormalformat}
+\def \zcurfooter {\footernormalformat}
+
+% Specify Runners
+% ------- -------
+
+
+%~ This command discards any current runner styles and sets up to use style
+%~ *style1* on the current page, *style2* on the next, *style3* on the one after
+%~ that, and so forth. The last style specified is used as the style for all
+%~ subsequent pages (it becomes the default style). No spaces are allowed in the
+%~ list.
+
+\def \setrunners #1{% {style1,style2,style3,...} %^runners
+ {\if \zoverrun \pop{\zoverstyle}{\zrunlist}\fi
+ \commalist{\zrunlist}{#1}%
+ \maplist{\gdef \zdefrun {##1}}{\zrunlist}%
+ \if \zoverrun \expandafter\overriderunners\expandafter{\zoverstyle}\fi
+ \zsetcurrun}}
+
+%~ This command overrides the style for the current page, using style *style*
+%~ instead. After the current page, runner styles revert to those established
+%~ by the last |\setrunners| command.
+
+\def \overriderunners #1{% {style} %^runners
+ \if \notp{\emptylistp{\zrunlist}}%
+ \pop{\znext}{\zrunlist}%
+ \fi
+ \push{#1}{\zrunlist}%
+ \global\setflag \zoverrun = \true
+ \zsetcurrun}
+
+%~ This command is simply a shorthand for |\overriderunners{blind}|.
+
+\def \blindrunners {% %^runners
+ \overriderunners{blind}}
+
+% Internal Common Macros
+% -------- ------ ------
+
+
+\def \zsetrunnerstoks #1{% {\token-reg}
+ \expandafter\setrunners\expandafter{\the#1}}
+
+\def \zoverriderunnerstoks #1{% {\token-reg}
+ \expandafter\overriderunners\expandafter{\the#1}}
+
+\def \zoldrunners #1{}
+
+% Output Routine Interface
+% ------ ------- ---------
+
+
+\def \zsetcurrun {%
+ \if \emptylistp{\zrunlist}%
+ \edef \znext {\zdefrun}%
+ \else
+ \listtop{\znext}{\zrunlist}%
+ \fi
+ \ztoksa = \expandaftertwice{\name{\background\znext format}}%
+ \xdef \zcurback {%
+ \noexpand\if \noexpand\definedp\the\ztoksa \the\ztoksa \noexpand\fi}%
+ \ztoksa = \expandaftertwice{\name{\header\znext format}}%
+ \xdef \zcurheader {\the\ztoksa}%
+ \ztoksa = \expandaftertwice{\name{\footer\znext format}}%
+ \xdef \zcurfooter {\the\ztoksa}}
+
+\def \znextpagerunners {%
+ \if \notp{\emptylistp{\zrunlist}}\pop{\znext}{\zrunlist}\fi
+ \zsetcurrun
+ \global\setflag \zoverrun = \false}
diff --git a/macros/plain/contrib/zztex/tex/zzsect.tex b/macros/plain/contrib/zztex/tex/zzsect.tex
new file mode 100644
index 0000000000..280d2ecc5b
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzsect.tex
@@ -0,0 +1,806 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Sectioning Facilities
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 25 August 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Part and Chapter Texts
+% ---- --- ------- -----
+
+
+\long\def \setauthortext #1{% {text} %^modifier
+ \with{\authortext = {#1}}}
+
+\long\def \setopenertext #1{% {text} %^modifier
+ \with{\openertext = {#1}}}
+
+% Part
+% ----
+
+
+\defineblock{\part}{\endpart}{\true}{}
+
+%~block part
+% \setflag \allowintoc = flag % Allow in ToC?
+% \authortext = {...} % Author needed for opener.
+% \def \comptextformat {...} % Composite number text formatter.
+% \def \paging {...} % Paging before part opener.
+% \def \partformat ##1{...} % Part page formatter.
+% \openertext = {...} % Special text needed for opener.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \runners = {style,...} % Running head/foot styles.
+% \style = {...} % Heading style.
+%~end
+
+\def \part #1{% {title}
+ \closeanychapter
+ \beginblockscope{part}%
+ \global\increment \partdepth
+ \authortext = {}% %~default hard
+ \openertext = {}% %~default hard
+ \runners = {blind,normal}% %~default soft
+ \zoldrunners{\blindheader\blindfooter}%
+ \style = {Caps/lowercase, \noindent} %~default soft
+ \processdesign{\part}{}%
+ \global\increment \partnumber
+ \setcomptext{\partcomptext}%
+ \paging
+ \remark{Starting PART \number\partnumber.}%
+ % Next three things are done first, in case opener is more than one page.
+ \providemark{#1}%
+ \zpartchaptoc{\the\partcomptext}{#1}{80}%
+ \settaginfo{\the\partcomptext}{#1}
+ \zsetrunnerstoks{\runners}%
+ {\partformat{#1}}%
+ \endgraf}
+
+\def \endpart {%
+ \global\decrement \partdepth
+ \endblockscope{part}}
+
+\def \setpartnumber #1{% {number}
+ \global\partnumber = #1\relax
+ \global\decrement \partnumber}
+
+% Quasi-Part
+% ----------
+
+
+\defineblock{\quasipart}{\endquasipart}{\true}{}
+
+%~block quasipart
+% \setflag \allowintoc = flag % Allow in ToC?
+% \openertext = {...} % Special text needed for opener.
+% \def \paging {...} % Paging before part opener.
+% \def \quasipartformat ##1{...} % Part page formatter.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \runners = {style,...} % Running head/foot styles.
+% \style = {...} % Heading style.
+%~end
+
+\def \quasipart #1{% {title}
+ \closeanychapter
+ \beginblockscope{quasipart}%
+ \global\increment \quasipartdepth
+ \openertext = {}% %~default hard
+ \runners = {blind,normal}% %~default soft
+ \zoldrunners{\blindheader\blindfooter}%
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \processdesign{\quasipart}{}%
+ \global\increment \quasipartnumber
+ \paging
+ \def \znext {#1}%
+ \remark{Starting QUASIPART `\expandafter\zdefof \meaning\znext\zmark'.}%
+ % Next three things are done first, in case opener is more than one page.
+ \providemark{#1}%
+ \zpartchaptoc{}{#1}{85}%
+ \settaginfo{}{#1}%
+ \zsetrunnerstoks{\runners}%
+ {\quasipartformat{#1}}%
+ \endgraf}
+%%% \endquasipart}
+
+\def \endquasipart {%
+ \global\decrement \quasipartdepth
+ \endblockscope{quasipart}}
+
+% Chapter
+% -------
+
+\defineblock{\chapter}{\endchapter}{\true}{}
+
+%~block chapter
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \authorlevel = integer % Author ToC entry level.
+% \authortext = {...} % Author text needed for opener.
+% \def \comptextformat {...} % Composite number text formatter.
+% \difficulty = integer % Level of difficulty.
+% \numberfont = {...} % Font for number.
+% \numberwordfont = {...} % Font for word like "chapter".
+% \def \numberformat {...} % Number format.
+% \numbersink = glue % Sinkage to number, or
+% \numberskip = glue % Space b/b to number.
+% \openertext = {...} % Special text needed for opener.
+% \def \paging {...} % Initial paging.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \setflag \resetsection = boolean % Reset section number?
+% \runners = {style,...} % Running head/foot styles.
+% \style = {...} % Heading style.
+% \textsink = sinkage % Sinkage to text, or
+% \textskip = skip % Space b/b from rule to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \titlesink = glue % Sinkage to title, or
+% \titleskip = glue % Space b/b from number to title.
+%~end
+
+\def \chapter #1{% {title}
+ \closeanychapter
+ \beginblockscope{chapter}%
+ \global\increment \chapterdepth
+ \authorlevel = 0 %~default hard
+ \authortext = {}% %~default hard
+ \difficulty = 0 %~default with
+ \openertext = {}% %~default hard
+ \setflag \resetsection = \true %~default hard
+ \runners = {chapter,normal}% %~default soft
+ \zoldrunners{\chapterheader\chapterfooter}%
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \processdesign{\chapter}{}%
+ \if \resetsection
+ \global\sectionnumber = 0
+ \global\quasisectionnumber = 0
+ \global\chapterappendixnumber = 0
+ \fi
+ \global\simpleheadnumber = 0
+ \global\increment \chapternumber
+ \setcomptext{\chaptercomptext}%
+ \paging
+ \remark{Starting chapter \if \emptytoksp{\chaptercomptext}'#1'\else
+ \the\chaptercomptext \fi.}%
+ \zsetrunnerstoks{\runners}%
+ \chapterformat{#1}%
+ \deferfloats{\true}%
+ \settaginfo{\the\chaptercomptext}{#1}}
+
+\def \endchapter {%
+ \closeanysection
+ \global\decrement \chapterdepth
+ \endblockscope{chapter}}
+
+\def \chapterformat #1{%
+ {\the\numberfont
+ \zsinkskip{\numbersink}{\breakbest}{\numberskip}%
+ \numberformat\par}%
+ {\the\titlefont
+ \zsinkskip{\titlesink}{\breaknever}{\titleskip}%
+ \titleformat{#1}\par}%
+ \providemark{#1}%
+ \zpartchaptoc{\the\chaptercomptext}{#1}{70}%
+ \zsinkskip{\textsink}{\breaknever}{\textskip}}
+
+\def \setchapternumber #1{% {number}
+ \global\chapternumber = #1\relax
+ \global\decrement \chapternumber}
+
+\def \setappendixnumber #1{% {number}
+ \global\appendixnumber = #1\relax
+ \global\decrement \appendixnumber}
+
+\def \setsectionnumber #1{% {number}
+ \global\sectionnumber = #1\relax
+ \global\decrement \sectionnumber}
+
+% Quasi-Chapter
+% -------------
+
+
+\defineblock{\quasichapter}{\endquasichapter}{\true}{}
+
+%~block quasichapter
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \authorlevel = integer % Author ToC entry level.
+% \authortext = {...} % Author text needed for opener.
+% \openertext = {...} % Special text needed for opener.
+% \def \paging {...} % Initial paging.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \runners = {style,...} % Running head/foot styles.
+% \style = {...} % Heading style.
+% \textsink = sinkage % Sinkage to text, or
+% \textskip = skip % Skip from rule to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \titlesink = glue % Sinkage to title, or
+% \titleskip = glue % Space b/b to title.
+%~end
+
+\def \quasichapter #1{% {title}
+ \closeanychapter
+ \beginblockscope{quasichapter}%
+ \global\increment \quasichapterdepth
+ \authorlevel = 0 %~default hard
+ \authortext = {}% %~default hard
+ \openertext = {}% %~default hard
+ \runners = {chapter,normal}% %~default soft
+ \zoldrunners{\chapterheader\chapterfooter}%
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \processdesign{\quasichapter}{}%
+ \global\increment \quasichapternumber
+ \chaptercomptext = {}%
+ \paging
+ \def \znext {#1}%
+ \remark{Starting quasichapter `\expandafter\zdefof \meaning\znext\zmark'.}%
+ \zsetrunnerstoks{\runners}%
+ \quasichapterformat{#1}%
+ \deferfloats{\true}%
+ \settaginfo{}{#1}}
+
+\def \endquasichapter {%
+ \closeanysection
+ \global\decrement \quasichapterdepth
+ \endblockscope{quasichapter}}
+
+\def \quasichapterformat #1{%
+ {\the\titlefont
+ \zsinkskip{\titlesink}{\breaknever}{\titleskip}%
+ \titleformat{#1}\par}
+ \providemark{#1}%
+ \zpartchaptoc{}{#1}{75}%
+ \zsinkskip{\textsink}{\breaknever}{\textskip}}
+
+% Appendix
+% --------
+
+
+\defineblock{\appendix}{\endappendix}{\true}{}
+
+%~block appendix
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \authortext = {...} % Author text needed for opener.
+% \def \comptextformat {...} % Composite number text formatter.
+% \numberfont = {...} % Font for number.
+% \numberwordfont = {...} % Font for word like "appendix".
+% \def \numberformat {...} % Number format.
+% \numbersink = glue % Sinkage to number, or
+% \numberskip = glue % Space b/b to number.
+% \openertext = {...} % Special text needed for opener.
+% \def \paging {...} % Initial paging.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \setflag \resetsection = boolean % Reset section number?
+% \runners = {style,...} % Running head/foot styles.
+% \style = {...} % Heading style.
+% \textsink = sinkage % Sinkage to text, or
+% \textskip = skip % Space b/b from rule to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \titlesink = glue % Sinkage to title, or
+% \titleskip = glue % Space b/b from number to title.
+%~end
+
+\def \appendix #1{% {title}
+ \closeanychapter
+ \beginblockscope{appendix}%
+ \global\increment \appendixdepth
+ \authortext = {}% %~default hard
+ \openertext = {}% %~default hard
+ \setflag \resetsection = \true %~default hard
+ \runners = {chapter,normal}% %~default soft
+ \zoldrunners{\chapterheader\chapterfooter}%
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \processdesign{\appendix}{}%
+ \if \resetsection
+ \global\sectionnumber = 0
+ \global\quasisectionnumber = 0
+ \global\chapterappendixnumber = 0
+ \fi
+ \global\increment \appendixnumber
+ \setcomptext{\chaptercomptext}% % Not \appendixcomptext!
+ \paging
+ \remark{Starting appendix \the\chaptercomptext.}%
+ \zsetrunnerstoks{\runners}%
+ \appendixformat{#1}%
+ \deferfloats{\true}%
+ \settaginfo{\the\chaptercomptext}{#1}}
+
+\def \endappendix {%
+ \closeanysection
+ \global\decrement \appendixdepth
+ \endblockscope{appendix}}
+
+\def \appendixformat #1{%
+ {\the\numberfont
+ \zsinkskip{\numbersink}{\breakbest}{\numberskip}%
+ \numberformat\par}%
+ {\the\titlefont
+ \zsinkskip{\titlesink}{\breaknever}{\titleskip}%
+ \titleformat{#1}\par}%
+ \providemark{#1}%
+ \zpartchaptoc{\the\chaptercomptext}{#1}{71}%
+ \zsinkskip{\textsink}{\breaknever}{\textskip}}
+
+% Section
+% -------
+
+
+\defineblock{\section}{\endsection}{\true}{}
+
+%~block section
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \def \comptextformat {...} % Composite number text formatter.
+% \difficulty = integer % Level of difficulty.
+% \numberfont = {...} % Number font.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \section #1{% {title}
+ \closeanysection
+ \beginblockscope{section}%
+ \global\increment \sectiondepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\section}{}%
+ \global\subsectionnumber = 0
+ \global\subsubsectionnumber = 0
+ \global\subsubsubsectionnumber = 0
+ \global\increment \sectionnumber
+ \setcomptext{\sectioncomptext}%
+ \sectionformat{#1}%
+ \settaginfo{\the\sectioncomptext}{#1}}
+
+\def \endsection {%
+ \closeanysubsection
+ \global\decrement \sectiondepth
+ \endblockscope{section}}
+
+\def \sectionformat #1{%
+ {\if \emptytoksp{\numberfont}\the\titlefont \else \the\numberfont \fi
+ \zskipabovehead{\breakbest}{\aboveskip}%
+ \titleformat{#1}\par}%
+ \providemark{#1}%
+ \ztocentry{\the\sectioncomptext}{#1}{60}{\allowintoc}%
+ \bbskipabove{\breaknever}{\textskip}%
+ \overrideclubpenalty{\breaknever}}
+
+% Quasi-Section
+% -------------
+
+
+\defineblock{\quasisection}{\endquasisection}{\true}{}
+
+%~block quasisection
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \difficulty = integer % Level of difficulty.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \quasisection #1{% {tile}
+ \closeanysection
+ \beginblockscope{quasisection}%
+ \global\increment \quasisectiondepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\quasisection}{}%
+ \global\increment \quasisectionnumber % In case needed for \tagpageonly.
+ \quasisectionformat{#1}%
+ \settaginfo{}{#1}}
+
+\def \endquasisection {%
+ \closeanysubsection
+ \global\decrement \quasisectiondepth
+ \endblockscope{quasisection}}
+
+\def \quasisectionformat #1{%
+ {\the\titlefont
+ \zskipabovehead{\breakbest}{\aboveskip}%
+ \titleformat{#1}\par}
+ \providemark{#1}%
+ \ztocentry{}{#1}{65}{\allowintoc}%
+ \bbskipabove{\breaknever}{\textskip}%
+ \overrideclubpenalty{\breaknever}}
+
+% Chapter Appendix
+% ------- --------
+
+
+\defineblock{\chapterappendix}{\endchapterappendix}{\true}{}
+
+%~block chapterappendix
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \def \comptextformat {...} % Composite number text formatter.
+% \difficulty = integer % Level of difficulty.
+% \numberfont = {...} % Number font.
+% \def \providemark ##1{...} % Mark provider.
+% \resetnumber = {...} % List of numbers to reset.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \chapterappendix #1{% {title}
+ \closeanysection
+ \beginblockscope{chapterappendix}%
+ \global\increment \chapterappendixdepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\chapterappendix}{}%
+ \global\subsectionnumber = 0
+ \global\subsubsectionnumber = 0
+ \global\subsubsubsectionnumber = 0
+ \global\increment \chapterappendixnumber
+ \setcomptext{\sectioncomptext}% % Not \chapterappendixcomptext!
+ \chapterappendixformat{#1}%
+ \settaginfo{\the\sectioncomptext}{#1}}
+
+\def \endchapterappendix {%
+ \closeanysubsection
+ \global\decrement \chapterappendixdepth
+ \endblockscope{chapterappendix}}
+
+\def \chapterappendixformat #1{%
+ {\if \emptytoksp{\numberfont}\the\titlefont \else \the\numberfont \fi
+ \zskipabovehead{\breakbest}{\aboveskip}%
+ \titleformat{#1}\par}%
+ \providemark{#1}%
+ \ztocentry{\the\sectioncomptext}{#1}{61}{\allowintoc}%
+ \bbskipabove{\breaknever}{\textskip}%
+ \overrideclubpenalty{\breaknever}}
+
+% Subsection
+% ----------
+
+
+\defineblock{\subsection}{\endsubsection}{\false}{}
+
+%~block subsection
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = flag % Allow in ToC?
+% \def \comptextformat {...} % Composite number text formatter.
+% \difficulty = integer % Level of difficulty.
+% \numberfont = {...} % Font for number.
+% \def \providemark ##1{...} % Mark provider.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \subsection #1{% {title}
+ \closeanysubsection
+ \beginblockscope{subsection}%
+ \global\increment \subsectiondepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\subsection}{}%
+ \global\subsubsectionnumber = 0
+ \global\subsubsubsectionnumber = 0
+ \global\increment \subsectionnumber
+ \setcomptext{\subsectioncomptext}%
+ \subsectionformat{#1}%
+ \settaginfo{\the\subsectioncomptext}{#1}%
+ \ignorespaces}
+
+\def \endsubsection {%
+ \closeanysubsubsection
+ \global\decrement \subsectiondepth
+ \endblockscope{subsection}}
+
+\def \subsectionformat #1{%
+ {\if \emptytoksp{\numberfont}\the\titlefont \else \the\numberfont \fi
+ \zskipabovehead{\breakbetter}{\aboveskip}%
+ \titleformat{#1}}%
+ \providemark{#1}%
+ \ztocentry{\the\subsectioncomptext}{#1}{50}{\allowintoc}%
+ \if \dimposp{\textskip}%
+ \par
+ \bbskipabove{\breaknever}{\textskip}%
+ \fi
+ \overrideclubpenalty{\breaknever}}
+
+% Quasi-Subsection
+% ----------------
+
+
+\defineblock{\quasisubsection}{\endquasisubsection}{\false}{}
+
+%~block quasisubsection
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \difficulty = integer % Level of difficulty.
+% \def \providemark ##1{...} % Mark provider.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \quasisubsection #1{% {title}
+ \closeanysubsection
+ \beginblockscope{quasisubsection}%
+ \global\increment \quasisubsectiondepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\quasisubsection}{}%
+ \quasisubsectionformat{#1}%
+ \settaginfo{}{#1}%
+ \ignorespaces}
+
+\def \endquasisubsection {%
+ \closeanysubsubsection
+ \global\decrement \quasisubsectiondepth
+ \endblockscope{quasisubsection}}
+
+\def \quasisubsectionformat #1{%
+ {\the\titlefont
+ \zskipabovehead{\breakbetter}{\aboveskip}%
+ \titleformat{#1}}
+ \providemark{#1}%
+ \ztocentry{}{#1}{55}{\allowintoc}%
+ \if \dimposp{\textskip}%
+ \par
+ \bbskipabove{\breaknever}{\textskip}%
+ \fi
+ \overrideclubpenalty{\breaknever}}
+
+% Subsubsection
+% -------------
+
+
+\defineblock{\subsubsection}{\endsubsubsection}{\false}{}
+
+%~block subsubsection
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = flag % Allow in ToC?
+% \def \comptextformat {...} % Composite number text formatter.
+% \difficulty = integer % Level of difficulty.
+% \numberfont = {...} % Font for number.
+% \def \providemark ##1{...} % Mark provider.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \subsubsection #1{% {title}
+ \closeanysubsubsection
+ \beginblockscope{subsubsection}%
+ \global\increment \subsubsectiondepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\subsubsection}{}%
+ \global\subsubsubsectionnumber = 0
+ \global\increment \subsubsectionnumber
+ \setcomptext{\subsubsectioncomptext}%
+ \subsubsectionformat{#1}%
+ \settaginfo{\the\subsubsectioncomptext}{#1}%
+ \ignorespaces}
+
+\def \endsubsubsection {%
+ \closeanysubsubsubsection
+ \global\decrement \subsubsectiondepth
+ \endblockscope{subsubsection}}
+
+\def \subsubsectionformat #1{%
+ {\if \emptytoksp{\numberfont}\the\titlefont \else \the\numberfont \fi
+ \zskipabovehead{\breakgood}{\aboveskip}%
+ \titleformat{#1}}%
+ \providemark{#1}%
+ \ztocentry{\the\subsubsectioncomptext}{#1}{40}{\allowintoc}%
+ \if \dimposp{\textskip}%
+ \par
+ \bbskipabove{\breaknever}{\textskip}%
+ \fi
+ \overrideclubpenalty{\breaknever}}
+
+% Subsubsubsection
+% ----------------
+
+
+\defineblock{\subsubsubsection}{\endsubsubsubsection}{\false}{}
+
+%~block subsubsubsection
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowintoc = flag % Allow in ToC?
+% \def \comptextformat {...} % Composite number text formatter.
+% \difficulty = integer % Level of difficulty.
+% \numberfont = {...} % Font for number.
+% \def \providemark ##1{...} % Mark provider.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\def \subsubsubsection #1{% {title}
+ \closeanysubsubsubsection
+ \beginblockscope{subsubsubsection}%
+ \global\increment \subsubsubsectiondepth
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\subsubsubsection}{}%
+ \global\increment \subsubsubsectionnumber
+ \setcomptext{\subsubsubsectioncomptext}%
+ \subsubsubsectionformat{#1}%
+ \settaginfo{\the\subsubsubsectioncomptext}{#1}%
+ \ignorespaces}
+
+\def \endsubsubsubsection {%
+ \global\decrement \subsubsubsectiondepth
+ \endblockscope{subsubsubsection}}
+
+\def \subsubsubsectionformat #1{%
+ {\if \emptytoksp{\numberfont}\the\titlefont \else \the\numberfont \fi
+ \zskipabovehead{\breakgood}{\aboveskip}%
+ \titleformat{#1}}%
+ \providemark{#1}%
+ \ztocentry{\the\subsubsubsectioncomptext}{#1}{30}{\allowintoc}%
+ \if \dimposp{\textskip}%
+ \par
+ \bbskipabove{\breaknever}{\textskip}%
+ \fi
+ \overrideclubpenalty{\breaknever}}
+
+% Simple Head
+% ------ ----
+
+
+\defineblock{\simplehead}{\endsimplehead}{\false}{}
+
+%~block simplehead Type
+% \aboveskip = glue % Space b/b above title.
+% \setflag \allowclubline = flag % True if club allowed below.
+% \setflag \allowintoc = boolean % Allow in ToC?
+% \difficulty = integer % Level of difficulty.
+% \style = {...} % Heading style.
+% \textskip = skip % Skip from title to text.
+% \titlefont = {...} % Title font.
+% \def \titleformat ##1{...} % Title format.
+% \tocentrylevel = integer % ToC entry level number (optional).
+% \topadjust = dimen % Adjust if at top of page.
+%~end
+
+\definecount{\tocentrylevel}{0}
+
+
+\def \simplehead #1#2{% {type}{title}
+ \endgraf
+ \beginblockscope{simplehead}%
+ \global\increment \simpleheaddepth
+ \setflag \allowclubline = \false %~default soft
+ \setflag \allowintoc = \true %~default with
+ \difficulty = 0 %~default with
+ \style = {Caps/lowercase, \noindent}% %~default soft
+ \tocentrylevel = 0 %~default soft
+ \topadjust = \mindimen %~default hard
+ \processdesign{\simplehead}{#1}%
+ \global\increment \simpleheadnumber
+ \simpleheadformat{#2}%
+ \endsimplehead}
+
+\def \endsimplehead {%
+ \global\decrement \simpleheaddepth
+ \endblockscope{simplehead}%
+ \ignorespaces}
+
+\def \simpleheadformat #1{%
+ {\the\titlefont
+ \zskipabovehead{\breakgood}{\aboveskip}%
+ \titleformat{#1}}%
+ \if \dimzerop{\textskip}%
+ \nobreak
+ \else
+ \endgraf
+ \bbskipabove{\breaknever}{\textskip}%
+ \fi
+ \if \posp{\tocentrylevel}%
+ \ztocentry{}{#1}{\tocentrylevel}{\allowintoc}%
+ \fi
+ \if \notp{\allowclubline}\overrideclubpenalty{\breaknever}\fi}
+
+% Useful Utilities
+% ------ ---------
+
+
+\def \chapterorchapterappendixcomptext {%
+ \if \inblockp{\chapterappendix}%
+ \the\sectioncomptext
+ \else
+ \the\chaptercomptext
+ \fi}
+
+\def \textonlyhead {% %^modifier
+ \with{\setflag\allowintoc=\false
+ \def\providemark##1{}}}
+
+\def \closeanychapter {%
+ \closeifinblock{\part}{\endpart}%
+ \closeifinblock{\quasipart}{\endquasipart}%
+ \closeifinblock{\quasichapter}{\endquasichapter}%
+ \closeifinblock{\chapter}{\endchapter}%
+ \closeifinblock{\appendix}{\endappendix}}
+
+\def \closeanysection {%
+ \closeifinblock{\quasisection}{\endquasisection}%
+ \closeifinblock{\section}{\endsection}%
+ \closeifinblock{\chapterappendix}{\endchapterappendix}}
+
+\def \closeanysubsection {%
+ \closeifinblock{\quasisubsection}{\endquasisubsection}%
+ \closeifinblock{\subsection}{\endsubsection}}
+
+\def \closeanysubsubsection {%
+ \closeifinblock{\subsubsection}{\endsubsubsection}}
+
+\def \closeanysubsubsubsection {%
+ \closeifinblock{\subsubsubsection}{\endsubsubsubsection}}
+
+\def \zsinkskip #1#2#3{% {sink}{penalty}{skip}
+ \if \dimposp{#3}%
+ \bbskipabove{#2}{#3}%
+ \else
+ \vsinkfromtypearea{#1}%
+ \fi}
+
+\def \zskipabovehead #1#2{% {penalty}{skip}
+ \bbskipabove{#1}{#2}%
+ \if \dimneqlp{\topadjust}{\mindimen}%
+ \vskip -\topadjust
+ \tdimena = \prevdepth
+ \rule{height 0pt depth 0pt width 0pt}%
+ \prevdepth = \tdimena
+ \penalty \breaknever
+ \vskip \topadjust
+ \fi}
+
+% If the author level is negative, the ToC entry goes before the chapter's
+% entry. Otherwise it goes after the chapter's entry.
+
+\def \zpartchaptoc #1#2#3{%
+ \edef \znext {\noexpand\tocentry{}{\the\authortext}}%
+ \if \andp{\notp{\emptytoksp{\authortext}}}{\negp{\authorlevel}}%
+ \znext{-\authorlevel}%
+ \fi
+ \ztocentry{#1}{#2}{#3}{\allowintoc}%
+ \if \andp{\notp{\emptytoksp{\authortext}}}{\posp{\authorlevel}}%
+ \znext{\authorlevel}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zztabbing.tex b/macros/plain/contrib/zztex/tex/zztabbing.tex
new file mode 100644
index 0000000000..08257a45f4
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztabbing.tex
@@ -0,0 +1,266 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Tabbing Facilities
+%
+% Synopsis: This module contains the definition of the block that is
+% used to format text with tab stops.
+%
+% Authors: Paul C. Anagnostopoulos
+% Created: 27 May 2016
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Tabbing Block
+% ------- -----
+
+
+\defineblock{\tabbing}{\endtabbing}{\false}{}
+\resetinvcontext{\tabbing}
+
+%~block tabbing Type
+% \abovepenalty = integer % Penalty above text.
+% \aboveskip = glue % Space b/b above text.
+% \setflag \autocallout = boolean % Automatically number lines?
+% \def \beginformat {...} % Beginning of text formatter.
+% \belowpenalty = integer % Penalty below text.
+% \belowskip = glue % Space b/b below text.
+% \bodyfont = {font} % Body font.
+% \def \calloutformat ##1{...} % Callout formatter.
+% \calloutnumber = integer % Number of first callout.
+% \def \callouttext {...} % Callout text or \arg.
+% \defaulttabwidth = dimen % Default repeating tab width.
+% \def \endformat {...} % End of text formatter.
+% \leftindent = glue % Left indentation.
+% \rightindent = glue % Right indentation.
+% \tabbinggapskip = glue % Standard tabbing gap.
+% \textcolor = {...} % Color of text.
+% \width = dimen % Line width.
+%~end
+
+\defineskip{\tabbinggapskip}{0pt}
+
+\def \tabbing #1{% {type}
+ \blockcantbein{\tabbing}{\tabbing}%
+ \beginblockscope{tabbing}%
+ \global\increment \tabbingdepth
+ \abovepenalty = \breakgood %~default hard
+ \setflag \autocallout = \false %~default soft
+ \def \beginformat {}% %~default soft
+ \belowpenalty = \breakgood %~default hard
+ \calloutnumber = 1 %~default with
+ \def \callouttext {\number\calloutnumber}% %~default soft
+ \defaulttabwidth = \mindimen %~default soft
+ \def \endformat {}% %~default soft
+ \tabbinggapskip = \enclosingbaselineskip %~default soft
+ \textcolor = {}% %~default soft
+ \parindent = 0pt
+ \parrag = 0pt
+ \parskip = 0pt
+ \processdesign{\tabbing}{#1}%
+ \global\increment \tabbingnumber
+ \tabbingformat
+ \def \zarg {\arg}%
+ \if \tokeqlp{\callouttext}{\zarg}%
+ \defineatsigncommand @##{\ztbngatcallout}%
+ \else
+ \defineatsigncommand @##{\ztbngatcallout{\callouttext}}%
+ \fi
+ \if \emptytoksp{\textcolor}% % Must have a group around \ztbnginit.
+ \bgroup
+ \else
+ \color{\the\textcolor}%
+ \fi
+ \ztbnginit
+ \ztbngstartline}
+
+\def \endtabbing {%
+ \ztbngfinal
+ \if \emptytoksp{\textcolor}%
+ \egroup % \tabbing group
+ \else
+ \endcolor
+ \fi
+ \futurelet\nexttoken \zendtabbing}
+
+\def \zendtabbing {%
+ \endtabbingformat
+ \global\decrement \tabbingdepth
+ \endblockscope{tabbing}%
+ \parnext}
+
+\def \tabbingformat {%
+ \endgraf
+ \the\bodyfont
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \beginformat}
+
+\def \endtabbingformat {%
+ \endformat
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+%~ Use this command in between lines in a |\tabbing| block to
+%~ perform a vertical adjustment between those two lines. For example,
+%~
+%~ \adjusttabbing{\fullpagebreak}
+
+\long\def \adjusttabbing #1{% {commands}
+ \ztbngadjust{#1}}
+
+% Initialize and Finalize
+% ---------- --- --------
+
+
+\definecount{\ztbngstopcount}{0}
+\definecount{\ztbngstopindex}{0}
+
+\definebox{\ztbngline}
+\definebox{\ztbngfragment}
+
+
+\def \ztbnginit {%
+ \let \par = \ztbngshouldntbepar
+ \def \nl {\ztbngfinishline{\false}}%
+ \defineatsigncommand @.{\ztbngatsetstop}%
+ \defineatsigncommand @>{\ztbngattab}%
+ \defineatsigncommand @C{\ztbngatclear}%
+ \defineatsigncommand @D{\ztbngatdiscard}%
+ \ztbngsetdefaultstops{\defaulttabwidth}}
+
+\def \ztbngsetdefaultstops #1{% {width}
+ \global\ztbngstopcount = 0
+ \def \ztbngstop {0pt}%
+ \if \dimgtrp{#1}{0pt}%
+ \tdimena = 0pt
+ \loop
+ \global\increment \ztbngstopcount
+ \advance \tdimena by #1\relax
+ \withname\edef {\ztbngstop\romannumeral\ztbngstopcount}{\the\tdimena}%
+ \if \dimlssp{\tdimena}{\hsize}%
+ \repeat
+ \fi}
+
+\def \ztbngfinal {%
+ \ztbngfinishline{\true}}
+
+% Build Lines
+% ----- -----
+
+
+\def \ztbngstartline {%
+ \ztbngstopindex = 0
+ \setbox\ztbngline = \hbox{}%
+ \global\setflag \ztbngdiscardp = \false
+ \settaginfo{\number\calloutnumber}{???title???}%
+ \ztbngstartfragment}
+
+\def \ztbngstartfragment {%
+ \setbox \ztbngfragment = \hbox\bgroup
+ \ignorespaces}
+
+\def \ztbngfinishfragment {%
+ \egroup % \ztbngfragment box
+ \setbox\ztbngline = \hbox{%
+ \unhbox\ztbngline
+ \tdimena = \name{\ztbngstop\romannumeral\ztbngstopindex}%
+ \hskip \tdimena
+ \tdimenb = \hsize
+ \advance \tdimenb by -\tdimena
+ \hbox to \tdimenb{\copy\ztbngfragment \hfil}%
+ \hskip -\tdimenb
+ \hskip -\tdimena}}
+
+\def \ztbngfinishline #1{% {end-of-block?}
+ \ztbngfinishfragment
+ \if \notp{\ztbngdiscardp}%
+ \if \orp{\posp{\ztbngstopindex}}{\dimposp{\wd\ztbngfragment}}%
+ \noindent
+ \if \autocallout
+ \llap{\calloutformat{\the\calloutnumber}}%
+ \increment \calloutnumber
+ \fi
+ \box\ztbngline
+ \endgraf
+ \else\if \notp{#1}%
+ \vspace{\tabbinggapskip}%
+ \fi\fi
+ \fi
+ \if #1\let \znext = \relax \else \let \znext = \ztbngstartline \fi
+ \znext}
+
+% At-sign Commands
+% ------- --------
+
+
+% @#{callout}text...
+
+\def \ztbngatcallout #1{% {callout}
+ \ztbngfinishfragment
+ \if \andp{\zerop{\ztbngstopindex}}{\dimzerop{\wd\ztbngfragment}}
+ \setbox\ztbngfragment = \hbox\bgroup
+ \llap{\calloutformat{#1}}%
+ \ztbngfinishfragment
+ \else
+ \error{badtabcallout}{Callout command (\noexpand@##) must appear
+ at the beginning of the line}%
+ \fi
+ \increment \calloutnumber
+ \ztbngstartfragment}
+
+% text@.more text...
+
+\def \ztbngatsetstop {%
+ \ztbngfinishfragment
+ \tdimena = \name{\ztbngstop\romannumeral\ztbngstopindex}%
+ \advance \tdimena by \wd\ztbngfragment
+ \increment \ztbngstopindex
+ \if \gtrp{\ztbngstopindex}{\ztbngstopcount}%
+ \withname\edef {\ztbngstop\romannumeral\ztbngstopindex}{\the\tdimena}%
+ \increment \ztbngstopcount
+ \else
+ \error{badtabstop}{There is already a tab stop}%
+ \fi
+ \ztbngstartfragment}
+
+% text@>more text...
+
+\def \ztbngattab {%
+ \ztbngfinishfragment
+ \if \lssp{\ztbngstopindex}{\ztbngstopcount}%
+ \increment \ztbngstopindex
+ \else
+ \warning{toomanytabs}{Too many tabs on line; extra tabs ignored}%
+ \fi
+ \ztbngstartfragment}
+
+% @Ctext...\nl
+
+\def \ztbngatclear {%
+ \if \zerop{\ztbngstopindex}%
+ \global\ztbngstopcount = 0\relax
+ \else
+ \error{badtabclear}{Tabs must be cleared at the beginning of the line}%
+ \fi}
+
+% text@D\nl
+
+\def \ztbngatdiscard {%
+ \global\setflag \ztbngdiscardp = \true \relax}
+
+% Adjustment
+% ----------
+
+
+\long\def \ztbngadjust #1{% {commands}
+ \ztbngfinishfragment
+ \if \andp{\zerop{\ztbngstopindex}}{\dimzerop{\wd\ztbngfragment}}
+ #1%
+ \else
+ \error{badtabadjust}{The \noexpand\adjusttabbing command must appear
+ in between lines}%
+ \fi
+ \ztbngstartfragment}
diff --git a/macros/plain/contrib/zztex/tex/zztabularv1.tex b/macros/plain/contrib/zztex/tex/zztabularv1.tex
new file mode 100644
index 0000000000..13fb536ab8
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztabularv1.tex
@@ -0,0 +1,465 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Tabular Facilities
+%
+% Synopsis: This module contains all the facilities for producing
+% tabular material.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Tabular Block
+% ------- -----
+
+
+\let \tabularcomptext = \relax
+\let \tabulardepth = \relax
+\let \tabularnumber = \relax
+
+
+\defineblock{\tabular}{\endtabular}{\false}{}
+
+%~obsolete-block tabular Type
+% \abovepenalty = integer
+% \aboveskip = glue
+% \setflag \allowbreaks = boolean
+% \belowpenalty = integer
+% \belowskip = glue
+% \bodyfont = {...}
+% \colheadaboveskip = glue
+% \colheadbelowskip = glue
+% \colheadfont = {...}
+% \colsubheadfont = {...}
+% \columngutter = glue
+% \cutinheadaboveskip = glue
+% \cutinheadbelowskip = glue
+% \cutinheadfont = {...}
+% \interrowskip = glue
+% \leftindent = glue
+% \parhang = dimen
+% \parrag = dimen
+% \rightindent = glue
+% \rulecolwidth = dimen
+% \spannerheadfont = {...}
+% \spannerruleaboveskip = dimen
+% \spannerrulebelowskip = dimen
+% \spannerruleheight = dimen
+% \def \tabnoteformat ##1{...}
+% \tabrulecolor = {color}%
+% \tabruleheight = dimen
+% \width = dimen
+%~end
+
+\defineskip{\colheadaboveskip}{0pt}
+\let \headaboveskip = \colheadaboveskip
+\let \headbelowskip = \colheadbelowskip
+\definetoks{\colsubheadfont}
+\defineskip{\cutinheadaboveskip}{0pt}
+\defineskip{\cutinheadbelowskip}{0pt}
+\definetoks{\cutinheadfont}
+
+
+\definecount{\tabularcolcount}{0} % Number of columns in table.
+\definebox{\rowstrutbox} % Strut for table rows.
+
+
+\def \tabular #1#2{% {type}{template}
+ \endgraf
+ \beginblockscope{tabular}%
+ \global\increment \tabulardepth
+ \abovepenalty = \breakgood %~default hard
+ \belowpenalty = \breakbetter %~default hard
+ \tabrulecolor = {black}% %~default soft
+ \processdesign{\tabular}{#1}%
+ \global\increment \tabularnumber
+ \iffalse{\fi % Must be done with master
+ \tabularcolcount = 0 % counter > 0, to hide inner
+ \ztabcols #2&\zmark % \set and &.
+ \let \set = \span
+ \iffalse}\fi
+ \tabularformat
+ \fakepar
+ \nointerlineskip % We assume this below.
+ \if \notp{\allowbreaks}\vtop \fi \bgroup
+ \offinterlineskip
+ \everycr = {}%
+ \tabskip = \leftskip
+ \halign \if \dimneqlp{\width}{\naturalwidth}to \width \fi \bgroup
+ #2\tabskip = \rightskip \cr}
+
+\def \endtabular {%
+ \crcr
+ \egroup % \halign
+ \if \posp{\prevdepth}\kern -\interrowskip \fi % If last line has strut.
+ \egroup % \vtop
+ \prevdepth = \dp\strutbox % So row strut depth won't shine thru.
+ \futurelet\nexttoken \zendtabular}
+
+\def \zendtabular {%
+ \endtabularformat
+ \global\decrement \tabulardepth
+ \endblockscope{tabular}%
+ \parnext}
+
+\def \tabularformat {%
+ \endgraf
+ \the\bodyfont
+ \tdimena = \dp\strutbox
+ \advance \tdimena by \interrowskip
+ \setbox \rowstrutbox = \hbox{\vrule height \ht\strutbox depth \tdimena
+ width 0pt}%
+ \advance \aboveskip by \baselineskip % Compensate for absence
+ \advance \aboveskip by -\prevdepth % of interlineskip above
+ \advance \aboveskip by -\ht\rowstrutbox % first row of tabular.
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}}
+
+\def \endtabularformat{%
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+\def \ztabcols #1&#2\zmark{%
+ \increment \tabularcolcount
+ \if \notp{\emptyargp{#2}}\ztabcols #2\zmark \fi}
+
+% Template Facilities
+% -------- ----------
+
+
+% The following macros are used to construct the tabular template.
+% They are all used with the \set macro.
+
+\def \centercol {%
+ \hfil ##\rowstrut \hfil \tabskip=\columngutter}
+
+\def \centernumbercol #1{% {template}
+ \hfil \znumcell{#1}{##}\rowstrut \hfil \tabskip=\columngutter}
+
+\let \colgutter = \tabskip
+
+\def \customcol #1#2{% {left}{right}
+ #1\relax##\rowstrut #2\relax \tabskip=\columngutter}
+
+\def \customrulecol #1{% {width}
+ \color{\the\tabrulecolor}%
+ \vrule width #1 ##%
+ \endcolor \tabskip=\columngutter}
+
+\def \emptycol #1{% {width}
+ ##\rowstrut \hspace{#1}\tabskip=\columngutter}
+
+\def \leftcol {%
+ ##\rowstrut \hfil \tabskip=\columngutter}
+
+\def \leftnumbercol #1{% {template}
+ \znumcell{#1}{##}\rowstrut \hfil \tabskip=\columngutter}
+
+\def \parcol #1{% {width}
+ \vtop{\zpushvcontext
+ \zinitparcell{#1}{\parhang}%
+ \strut ##%
+ \if \hmodep \rowstrut \par \fi
+ \zpopvcontext}%
+ \tabskip=\columngutter}
+
+\def \rightcol {%
+ \hfil ##\rowstrut \tabskip=\columngutter}
+
+\def \rightnumbercol #1{% {template}
+ \hfil \znumcell{#1}{##}\rowstrut \tabskip=\columngutter}
+
+\def \rulecol {%
+ \color{\the\tabrulecolor}%
+ \vrule width \rulecolwidth ##%
+ \endcolor \tabskip=\columngutter}
+
+% Cell Facilities
+% ---- ----------
+
+
+% The following macros help with tabular entries (cells).
+
+\def \0{\phantom{0}}
+
+\def \centercell #1{% {text}
+ \omit
+ \hfil #1\rowstrut \hfil}
+
+\def \centerhead #1{% {heading}
+ \centercell{\the\colheadfont #1}}
+
+\def \centernumbercell #1#2{% {template}{text}
+ \omit
+ \hfil \znumcell{#1}{#2}\rowstrut \hfil}
+
+\def \centersubhead #1{% {heading}
+ \centercell{\the\colsubheadfont #1}}
+
+\def \customspannerrule #1#2{% {columns}{height}
+ \multispan{#1}%
+ \rowstrut
+ \ruleleaders{\hrule height #2 depth 0pt}}
+
+\def \customspannerruleabut #1#2{% {columns}{height}
+ \multispan{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}}
+
+\def \cutinhead #1{% {heading}
+ \multispan{\tabularcolcount}%
+ \leftcell{\the\cutinheadfont #1}}
+
+\def \cutinpar #1#2{% {width}{text}
+ \multispan{\tabularcolcount}%
+ \parhang = 0pt \parcell{#1}{#2}}
+
+\zremovePlaindef \hideskip
+\defineskip{\hideskip}{-1000pt plus 1fill}
+
+\def \hidewidth {\hskip \hideskip}
+
+\def \leftcell #1{% {text}
+ \omit
+ #1\rowstrut \hfil}
+
+\def \lefthead #1{% {heading}
+ \leftcell{\the\colheadfont #1}}
+
+\def \leftnumbercell #1#2{% {template}{text}
+ \omit
+ \znumcell{#1}{#2}\rowstrut \hfil}
+
+\def \leftsubhead #1{% {heading}
+ \leftcell{\the\colsubheadfont #1}}
+
+\def \multispan #1{% {columns}
+ \omit
+ \tcounta =#1\relax
+ \loop \ifnum \tcounta > 1 \zspan \repeat
+ \let \omit = \relax % In case the next thing is a \leftcell or whatever.
+ \ignorespaces}
+
+\def \zspan{\span\omit \decrement \tcounta}
+
+\def \nocolrule {%
+ width 0pt }
+
+\def \parcell #1#2{% {width}{text}
+ \omit
+ \vtop{\zpushvcontext
+ \zinitparcell{#1}{\parhang}%
+ \strut #2%
+ \if \hmodep \rowstrut \par \fi
+ \zpopvcontext}}
+
+\def \rightcell #1{% {text}
+ \omit
+ \hfil #1\rowstrut}
+
+\def \righthead #1{% {heading}
+ \rightcell{\the\colheadfont #1}}
+
+\def \rightnumbercell #1#2{% {template}{text}
+ \omit
+ \hfil \znumcell{#1}{#2}\rowstrut}
+
+\def \rightsubhead #1{% {heading}
+ \rightcell{\the\colsubheadfont #1}}
+
+\def \rowstrut {\unhcopy \rowstrutbox}
+
+\def \spannerhead #1#2{% {columns}{heading}
+ \multispan{#1}%
+ \centercell{\the\spannerheadfont #2}}
+
+\def \spannerrule #1{% {columns}
+ \multispan{#1}%
+ \rowstrut
+ \ruleleaders{\hrule height \spannerruleheight depth 0pt}}
+
+\def \spannerruleabut #1{% {columns}
+ \multispan{#1}%
+ \ruleleaders{\hrule height \spannerruleheight depth 0pt}}
+
+\def \spannerruleabutbelow #1{% {columns}
+ \multispan{#1}%
+ \vrule height \ht\rowstrutbox depth 0pt width 0pt\relax
+ \ruleleaders{\hrule height \spannerruleheight depth 0pt}}
+
+\def \tabnote #1{% {note-mark}
+ {\tabnoteformat{#1}}}
+
+\def \znumcell #1#2{% {template}{text}
+ \if \emptyargp{#2}%
+ \relax
+ \else
+ \znumcella{#1}{#2}%
+ \fi}
+
+\def \znumcella #1#2{% {template}{text}
+ {\ztoksa = {}\ztoksb = {}%
+ \setflag \znumpt = \false
+ \znumcellb #1\zmark
+ \setbox\zboxa = \hbox{\the\ztoksa}%
+ \tdimena = \wd\zboxa
+ \setbox\zboxa = \hbox{\the\ztoksb}%
+ \tdimenb = \wd\zboxa
+ \setflag \ztempt = \znumpt
+ \ztoksa = {}\ztoksb = {}%
+ \setflag \znumpt = \false
+ \znumcellb #2\zmark
+ \if \ztempt % Template had a decimal point.
+ \if \znumpt
+ \hbox to \tdimena{\hss \the\ztoksa}%
+ \the\decimalpoint
+ \hbox to \tdimenb{\the\ztoksb \hss}%
+ \else
+ \setbox\zboxa = \hbox{\the\decimalpoint}%
+ \hbox to \tdimena{\hss \the\ztoksa}%
+ \kern \wd\zboxa \kern \tdimenb
+ \fi
+ \else % Template had no decimal point.
+ \if \znumpt
+ \error{celldecpt}{Tabular template did not specify a decimal point}%
+ \else
+ \hbox to \tdimena{\hss \the\ztoksa}%
+ \fi
+ \fi}}
+
+\def \znumcellb #1#2\zmark{% t1 trest \zmark
+ \if \codeeqlp{\noexpand#1}{\the\decimalpoint}%
+ \setflag \znumpt = \true
+ \else
+ \if \znumpt
+ \ztoksb = \expandafter{\the\ztoksb #1}%
+ \else
+ \ztoksa = \expandafter{\the\ztoksa #1}%
+ \fi
+ \fi
+ \if \emptyargp{#2}%
+ \let \znext = \relax
+ \else
+ \def \znext {\znumcellb #2\zmark}%
+ \fi
+ \znext}
+
+% Inter-Row Facilities
+% --------- ----------
+
+
+% The following macros perform various actions in between rows.
+
+\def \adjusttab #1{%
+ \if \notp{\vmodep}%
+ \error{badrowcmd}{The \string\adjusttab command cannot be used in a table row}%
+ \fi
+ \noalign{#1}}
+
+\def \customtabrule #1{% {height}
+ \multispan{\tabularcolcount}%
+ \rowstrut
+ \color{\the\tabrulecolor}%
+ \ruleleaders{\hrule height #1 depth 0pt}%
+ \endcolor
+ \cr}
+
+\def \customtabruleabut #1{%
+ \multispan{\tabularcolcount}%
+ \color{\the\tabrulecolor}%
+ \ruleleaders{\hrule height #1 depth 0pt}%
+ \endcolor
+ \cr}
+
+\def \customtabruleabutbelow #1{%
+ \multispan{\tabularcolcount}%
+ \vrule height \ht\rowstrutbox depth 0pt width 0pt\relax
+ \color{\the\tabrulecolor}%
+ \ruleleaders{\hrule height #1 depth 0pt}%
+ \endcolor
+ \cr}
+
+\def \nointerrowskip {\tabvspace{-\interrowskip}}
+
+\def \skipabovecolhead {%
+ \tabbbskip{\colheadaboveskip}}
+
+\def \skipbelowcolhead {%
+ \tabbbskip{\colheadbelowskip}}
+
+\def \skipabovespannerrule {%
+ \tabbbskip{\spannerruleaboveskip}}
+
+\def \skipbelowspannerrule {%
+ \tabbbskip{\spannerrulebelowskip}}
+
+\def \skipabovecutinhead {%
+ \tabbbskip{\cutinheadaboveskip}}
+
+\def \skipbelowcutinhead {%
+ \tabbbskip{\cutinheadbelowskip}}
+
+\def \tabbbskip #1{% {glue}
+ \adjusttab{\zskipa = #1\relax
+ \advance \zskipa by -\ht\rowstrutbox
+ \advance \zskipa by -\dp\rowstrutbox
+ \vskip \zskipa}}
+
+\def \tabrule {%
+ \multispan{\tabularcolcount}%
+ \rowstrut
+ \color{\the\tabrulecolor}%
+ \ruleleaders{\hrule height \tabruleheight depth 0pt}%
+ \endcolor
+ \cr}
+
+\def \tabruleabut {%
+ \multispan{\tabularcolcount}%
+ \color{\the\tabrulecolor}%
+ \ruleleaders{\hrule height \tabruleheight depth 0pt}%
+ \endcolor
+ \cr}
+
+\def \tabruleabutbelow {%
+ \multispan{\tabularcolcount}%
+ \vrule height \ht\rowstrutbox depth 0pt width 0pt\relax
+ \color{\the\tabrulecolor}%
+ \ruleleaders{\hrule height \tabruleheight depth 0pt}%
+ \endcolor
+ \cr}
+
+\def \tabvspace #1{\adjusttab{\vskip #1}}% {glue}
+
+% Alignment Utilities
+% --------- ---------
+
+
+\let \completerow = \cr
+
+\def \ialign {\everycr = {}\tabskip = 0pt \halign}
+
+\def \oalign #1{% {row...}
+ \ensurepar
+ \vtop{\baselineskip = 0pt
+ \lineskip = .25ex
+ \ialign{##\cr #1\crcr}}}
+
+\def \ooalign {%
+ \lineskiplimit = -\maxdimen
+ \oalign}
+
+\def \ozalign {%
+ \lineskiplimit = 0pt\relax
+ \oalign}
+
+\def \zinitparcell #1#2{% {width}{hang}
+ \baselineskip = \normalbaselineskip
+ \lineskiplimit = 0pt \lineskip = 0pt
+ \setindentation{0pt}{0pt}%
+ \settextwidth{#1}%
+ \setparrag{\parrag}%
+ \leftskip = #2
+ \parindent = -#2
+ \parfillskip = \normalparfillskip}
diff --git a/macros/plain/contrib/zztex/tex/zztabularv2.tex b/macros/plain/contrib/zztex/tex/zztabularv2.tex
new file mode 100644
index 0000000000..932a42f5d4
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztabularv2.tex
@@ -0,0 +1,512 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Tabular Facilities
+%
+% Synopsis: This module contains all the facilities for producing
+% tabular material. This is the second major version.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 30 April 2001
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Tabular Block
+% ------- -----
+
+
+\let \tabularcomptext = \relax
+\let \tabulardepth = \relax
+\let \tabularnumber = \relax
+
+
+\defineblock{\tabular}{\endtabular}{\false}{}
+
+%~obsolete-block tabular Type
+% \abovepenalty = integer
+% \aboveskip = glue
+% \belowpenalty = integer
+% \belowskip = glue
+% \bodyfont = {...}
+% \columngutter = glue
+% \colheadaboveskip = glue
+% \colheadbelowskip = glue
+% \colheadfont = {...}
+% \cutinheadfont = {...}
+% \setflag \hastoprule = \false
+% \interrowskip = glue
+% \leftindent = glue
+% \parhang = dimen
+% \parrag = dimen
+% \rightindent = glue
+% \rulecolwidth = dimen
+% \sectionheadaboveskip = glue
+% \sectionheadbelowskip = glue
+% \sideheadfont = {...}
+% \spannerheadfont = {...}
+% \spannerruleaboveskip = dimen
+% \spannerrulebelowskip = dimen
+% \spannerrulecolor = {color}
+% \spannerruleheight = dimen
+% \style = {...}
+% \tabbottomruleaboveskip = dimen
+% \tabheadrulebelowskip = dimen
+% \def \tabnoteformat ##1{...}
+% \tabrulecolor = {color}
+% \tabruleheight = dimen
+% \width = dimen
+%~end
+
+\defineskip{\colheadaboveskip}{0pt}
+%%%\defineskip{\colheadbelowskip}{0pt}
+%%%\definetoks{\colheadfont}
+\definetoks{\cutinheadfont}
+%%%\definedimen{\rulecolwidth}{0pt}
+\defineskip{\sectionheadaboveskip}{0pt}
+\defineskip{\sectionheadbelowskip}{0pt}
+%%%\definetoks{\sideheadfont}
+%%%\definetoks{\spannerheadfont}
+%%%\defineskip{\spannerruleaboveskip}{0pt}
+%%%\defineskip{\spannerrulebelowskip}{0pt}
+%%%\definetoks{\spannerrulecolor}
+%%%\definedimen{\spannerruleheight}{0pt}
+%%%\definedimen{\tabbottomruleaboveskip}{0pt}
+%%%\definedimen{\tabheadrulebelowskip}{0pt}
+%%%\definetoks{\tabrulecolor}
+%%%\definedimen{\tabruleheight}{0pt}
+
+
+%%%\definecount{\tabcolcount}{0} % Number of columns in table.
+
+\definetoks{\ztabspacetoks} % Special row for vertical spacing.
+%%%\definebox{\zrowstrut} % Strut for table rows.
+%%%\definebox{\zparcelltopstrut} % Strut for first line of par cell.
+%%%\definebox{\zparcellbotstrut} % Strut for last line of par cell.
+
+
+\def \tabular #1#2{% {type}{template}
+ \endgraf
+ \beginblockscope{tabular}%
+ \global\increment \tabulardepth
+ \abovepenalty = \breakgood %~default hard
+ \belowpenalty = \breakbetter %~default hard
+ \setflag \hastoprule = \false %~default soft
+ \parhang = 0pt %~default soft
+ \spannerrulecolor = {black}% %~default soft
+ \style = {top/head/bottom rules}% %~default soft
+ \tabrulecolor = {black}% %~default soft
+ \processdesign{\tabular}{#1}%
+ \global\increment \tabularnumber
+ \iffalse{\fi % Analyze the template with
+ \tabcolcount = 0 % master counter > 0 to hide
+ \ztabspacetoks = {}% % \set and &.
+ \zchecktabcols #2&\zmark
+ \let \set = \span
+ \iffalse}\fi
+ \tabularformat
+ \offinterlineskip
+ \everycr = {}%
+ \defineatsigncommand @A{\adjustcolrule}%
+ \defineatsigncommand @C{\nointerrowskip}%
+ \defineatsigncommand @N{\nocolrule}%
+ \defineatsigncommand @S{\skipabovespannerrule}%
+ \defineatsigncommand @T{\skipbelowspannerrule}%
+ \tabskip = \leftskip
+ \halign \if \dimneqlp{\width}{\naturalwidth}to \width \fi \bgroup
+ #2\tabskip = \rightskip\cr}
+
+\def \endtabular {%
+ \egroup % \halign
+ \if \posp{\prevdepth}% % Does the last line have a strut?
+ \kern -.5\interrowskip % To eliminate row strut depth.
+ \prevdepth = \dp\strutbox
+ \else
+ \prevdepth = \tabruleheight
+ \fi
+ \futurelet\nexttoken \zendtabular}
+
+\def \zendtabular {%
+ \endtabularformat
+ \global\decrement \tabulardepth
+ \endblockscope{tabular}%
+ \parnext}
+
+\def \tabularformat {%
+ \the\bodyfont
+ \calculate \tdimena = {\interrowskip,/,2,+,\ht\strutbox}%
+ \calculate \tdimenb = {\interrowskip,/,2,+,\dp\strutbox}%
+ \setbox \zrowstrut = \hbox{\vrule width 0pt
+ height \tdimena depth \tdimenb}%
+ \setbox \zparcelltopstrut = \hbox{\vrule width 0pt
+ height \tdimena depth 0pt}%
+ \setbox \zparcellbotstrut = \hbox{\vrule width 0pt
+ height 0pt depth \tdimenb}%
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \fakepar % This fakes an empty paragraph
+ \hbox{}% % so the \bbskipabove works.
+ \nobreak
+ \vskip \if \hastoprule -\tabruleheight \else -\ht\zrowstrut \fi
+ \alterindentation{\leftindent}{\rightindent}}
+
+\def \endtabularformat{%
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+\def \zchecktabcols #1#2#3&#4\zmark{%
+ \if \notp{\tokeqlp{#1}{\set}}%
+ \error{misset}{A tabular column template must begin with \string\set}%
+ \fi
+ \if \posp{\tabcolcount}%
+ \ztabspacetoks = \expandafter{\the\ztabspacetoks &}%
+ \fi
+ \if \notp{\tokeqlp{#2}{\rulecol}}%
+ \ztabspacetoks = \expandafter{\the\ztabspacetoks \omit \ztabspacestrut}%
+ \fi
+ \increment \tabcolcount
+ \if \notp{\emptyargp{#4}}\zchecktabcols #4\zmark \fi}
+
+% Template Facilities
+% -------- ----------
+
+
+% The following macros are used to construct the tabular template.
+% They are all used with the \set macro.
+
+\def \centercol {%
+ \hfil ##\rowstrut \hfil \tabskip=\columngutter}
+
+\def \centernumbercol #1{% {template}
+ \hfil \znumcell{#1}{##}\rowstrut \hfil \tabskip=\columngutter}
+
+\let \gutter = \tabskip
+
+\def \customcol #1{% {template}
+ #1\rowstrut \tabskip=\columngutter}
+
+\def \customrulecol #1#2{% {color}{width}
+ \color{#1}%
+ \vrule width #2 ##%
+ \endcolor \tabskip=\columngutter}
+
+\def \emptycol #1{% {width}
+ ##\rowstrut \hspace{#1}\tabskip=\columngutter}
+
+\def \leftcol {%
+ ##\rowstrut \hfil \tabskip=\columngutter}
+
+\def \leftnumbercol #1{% {template}
+ \znumcell{#1}{##}\rowstrut \hfil \tabskip=\columngutter}
+
+\def \parcol #1{% {width}
+ \vtop{\zpushvcontext
+ \zinitparcell{#1}{\parhang}%
+ \unhcopy \zparcelltopstrut ##%
+ \if \hmodep \unhcopy \zparcellbotstrut \par \fi
+ \zpopvcontext}%
+ \tabskip=\columngutter}
+
+\def \rightcol {%
+ \hfil ##\rowstrut \tabskip=\columngutter}
+
+\def \rightnumbercol #1{% {template}
+ \hfil \znumcell{#1}{##}\rowstrut \tabskip=\columngutter}
+
+\def \rulecol {%
+ \color{\the\tabrulecolor}%
+ \vrule width \rulecolwidth ##%
+ \endcolor \tabskip=\columngutter}
+
+% Cell Facilities
+% ---- ----------
+
+
+% The following macros help with tabular entries (cells).
+
+\def \0{\phantom{0}}
+
+\def \centercell #1{% {text}
+ \omit
+ \hfil #1\rowstrut \hfil}
+
+\def \centerhead #1{% {heading}
+ \centercell{\the\colheadfont #1}}
+
+\def \centernumbercell #1#2{% {template}{text}
+ \omit
+ \hfil \znumcell{#1}{#2}\rowstrut \hfil}
+
+\def \cutinhead #1{% {heading}
+ \skipabovetabsection
+ \multispan{\tabcolcount}%
+ \leftcell{\the\cutinheadfont #1}\cr
+ \skipbelowtabsection}
+
+\zremovePlaindef \hideskip
+\defineskip{\hideskip}{-1000pt plus 1fill}
+
+\def \hidewidth {\hskip \hideskip}
+
+\def \leftcell #1{% {text}
+ \omit
+ #1\rowstrut \hfil}
+
+\def \lefthead #1{% {heading}
+ \leftcell{\the\colheadfont #1}}
+
+\def \leftnumbercell #1#2{% {template}{text}
+ \omit
+ \znumcell{#1}{#2}\rowstrut \hfil}
+
+\def \multispan #1{% {columns}
+ \omit
+ \tcounta = #1%
+ \loop \ifnum \tcounta > 1 \zspan \repeat
+ \let \omit = \relax % In case the next thing is a \leftcell or whatever.
+ \ignorespaces}
+
+\def \zspan {\span\omit \decrement \tcounta}
+
+\def \parcell #1#2{% {width}{text}
+ \omit
+ \vtop{\zpushvcontext
+ \zinitparcell{#1}{\parhang}%
+ \unhcopy \zparcelltopstrut #2%
+ \if \hmodep \unhcopy \zparcellbotstrut \par \fi
+ \zpopvcontext}}
+
+\def \rightcell #1{% {text}
+ \omit
+ \hfil #1\rowstrut}
+
+\def \righthead #1{% {heading}
+ \rightcell{\the\colheadfont #1}}
+
+\def \rightnumbercell #1#2{% {template}{text}
+ \omit
+ \hfil \znumcell{#1}{#2}\rowstrut}
+
+\def \rowstrut {%
+ \unhcopy \zrowstrut}
+
+\def \sidehead #1{% {heading}
+ \leftcell{\the\sideheadfont #1}}
+
+\def \spannerhead #1#2{% {columns}{heading}
+ \multispan{#1}%
+ \centercell{\the\spannerheadfont #2}}
+
+\def \tabnote #1{% {note-mark}
+ {\tabnoteformat{#1}}}
+
+\def \znumcell #1#2{% {template}{text}
+ \if \emptyargp{#2}%
+ \relax
+ \else
+ \znumcella{#1}{#2}%
+ \fi}
+
+\def \znumcella #1#2{% {template}{text}
+ {\ztoksa = {}\ztoksb = {}%
+ \setflag \znumpt = \false
+ \znumcellb #1\zmark
+ \setbox\zboxa = \hbox{\the\ztoksa}%
+ \tdimena = \wd\zboxa
+ \setbox\zboxa = \hbox{\the\ztoksb}%
+ \tdimenb = \wd\zboxa
+ \setflag \ztempt = \znumpt
+ \ztoksa = {}\ztoksb = {}%
+ \setflag \znumpt = \false
+ \znumcellb #2\zmark
+ \if \ztempt % Template had a decimal point.
+ \if \znumpt
+ \hbox to \tdimena{\hss \the\ztoksa}%
+ \the\decimalpoint
+ \hbox to \tdimenb{\the\ztoksb \hss}%
+ \else
+ \setbox\zboxa = \hbox{\the\decimalpoint}%
+ \hbox to \tdimena{\hss \the\ztoksa}%
+ \kern \wd\zboxa \kern \tdimenb
+ \fi
+ \else % Template had no decimal point.
+ \if \znumpt
+ \error{celldecpt}{Tabular template did not specify a decimal point}%
+ \else
+ \hbox to \tdimena{\hss \the\ztoksa}%
+ \fi
+ \fi}}
+
+\def \znumcellb #1#2\zmark{% t1 trest \zmark
+ \if \codeeqlp{\noexpand#1}{\the\decimalpoint}%
+ \setflag \znumpt = \true
+ \else
+ \if \znumpt
+ \ztoksb = \expandafter{\the\ztoksb #1}%
+ \else
+ \ztoksa = \expandafter{\the\ztoksa #1}%
+ \fi
+ \fi
+ \if \emptyargp{#2}%
+ \let \znext = \relax
+ \else
+ \def \znext {\znumcellb #2\zmark}%
+ \fi
+ \znext}
+
+% Rule Facilities
+% ---- ----------
+
+
+\def \adjustcolrule #1,#2,#3;{% width,height,depth;
+ \if \notp{\emptyargp{#1}}width #1pt\fi
+ \if \notp{\emptyargp{#2}}height #2pt\fi
+ \if \notp{\emptyargp{#3}}depth #3pt\fi\relax}
+
+\def \custompartialtabrule #1#2#3{% {color}{thickness}{columns}
+ \multispan{#3}%
+ \color{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}%
+ \endcolor}
+
+\def \customspannerrule #1#2#3{% {color}{thickness}{columns}
+ \multispan{#3}%
+ \rowstrut
+ \color{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}%
+ \endcolor}
+
+\def \customtabrule #1#2{% {color}{thickness}
+ \multispan{\tabcolcount}%
+ \color{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}%
+ \endcolor\cr}
+
+\def \nocolrule {%
+ width 0pt }
+
+\def \partialtabrule #1{% {columns}
+ \custompartialtabrule{\the\tabrulecolor}{\tabruleheight}{#1}}
+
+\def \spannerrule #1{% {columns}
+ \customspannerrule{\the\spannerrulecolor}{\spannerruleheight}{#1}}
+
+\def \tabbottomrule {%
+ \tabbbskipaboverule{\tabbottomruleaboveskip}%
+ \tabrule}
+
+\def \tabheadrule {%
+ \tabbbskipaboverule{\colheadbelowskip}%
+ \tabrule
+ \tabbbskipbelowrule{\tabheadrulebelowskip}}
+
+\def \tabrule {%
+ \customtabrule{\the\tabrulecolor}{\tabruleheight}}
+
+\def \tabtoprule {%
+ \tabrule
+ \tabbbskipbelowrule{\colheadaboveskip}}
+
+% Spacing Facilities
+% ------- ----------
+
+
+\definedimen{\zskipamount}{0pt}
+
+
+\def \nointerrowskip {%
+ \tabvspace{-\interrowskip}}
+
+\def \skipabovecolhead {%
+ \tabbbskip{\colheadaboveskip}}
+
+\def \skipbelowcolhead {%
+ \tabbbskip{\colheadbelowskip}}
+
+\def \skipabovespannerrule {%
+ \tabbbskip{\spannerruleaboveskip}}
+
+\def \skipbelowspannerrule {%
+ \tabbbskip{\spannerrulebelowskip}}
+
+\def \skipabovetabsection {%
+ \tabbbskip{\sectionheadaboveskip}}
+
+\def \skipbelowtabsection {%
+ \tabbbskip{\sectionheadbelowskip}}
+
+\def \tabbbskip #1{%
+ \noalign{%
+ \calculate \zskipamount = {#1,-,\dp\zrowstrut,-,\ht\zrowstrut}%
+ \ztabvspace{\zskipamount}}%
+ \the\ztabspacetoks\cr}
+
+\def \tabbbskipaboverule #1{%
+ \noalign{%
+ \calculate \zskipamount = {#1,-,\dp\zrowstrut,-,\tabruleheight}%
+ \ztabvspace{\zskipamount}}%
+ \the\ztabspacetoks\cr}
+
+\def \tabbbskipbelowrule #1{%
+ \noalign{%
+ \calculate \zskipamount = {#1,-,\ht\zrowstrut,-,\tabruleheight}%
+ \ztabvspace{\zskipamount}}%
+ \the\ztabspacetoks\cr}
+
+\def \tabvspace #1{%
+ \noalign{\ztabvspace{#1}}%
+ \the\ztabspacetoks\cr}
+
+\def \ztabvspace #1{%
+ \if \dimnegp{#1}%
+ \vskip #1\relax
+ \global\zskipamount = 0pt
+ \else
+ \global\zskipamount = #1%
+ \fi}
+
+\def \ztabspacestrut {%
+ \vrule width 0pt height 0pt depth \zskipamount\relax}
+
+% Inter-Row Facilities
+% --------- ----------
+
+
+\def \adjusttab #1{%
+ \if \notp{\vmodep}%
+ \error{badrowcmd}{The \string\adjusttab command cannot be used
+ in a table row}%
+ \fi
+ \noalign{#1}}
+
+
+% Utilities
+% ---------
+
+
+\let \completerow = \cr
+
+\def \ialign {\everycr = {}\tabskip = 0pt \halign}
+
+\def \oalign #1{% {row...}
+ \ensurepar
+ \vtop{\baselineskip = 0pt
+ \lineskip = .25ex
+ \ialign{##\cr #1\crcr}}}
+
+\def \ooalign {%
+ \lineskiplimit = -\maxdimen
+ \oalign}
+
+\def \ozalign {%
+ \lineskiplimit = 0pt\relax
+ \oalign}
+
+\def \zinitparcell #1#2{% {width}{hang}
+ \baselineskip = \normalbaselineskip
+ \lineskiplimit = 0pt \lineskip = 0pt
+ \setindentation{0pt}{0pt}%
+ \settextwidth{#1}%
+ \setparrag{\parrag}%
+ \leftskip = #2
+ \parindent = -#2
+ \parfillskip = \normalparfillskip}
diff --git a/macros/plain/contrib/zztex/tex/zztabularv3.tex b/macros/plain/contrib/zztex/tex/zztabularv3.tex
new file mode 100644
index 0000000000..c7035daa73
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztabularv3.tex
@@ -0,0 +1,771 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Tabular Facilities, version 3
+%
+% Synopsis: This module contains all the facilities for producing
+% tabular material. This is the third major version.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 4 June 2004
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Tabular Block
+% ------- -----
+
+
+\defineblock{\tabular}{\endtabular}{\false}{}
+
+%~block tabular Type
+% \abovepenalty = integer % Penalty above text.
+% \aboveskip = glue % Space b/b above text.
+% \belowpenalty = integer % Penalty below text.
+% \belowskip = glue % Space b/b below text.
+% \bodyfont = {font} % Body font.
+% \columngutter = glue % Width of column gutter.
+% \colheadbelowskip = dimen % Space b/b below column heads.
+% \colheadcolor = {color} % Color of Column heads.
+% \colheadfont = {font} % Column head font.
+% \interrowskip = dimen % Extra space between rows.
+% \leftindent = glue % Left indentation.
+% \parhang = dimen % Paragraph column hang.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = skip % Paragraph skip.
+% \rightindent = glue % Right indentation.
+% \rulecolcolor = {color} % Color of table rules.
+% \rulecolwidth = dimen % Width of column rules.
+% \sideheadaboveskip = dimen % Space b/b above side heads.
+% \sideheadbelowskip = dimen % Space b/b below side heads.
+% \sideheadcolor = {color} % Color of side heads.
+% \sideheadfont = {font} % Side head font.
+% \spannerheadcolor = {color} % Color of spanner heads.
+% \spannerheadfont = {font} % Spanner head font.
+% \spannerruleaboveskip = dimen % Space b/b above spanner rules.
+% \spannerrulebelowskip = dimen % Space b/b below spanner rules.
+% \spannerrulecolor = {color} % Color of spanner rules.
+% \spannerruleheight = dimen % Spanner rule thickness.
+% \style = {...} % Style description.
+% \tabbottomruleaboveskip = dimen % Space b/b above bottom rules.
+% \tabheadrulebelowskip = dimen % Space b/b below head rules.
+% \def \tabnoteformat ##1{...} % Format of table note references.
+% \tabrulecolor = {color} % Color of table rules.
+% \tabruleheight = dimen % Table rule thickness.
+% \tabtoprulebelowskip = dimen % Space b/b below top rules.
+% \width = dimen % Width of tabular material.
+%~end
+
+\defineskip{\colheadbelowskip}{0pt}
+\definetoks{\colheadcolor}
+\definetoks{\colheadfont}
+\definetoks{\rulecolcolor}
+\definedimen{\rulecolwidth}{0pt}
+\definedimen{\sideheadaboveskip}{0pt}
+\definedimen{\sideheadbelowskip}{0pt}
+\definetoks{\sideheadcolor}
+\definetoks{\sideheadfont}
+\definetoks{\spannerheadcolor}
+\definetoks{\spannerheadfont}
+\definedimen{\spannerruleaboveskip}{0pt}
+\definedimen{\spannerrulebelowskip}{0pt}
+\definetoks{\spannerrulecolor}
+\definedimen{\spannerruleheight}{0pt}
+\definedimen{\tabbottomruleaboveskip}{0pt}
+\definedimen{\tabheadrulebelowskip}{0pt}
+\definetoks{\tabrulecolor}
+\definedimen{\tabruleheight}{0pt}
+\definedimen{\tabtoprulebelowskip}{0pt}
+
+
+\def \tabular #1#2{% {type}{template}
+ \endgraf
+ \beginblockscope{tabular}%
+ \global\increment \tabulardepth
+ \abovepenalty = \breakgood %~default hard
+ \belowpenalty = \breakbetter %~default hard
+ \processdesign{\tabular}{#1}%
+ \global\increment \tabularnumber
+ \zsetuptabular{#2}%
+ \tabularformat
+ \defineatsigncommand @A{\adjustcolrule}%
+ \defineatsigncommand @C{\closeuprows}%
+ \defineatsigncommand @N{\nocolrule}%
+ \defineatsigncommand @S{\skipabovespannerrule}%
+ \defineatsigncommand @T{\skipbelowspannerrule}%
+ \offinterlineskip
+ \nobreak
+ \tabskip=\leftskip
+ \halign \if \dimneqlp{\width}{\naturalwidth}to \width \fi \bgroup
+ \span\the\zpreamble \tabskip=\rightskip \cr}
+
+\def \endtabular {%
+ \crcr
+ \egroup % \halign
+ \if \posp{\prevdepth}% % Does the last line have a strut?
+ \kern -.5\interrowskip % Yes, eliminate extra depth from
+ \prevdepth = \dp\strutbox % \interrowskip.
+ \else
+ \prevdepth = \tabruleheight % No, compensate for bottom rule.
+ \fi
+ \futurelet\nexttoken \zendtabular}
+
+\def \zendtabular {%
+ \endtabularformat
+ \global\decrement \tabulardepth
+ \endblockscope{tabular}%
+ \parnext}
+
+\def \tabularformat {%
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \fakepar % This empty paragraph allows
+ \hbox{}% % the \bbskipabove to work.
+ \kern
+ \if \dimzerop{\tabtoprulebelowskip}-\ht\zrowstrut \else -\tabruleheight \fi
+ \alterindentation{\leftindent}{\rightindent}}
+
+\def \endtabularformat{%
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+\def \adjustcolumngutter #1{% {amount} %^tabular
+ \with{\advance\columngutter by #1}}
+
+\def \adjustinterrowskip #1{% {amount} %^tabular
+ \with{\advance\interrowskip by #1}}
+
+% Set Up Tabular
+% --- -- -------
+
+
+\definecount{\tabcolcount}{0} % Number of columns in table.
+\definetoks{\zpreamble} % Preamble for \halign.
+\definetoks{\ztabspacerow} % Special row for vertical spacing.
+\definebox{\zrowstrut} % Strut for table rows.
+\definebox{\zparcelltopstrut} % Strut for first line of par cell.
+\definebox{\zparcellbotstrut} % Strut for last line of par cell.
+
+\def \zsetuptabular #1{% {template}
+ \zanaltemplate{#1}%
+ \the\bodyfont
+ \calculate \tdimena = {\interrowskip,/,2,+,\ht\strutbox}%
+ \calculate \tdimenb = {\interrowskip,/,2,+,\dp\strutbox}%
+ \setbox \zrowstrut = \hbox{\vrule width 0pt
+ height \tdimena depth \tdimenb}%
+ \setbox \zparcelltopstrut = \hbox{\vrule width 0pt
+ height \tdimena depth 0pt}%
+ \setbox \zparcellbotstrut = \hbox{\vrule width 0pt
+ height 0pt depth \tdimenb}%
+ \global\zprevrowclass = \zrcpream
+ \global\zcurrowclass = \zrcpream
+ \gdef \zcolrulegate {}%
+ \global\setflag \zcolrulesenabled = \false
+ \everycr = {\noalign{\ztabcr}}}
+
+% Analyze Template
+% ------- --------
+
+
+\defineskip{\zpendgutter}{0pt}
+
+
+\def \zanaltemplate #1{% {template}
+ \setbox\zboxa = \hbox{%
+ \defineatsigncommand @!{\zcustomrulecol}%
+ \defineatsigncommand @>{\zgutterspec}%
+ \defineatsigncommand @c{\zcentercol}%
+ \defineatsigncommand @C{\zcenternumbercol}%
+ \defineatsigncommand @e{\zemptycol}%
+ \defineatsigncommand @l{\zleftcol}%
+ \defineatsigncommand @L{\zleftnumbercol}%
+ \defineatsigncommand @p{\zparcol}%
+ \defineatsigncommand @r{\zrightcol}%
+ \defineatsigncommand @R{\zrightnumbercol}%
+ \defineatsigncommand @s{\zspecialcol}%
+ \defineatsigncommand @|{\zrulecol}%
+ \global\tabcolcount = 0
+ \global\zpreamble = {}%
+ \global\ztabspacerow = {}%
+ #1}%
+ \tabcolcount = \tabcolcount
+ \zpreamble = \zpreamble
+ \ztabspacerow = \ztabspacerow}
+
+\def \zcentercol {%
+ \zstartcol{\false}%
+ \zappendpreamble{\hfil ##\rowstrut \hfil}}
+
+\def \zcenternumbercol #1{%
+ \zstartcol{\false}%
+ \zmeasuredanumber #1..\zmark
+ \edef \znext {%
+ \noexpand\zappendpreamble{%
+ \hfil \noexpand\zsetnumbercell{\the\tdimena}{\the\tdimenb}{####}\hfil}}%
+ \znext}
+
+\def \zcustomrulecol #1#2{% {color}{width}
+ \if \dimeqlp{\zpendgutter}{\mindimen}\zpendgutter = .5\columngutter \fi
+ \zstartcol{\true}%
+ \zappendpreamble{\zsetcolrule{#1}{#2}{##}}%
+ \zpendgutter = .5\columngutter}
+
+\def \zemptycol #1{% {width}
+ \zstartcol{\false}%
+ \zappendpreamble{##\rowstrut \hspace{#1}}}
+
+\def \zgutterspec #1{% {width}
+ \zparsegutterspec #1*\zmark}
+
+\def \zparsegutterspec #1*#2\zmark{%
+ \zpendgutter = #1\relax
+ \if \notp{\emptyargp{#2}}%
+ \advance \zpendgutter by \columngutter
+ \advance \zpendgutter by -1\columngutter
+ \fi}
+
+\def \zleftcol {%
+ \zstartcol{\false}%
+ \zappendpreamble{##\rowstrut \hfil}}
+
+\def \zleftnumbercol #1{%
+ \zstartcol{\false}%
+ \zmeasuredanumber #1..\zmark
+ \edef \znext {%
+ \noexpand\zappendpreamble{%
+ \noexpand\zsetnumbercell{\the\tdimena}{\the\tdimenb}{####}\hfil}}%
+ \znext}
+
+\def \zparcol #1{% {width}
+ \zstartcol{\false}%
+ \zappendpreamble{\zsetparcol{#1}{##}}}
+
+\def \zrightcol {%
+ \zstartcol{\false}%
+ \zappendpreamble{\hfil ##\rowstrut}}
+
+\def \zrightnumbercol #1{%
+ \zstartcol{\false}%
+ \zmeasuredanumber #1..\zmark
+ \edef \znext {%
+ \noexpand\zappendpreamble{%
+ \hfil \noexpand\zsetnumbercell{\the\tdimena}{\the\tdimenb}{####}}}%
+ \znext}
+
+\def \zrulecol {%
+ \if \dimeqlp{\zpendgutter}{\mindimen}\zpendgutter = .5\columngutter\relax \fi
+ \zstartcol{\true}%
+ \zappendpreamble{\zsetcolrule{}{}{##}}%
+ \zpendgutter = .5\columngutter\relax}
+
+\def \zspecialcol #1{% {template}
+ \zstartcol{\false}%
+ \zappendpreamble{#1\rowstrut}}
+
+\def \zstartcol #1{% {rule-column?}
+ \if \posp{\tabcolcount}%
+ \if \dimeqlp{\zpendgutter}{\mindimen}\zpendgutter = \columngutter \fi
+ \edef \znext {\noexpand\zappendpreamble{\tabskip=\the\zpendgutter &}}%
+ \znext
+ \global\ztabspacerow = \expandafter{\the\ztabspacerow &}%
+ \fi
+ \global\increment \tabcolcount
+ \if \notp{#1}%
+ \global\ztabspacerow = \expandafter{\the\ztabspacerow
+ \omit \copy \ztabvspacebox}%
+ \fi
+ \zpendgutter = \mindimen}
+
+\def \zappendpreamble #1{% {preamble stuff}
+ \global\zpreamble = \expandafter{\the\zpreamble #1}}
+
+% Preamble Helpers
+% -------- -------
+
+
+\def \zmeasuredanumber #1.#2.#3\zmark{%
+ \measuretextwidth{\tdimena}{#1}%
+ \measuretextwidth{\tdimenb}{.#2}%
+ \if \andp{\emptyargp{#2}}{\emptyargp{#3}}\tdimenb = 0pt\fi}
+
+\def \zsetcolrule #1#2#3{% {color}{width}{adjustment}
+ \if \emptyargp{#1}\color{\the\tabrulecolor}\else \color{#1}\fi
+ \vrule width \if \emptyargp{#2}\rulecolwidth \else #2\fi
+ \zcolrulegate #3%
+ \endcolor}
+
+\def \zsetnumbercell #1#2#3{% {pre-width}{post-width}{text}
+ \gdef \zcellstyle {}%
+ \zsplitdanumber #3..\zmark
+ \if \dimzerop{#2}%
+ \if \emptytoksp{\ztoksb}%
+ \hbox to #1{\hfil \the\ztoksa}%
+ \else
+ \error{celldecpt}{Template picture did not include a decimal point}%
+ \fi
+ \else
+ \hbox to #1{\hfil \the\ztoksa}%
+ \hbox to #2{\zcellstyle \the\ztoksb \hfil}%
+ \fi
+ \rowstrut}
+
+\long\def \zsetparcol #1#2{% {width}{text}
+ \vtop{%
+ \zpushvcontext
+ \baselineskip = \normalbaselineskip
+ \lineskiplimit = 0pt \lineskip = 0pt
+%%% \setindentation{0pt}{0pt}%
+ \settextwidth{#1}%
+ \setparrag{\parrag}%
+ \leftskip = \parhang
+ \parindent = -\parhang
+ \parfillskip = \normalparfillskip
+ \unhcopy \zparcelltopstrut
+ #2%
+ \if \hmodep \unhcopy \zparcellbotstrut \par \fi
+ \zpopvcontext}}
+
+\def \zsplitdanumber #1.#2.#3\zmark{%
+ \ztoksa = {#1}%
+ \ztoksb = {.#2}%
+ \if \andp{\emptyargp{#2}}{\emptyargp{#3}}\ztoksb = {}\fi}
+
+% Row Class
+% --- -----
+
+
+\definecount{\zprevrowclass}{0}
+\definecount{\zcurrowclass}{0}
+
+\chardef \zrcpream = 0
+\chardef \zrcdata = 1
+\chardef \zrchead = 2
+\chardef \zrcrule = 3
+\chardef \zrcvspace = 4
+\chardef \zrcbbskip = 5
+
+\def \zsetrowclass #1{%
+ \if \gtrp{#1}{\zcurrowclass}\global\zcurrowclass = #1\relax \fi}
+
+\def \ztabcr {%
+ \global\zprevrowclass = \zcurrowclass
+ \global\zcurrowclass = \zrcdata
+ \global\setflag \zcolrulesenabled = \false}
+
+% Cell Facilities
+% ---- ----------
+
+
+%~ This command produces a phantom zero, which is useful for aligning
+%~ numbers when decimal-aligned columns are not being used.
+
+\def \0{\phantom{0}} %^tabular
+
+\zremovePlaindef \hideskip
+\defineskip{\hideskip}{-1000pt plus 1fill}
+
+%~ This command "hides" the width of the cell from the column width calculation
+%~ process. The cell does not participate in determining the widest cell of
+%~ the column. If the cell is wider than the calculated column width, it will
+%~ stick into the left or right column gutter, depending on the position of the
+%~ |\hidewidth| command.
+
+\def \hidewidth {\hskip \hideskip} %^tabular
+
+%~ This command discards the templates for the specified number of columns and
+%~ creates one cell that spans them all. The content of the cell is specified
+%~ immediately following the command. This spanning cell has no template, so
+%~ you must include all the required commands in the cell text. This is usually done
+%~ using one of the cell override commands such as |\leftcell|.
+
+\def \multispan #1{% {columns} %^tabular
+ \omit
+ \tcounta = #1%
+ \loop \ifnum \tcounta > 1 \zspan \repeat
+ \let \omit = \relax % In case the next thing is a \leftcell or whatever.
+ \ignorespaces}
+
+\def \zspan {\span\omit \decrement \tcounta}
+
+\def \rowstrut {%
+ \unhcopy \zrowstrut}
+
+\def \zcellstyle {}
+
+\def \setcellstyle #1{%
+ #1%
+ \gdef \zcellstyle {#1}%
+ \ignorespaces}
+
+%~ This command sets a table note reference, usually a lowercase
+%~ letter. The format of the reference is determined by the design.
+
+\def \tabnote #1{% {note-mark} %^tabular
+ {\tabnoteformat{#1}}}
+
+% Cell Overrides
+% ---- ---------
+
+
+%~ This command overrides the template for the column and sets
+%~ a centered cell. It must appear immediately after the
+%~ ampersand (|&&|) that begins the cell.
+
+\def \centercell #1{% {text} %^tabular
+ \omit
+ \hfil #1\rowstrut \hfil}
+
+%~ This command overrides the template for the column and sets
+%~ a flush left cell. It must appear immediately after the
+%~ ampersand (|&&|) that begins the cell.
+
+\def \leftcell #1{% {text} %^tabular
+ \omit
+ #1\rowstrut \hfil}
+
+%~ This command overrides the template for the column and sets
+%~ a paragraph cell. It must appear immediately after the
+%~ ampersand (|&&|) that begins the cell.
+
+\def \parcell #1#2{% {width}{text} %^tabular
+ \omit
+ \zsetparcol{#1}{#2}}
+
+%~ This command overrides the template for the column and sets
+%~ a flush right cell. It must appear immediately after the
+%~ ampersand (|&&|) that begins the cell.
+
+\def \rightcell #1{% {text} %^tabular
+ \omit
+ \hfil #1\rowstrut}
+
+% Column Heads
+% ------ -----
+
+
+%~ This column head command produces a centered head.
+
+\def \centerhead #1{% {heading} %^tabular
+ \centercell{%
+ \the\colheadfont \colortext{\the\colheadcolor}{#1}%
+ \zchkadjheads}}
+
+%~ This column head command produces a flush left head.
+
+\def \lefthead #1{% {heading} %^tabular
+ \leftcell{%
+ \the\colheadfont \colortext{\the\colheadcolor}{#1}%
+ \zchkadjheads}}
+
+%~ This column head command produces a flush right head.
+
+\def \righthead #1{% {heading} %^tabular
+ \rightcell{%
+ \the\colheadfont \colortext{\the\colheadcolor}{#1}%
+ \zchkadjheads}}
+
+%~ This command produces a spanner head that spans the specified
+%~ number of columns.
+
+\def \spannerhead #1#2{% {columns}{heading} %^tabular
+ \multispan{#1}%
+ \centercell{\the\spannerheadfont \colortext{\the\spannerheadcolor}{#2}}%
+ \zsetrowclass{\zrchead}}
+
+\def \zchkadjheads {%
+ \if \andp{\eqlp{\zprevrowclass}{\zrchead}}{\posp{\interrowskip}}%
+ \warning{adjheads}{Two adjacent rows of heads need to be closed up}%
+ \global\zprevrowclass = \zrcdata
+ \fi
+ \zsetrowclass{\zrchead}}
+
+% Side Heads
+% ---- -----
+
+%~ This command is a shorthand for producing a cut-in head that spans the
+%~ entire width of the table. It is equivalent to:
+%~
+%~ | \skipabovesidehead
+%~ | \sidehead{*all-columns*}{*heading*}\cr
+%~ | \skipbelowsidehead
+
+\def \cutinhead #1{% {heading} %^tabular
+ \skipabovesidehead
+ \sidehead{\tabcolcount}{#1}\cr
+ \skipbelowsidehead}
+
+%~ This command produces a side head that spans the specified number of
+%~ columns. It is similar to |\spannerhead|. It is almost always the case that a
+%~ |\sidehead| row should be preceded by a |\skipabovesidehead| and followed by a
+%~ |\skipbelowsidehead|.
+
+\def \sidehead #1#2{% {columns}{heading} %^tabular
+ \multispan{#1}%
+ \leftcell{\the\sideheadfont \colortext{\the\sideheadcolor}{#2}}}
+
+% Vertical Spacing
+% -------- -------
+
+
+%~ This command eliminates the inter-row space between two rows. It must be
+%~ used between two consective rows of table heads. Shorthand: |@C|.
+
+\def \closeuprows {% %^tabular
+ \tabvspace{-\interrowskip}}
+
+%~ This command adds extra space between column heads and the first data row.
+%~ It must be used in tables that do not have head rules.
+
+\def \skipbelowcolhead {% %^tabular
+ \zchkbelowhead
+ \tabbbskip{\colheadbelowskip}}
+
+%~ This command produces the appropriate vertical space above
+%~ a spanner rule. Shorthand: |@S|. See also |\skipbelowspannerrule|.
+
+\def \skipabovespannerrule {% %^tabular
+ \tabbbskip{\spannerruleaboveskip}}
+
+%~ This command produces the appropriate vertical space below
+%~ a spanner rule. Shorthand: |@T|. See also |\skipabovespannerrule|.
+
+\def \skipbelowspannerrule {% %^tabular
+ \tabbbskip{\spannerrulebelowskip}}
+
+%~ This command produces the appropriate vertical space above
+%~ a side head. See also |\skipbelowsidehead|.
+
+\def \skipabovesidehead {% %^tabular
+ \tabbbskip{\sideheadaboveskip}}
+
+%~ This command produces the appropriate vertical space below
+%~ a side head. See also |\skiabovewsidehead|.
+
+\def \skipbelowsidehead {% %^tabular
+ \tabbbskip{\sideheadbelowskip}}
+
+%~ This command produces extra vertical space so that the base-to-base space
+%~ between the preceding and following rows is as specified.
+
+\def \tabbbskip #1{% {amount} %^tabular
+ \ztabbbskip{#1,-,\dp\zrowstrut,-,\ht\zrowstrut}%
+ \the\ztabspacerow\cr}
+
+%~ This command produces extra vertical space between a row and a rule.
+%~ It must be used instead of |\tabbbskip| to obtain the desired results when
+%~ spacing above horizontal rules. See also |\tabbbskipbelowrule|.
+
+\def \tabbbskipaboverule #1{% {amount} %^tabular
+ \noalign{\nobreak}%
+ \ztabbbskip{#1,-,\dp\zrowstrut,-,\tabruleheight}%
+ \noalign{\if \zcolrulesenabled \zsuppresscolrules \fi}%
+ \the\ztabspacerow \if \zcolrulesenabled \zallowcolrules \fi\cr
+ \noalign{\nobreak}}
+
+%~ This command produces extra vertical space between a rule and a row.
+%~ It must be used instead of |\tabbbskip| to obtain the desired results when
+%~ spacing below horizontal rules. See also |\tabbbskipaboverule|.
+
+\def \tabbbskipbelowrule #1{% {amount} %^tabular
+ \ztabbbskip{#1,-,\ht\zrowstrut}%
+ \the\ztabspacerow\cr}
+
+%~ This command produces the specified amount of extra vertical space
+%~ between two rows of the table.
+
+\def \tabvspace #1{% {amount} %^tabular
+ \noalign{%
+ \zsetrowclass{\zrcvspace}%
+ \zsetvspacebox{#1}}%
+ \the\ztabspacerow\cr}
+
+\def \ztabbbskip #1{%
+ \noalign{%
+ \zsetrowclass{\zrcbbskip}%
+ \if \eqlp{\zprevrowclass}{\zrcbbskip}%
+ \tdimena = 0pt\relax
+ \else
+ \calculate \tdimena = {#1}%
+ \fi
+ \zsetvspacebox{\tdimena}}}
+
+\definebox{\ztabvspacebox}
+\setbox \ztabvspacebox = \hbox{}%
+
+\def \zsetvspacebox #1{%
+ \if \dimnegp{#1}%
+ \vskip #1\relax
+ \dp\ztabvspacebox = 0pt
+ \else
+ \dp\ztabvspacebox = #1\relax
+ \fi}
+
+\def \zchkbelowhead {%
+ \noalign{%
+ \if \neqlp{\zprevrowclass}{\zrchead}%
+ \warning{needheads}{The previous row should be a row of column heads}%
+ \fi}}
+
+% Horizontal Rules
+% ---------- -----
+
+
+%~ This command produces a custom version of the partial table rule
+%~ (|\partialtabrule|). The color and thickness of the rules is specified
+%~ explicitly.
+
+\def \custompartialtabrule #1#2#3{% {color}{thickness}{columns} %^tabular
+ \multispan{#3}%
+ \color{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}%
+ \endcolor}
+
+%~ This command produces a custom version of the table spanner rule
+%~ (|\spannerrule|). The color and thickness of the rules is specified
+%~ explicitly.
+
+\def \customspannerrule #1#2#3{% {color}{thickness}{columns} %^tabular
+ \multispan{#3}%
+ \rowstrut
+ \color{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}%
+ \endcolor}
+
+%~ This command produces a custom version of the table rule
+%~ (|\tabrule|). The color and thickness of the rules is specified
+%~ explicitly.
+
+\def \customtabrule #1#2{% {color}{thickness} %^tabular
+ \multispan{\tabcolcount}%
+ \color{#1}%
+ \ruleleaders{\hrule height #2 depth 0pt}%
+ \endcolor\cr}
+
+%~ This command produces a table rule across the specified number of columns.
+%~ It is similar to |\spannerrule| but sets a rule of the same thickness
+%~ as |\tabrule|.
+
+\def \partialtabrule #1{% {columns} %^tabular
+ \custompartialtabrule{\the\tabrulecolor}{\tabruleheight}{#1}}
+
+%~ This command produces a spanner rule across the specified number of columns.
+%~ The color and thickness of the rule are determined by the design. A row with
+%~ spanner rules is usually preceded and followed by |\skipabovespannerrule| and
+%~ |\skipbelowspannerrule|.
+
+\def \spannerrule #1{% {columns} %^tabular
+ \customspannerrule{\the\spannerrulecolor}{\spannerruleheight}{#1}}
+
+%~ This command produces the standard bottom rule in a table. Which rules are
+%~ required is specified in the |\style| parameter of the |\tabular| design.
+%~ This command is not followed by |\cr|.
+
+\def \tabbottomrule {% %^tabular
+ \tabbbskipaboverule{\tabbottomruleaboveskip}%
+ \tabrule}
+
+%~ This command produces the standard head rule in a table. Which rules are
+%~ required is specified in the |\style| parameter of the |\tabular| design.
+%~ This command is not followed by |\cr|.
+
+\def \tabheadrule {% %^tabular
+ \zchkbelowhead
+ \tabbbskipaboverule{\colheadbelowskip}%
+ \tabrule
+ \tabbbskipbelowrule{\tabheadrulebelowskip}}
+
+%~ This command produces a table rule across the entire width of the table. The
+%~ color and thickness of the rule are determined by the design. This command
+%~ is not followed by |\cr|.
+
+\def \tabrule {% %^tabular
+ \customtabrule{\the\tabrulecolor}{\tabruleheight}}
+
+%~ This command produces the standard top rule in a table. Which rules are
+%~ required is specified in the |\style| parameter of the |\tabular| design.
+%~ This command is not followed by |\cr|.
+
+\def \tabtoprule {% %^tabular
+ \tabrule
+ \noalign{\nobreak}%
+ \tabbbskipbelowrule{\tabtoprulebelowskip}}
+
+% Vertical Rules
+% -------- -----
+
+
+%~ This command is used in the normally empty cell corresponding to a vertical
+%~ rule column. It adjusts the width, height, and/or depth of the rule in that
+%~ cell. To adjust one of those dimensions, specify the new dimension in
+%~ points, without the usual |pt|, in the appropriate argument position.
+%~ Omitted dimensions will have their standard values. You must specify both
+%~ commas and the semicolon. Shorthand: |@A*width*,*height*,*depth*;|
+
+\def \adjustcolrule #1,#2,#3;{% width,height,depth; %^tabular
+ \if \notp{\emptyargp{#1}}width #1pt\fi
+ \if \notp{\emptyargp{#2}}height #2pt\fi
+ \if \notp{\emptyargp{#3}}depth #3pt\fi\relax}
+
+%~ This command can be used between rows of a table to allow all vertical
+%~ rules. This is typically done after the column head portion of a table. If
+%~ |\allowcolrules| appears just before |\tabheadrule|, it is deferred until
+%~ after the vertical space above the horizontal rule, so that the vertical
+%~ rules recommence precisely at the horizontal rule. See also
+%~ |\suppresscolrules|.
+
+\def \allowcolrules {% %^tabular
+ \noalign{%
+ \zallowcolrules
+ \global\setflag \zcolrulesenabled = \true}}
+
+\def \zallowcolrules {%
+ \gdef \zcolrulegate {}}
+
+%~ This command can be used between rows of a table to suppress all vertical
+%~ rules. This is typically done for the column head portion of a table.
+%~ See also |\allowcolrules|.
+
+\def \suppresscolrules {% %^tabular
+ \noalign{\zsuppresscolrules}}
+
+\def \zsuppresscolrules {%
+ \gdef \zcolrulegate {\nocolrule}}
+
+%~ This command is used in the normally empty cell corresponding to a vertical
+%~ rule column. It suppresses the vertical rule in that cell. Shorthand: |@N|.
+
+\def \nocolrule {% %^tabular
+ width 0pt }
+
+% Inter-Row Facilities
+% --------- ----------
+
+
+%~ This command can be used between rows of a table to insert vertical material
+%~ that is independent of the rows themselves. It is rarely needed.
+
+\def \adjusttabular #1{% {commands} %^tabular
+ \noalign{#1}}
+
+\let \adjusttab = \adjusttabular
+
+% Low-Level Alignment Facilities
+% --------- --------- ----------
+
+
+\let \completerow = \cr
+
+\def \ialign {\everycr = {}\tabskip=0pt \halign}
+
+\def \oalign #1{% {row...}
+ \ensurepar
+ \vtop{\baselineskip = 0pt
+ \lineskip = .25ex
+ \ialign{##\cr #1\crcr}}}
+
+\def \ooalign {%
+ \lineskiplimit = -\maxdimen
+ \oalign}
+
+\def \ozalign {%
+ \lineskiplimit = 0pt\relax
+ \oalign}
diff --git a/macros/plain/contrib/zztex/tex/zztag.tex b/macros/plain/contrib/zztex/tex/zztag.tex
new file mode 100644
index 0000000000..32154dd8c4
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztag.tex
@@ -0,0 +1,269 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Tag Facilities
+%
+% Synopsis: This module contains the definitions necessary to implement
+% tags and references to them.
+%
+% Note: Tag names beginning with `zX:' are reserved for ZzTeX:
+%
+% zA: design alternative choices (obsolete)
+% zB: bibliographic tags
+% zE: frame page numbers
+% zF: float page numbers
+% zH: help text
+% zM: margin note page numbers
+% zP: proof note page numbers
+% zR: margin rule page numbers
+% zS: snapshot information
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 19 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Tag Definition
+% --- ----------
+
+
+\definetoks{\taginfonumber}
+\taginfonumber = {???}
+\definetoks{\taginfotitle}
+\taginfotitle = {???}
+\definecount{\zmistags}{0}
+
+
+% The number is fully expanded, while the title is not expanded.
+% Then we make sure they are never expanded again.
+
+\def \settaginfo #1#2{% {number}{title}
+ \edef \znext {\taginfonumber = {#1}}%
+ \znext
+ \taginfotitle = {#2}}
+
+\def \tag #1{% {name}
+ \if \emptytoksp{\taginfonumber}%
+ \warning{notaginfo}{ZzTeX reference: Misplaced tag '#1'}%
+ \global\increment \zmistags
+ \fi
+ \zbeginhidewrite
+ \edef \znext {\noexpand\xref{tag}{\noexpand\folio}%
+ {\the\taginfonumber}%
+ {\the\taginfotitle}
+ {#1}}%
+ \znext
+ \if \PDFhyperlinks \PDFmark{T:#1}\fi
+ \zendhidewrite}
+
+\def \tagwith #1#2{% {name}{reference-text}
+ \zbeginhidewrite
+ \edef \znext {\noexpand\xref{tag}{\noexpand\folio}%
+ {#2}%
+ {???notitle???}
+ {#1}}%
+ \znext
+ \if \PDFhyperlinks \PDFmark{T:#1}\fi
+ \zendhidewrite}
+
+% This is a special command when you just want to know the page number.
+
+\def \tagpageonly #1{% {name}
+ \zbeginhidewrite
+ \edef \znext {\noexpand\xref{tag}{\noexpand\folio}%
+ {???nonumber???}%
+ {???notitle???}
+ {#1}}%
+ \znext
+ \if \PDFhyperlinks \PDFmark{T:#1}\fi
+ \zendhidewrite}
+
+\def \uniquetag #1#2{% {prefix}{counter}
+ #1:\the\divisionname-#2}
+
+% Subtag Definition
+% ------ ----------
+
+
+\definecount{\subtagnumber}{0}
+
+
+\def \setsubtagnumber #1{% {integer}
+ \subtagnumber = #1\relax}
+
+\def \subtag #1#2{% {name}{subnumber}
+ \zparsesubnumber #2???\zmark
+ \tagwith{#1}{\zsubtagtext}}
+
+\def \zparsesubnumber #1?#2?#3?#4\zmark{%
+ \if \emptyargp{#2}%
+ \edef \zsubtagtext {\the\taginfonumber #1}%
+ \else
+ \increment \subtagnumber
+ \edef \zsubtagtext {\the\taginfonumber #1#2\subtagnumber#3}%
+ \fi}
+
+% Tag Reference
+% --- ---------
+
+
+% This counter keeps track of the number of undefined tag references.
+
+\definecount{\zuntagrefs}{0}
+
+
+\def \refnumber #1{% {tag-name}
+ \zbeginrefhilight
+ \if \definedp{\=#1}%
+ \zreftext{#1}{\expandafterthrice\ztagdata \name{\=#1}\zmark1}%
+ \else
+ \zuntag{#1}{???}%
+ \fi
+ \zendrefhilight}
+
+\let \ref = \refnumber % Because it's so common.
+
+\def \refpage #1{% {tag-name}
+ \zbeginrefhilight
+ \if \definedp{\=#1}%
+ \zreftext{#1}{\expandafterthrice\ztagdata \name{\=#1}\zmark0}%
+ \else
+ \zuntag{#1}{???}%
+ \fi
+ \zendrefhilight}
+
+\def \reftitle #1{% {tag-name}
+ \zbeginrefhilight
+ \if \notp{\allowreftitle}%
+ \warning{noreftitle}{Use of \string\reftitle is not allowed}%
+ ???not allowed???%
+ \else \if \definedp{\=#1}%
+ {\zadjtitle = \zadjtitlenone
+ \zreftext{#1}{\expandafterthrice\ztagdata \name{\=#1}\zmark2}}%
+ \else
+ \zuntag{#1}{???title???}%
+ \fi\fi
+ \zendrefhilight}
+
+\def \zbeginrefhilight {%
+ \if \DVIWindoinuse
+ \colorspecial{ifview color push rgb 1 0 .25}% % Color the reference.
+ \fi}
+
+\def \zendrefhilight {%
+ \if \DVIWindoinuse
+ \colorspecial{ifview color pop}% % Done with color.
+ \fi}
+
+\def \zreftext #1#2{% {tag}{text}
+ \if \PDFhyperlinks
+ \tagbutton{#1}{#2}%
+ \else
+ #2%
+ \fi}
+
+\def \ztagdata #1\zmark#2\zmark#3\zmark#4{%
+ \ifcase #4 #1\or #2\or #3\fi} % Space after #4 is critical!
+
+\def \zuntag #1#2{% {tag}{what-to-set}
+ \writelog{ZzTeX reference: Undefined tag `#1'.}%
+ \zxwriteinfo{\false}{undef-tag}{#1}{}%
+ \global\increment \zuntagrefs
+ #2}
+
+% Determining the Page
+% ----------- --- ----
+
+
+% This command allows us to use the tag facility to determine which page
+% a particular element is on, in case the design of the element depends
+% on whether it is on a recto or verso.
+
+\def \whichpage #1#2{% {\count-reg}{tag-name}
+ \def \zreg {#1}%
+ \if \definedp{\=#2}%
+ \edef \zpg {\expandafterthrice\ztagdata \name{\=#2}\zmark0}%
+ \expandafter\zwhichpagea \zpg--\zmark
+ \else
+ \zuntag{#2}{\relax}%
+ #1=\pagenumber
+ \fi\relax}
+
+\def \zwhichpagea #1-#2-#3\zmark{%
+ \if \emptyargp{#2}%
+ \zwhichpageb #1\zmark
+ \else
+ \zwhichpageb #2\zmark
+ \fi}
+
+\def \zwhichpageb #1\zmark{%
+ \setbox \zboxa=\hbox{\zreg=0#1}%
+ \if \dimzerop{\wd\zboxa}%
+ \zreg=#1%
+ \else
+ \zreg=\pagenumber
+ \fi}
+
+% Tag Cross-Reference
+% --- ---------------
+
+
+% These counters keep track of the number of duplicate tags, and the
+% number of tags that have changed since the previous run.
+
+\definecount{\zduptags}{0}
+\definecount{\zchangedtags}{0}
+
+
+% Define the macro \=tag to contain the page, number, and title.
+% However, use of the title is controlled by \allowreftitle.
+
+\def \xreftag #1#2#3#4{% {page}{number}{title}{tag}
+ \ifnum \xrefmode=\xrefloadtagmode
+ \if \definedp{\=#4}\zduptag{#4}\fi
+ \xreftagdef{#1}{#2}{#3}{\=#4}%
+ \else\ifnum \xrefmode=\xrefcopymode
+ \xreftagchk{#1}{#2}{#3}{\=#4}%
+ \fi\fi}
+
+\def \xreftagdef #1#2#3#4{% {page}{number}{title}{\name}
+ \if \allowreftitle
+ \withname\gdef{#4}{#1\zmark#2\zmark#3}%
+ \else
+ \withname\gdef{#4}{#1\zmark#2\zmark}%
+ \fi}
+
+\def \xreftagchk #1#2#3#4{% {page}{number}{title}{\name}
+ \xreftagdef{#1}{#2}{#3}{\zxrefchk}%
+ \expandaftertwice\ifx \name{#4}\zxrefchk
+ \else
+ \global\increment \zchangedtags
+ \fi}
+
+\def \zduptag #1{% {tag}
+ \writelog{ZzTeX reference: Duplicate tag `#1'.}%
+ \global\increment \zduptags}
+
+% Tag Cross-Reference Summary
+% --- --------------- -------
+
+
+\def \ztagsummary {%
+ \if \posp{\zuntagrefs}%
+ \remark{Number of undefined tags in this run: \number\zuntagrefs.}%
+ \fi
+ \if \posp{\zduptags}%
+ \remark{Number of duplicate tags in this run: \number\zduptags._%
+ \space\space\space\space\space\space\space Eliminate duplicates %
+ and reprocess the book twice.}%
+ \fi
+ \if \posp{\zmistags}%
+ \remark{Number of misplaced tags in this run: \number\zmistags.}%
+ \fi
+ \if \posp{\zchangedtags}%
+ \remark{Number of tags changed since previous run: \number\zchangedtags._%
+ \space\space\space\space\space\space\space Reprocess the book %
+ to obtain correct cross-references.}%
+ \fi}
diff --git a/macros/plain/contrib/zztex/tex/zztex.tex b/macros/plain/contrib/zztex/tex/zztex.tex
new file mode 100644
index 0000000000..203affbfac
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztex.tex
@@ -0,0 +1,196 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Main Module
+%
+% Synopsis: This is the main module of ZzTeX. It sets up character
+% categories and loads all the other modules.
+%
+% Note: ZzTeX assumes the use of DVIPSONE, the PostScript DVI program
+% from Y&Y.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 27 March 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% If ZzTeX is already loaded, quit immediately.
+
+\ifx \ZzTeX\zzzundefinedzzz \else \message{... using format}\endinput \fi
+
+% Character Categories
+% --------- ----------
+
+
+% Character INITEX ZzTeX Notes
+%
+% NUL ignored invalid Ignored in Plain TeX.
+% TAB invalid Space in Plain TeX.
+% FORMFEED active: \par
+% RETURN end of line end of line
+% space space space
+% # parameter
+% $ math shift
+% & alignment tab
+% % comment comment
+% @ other active: command
+% letters letter letter
+% \ escape escape
+% ^ superscript
+% _ subscript
+% { begin group
+% } end group
+% ~ active: tie
+% DELETE invalid invalid
+% others other invalid
+
+
+\chardef \catescape = 0 % Escape character (\). %^catcode
+\chardef \catbegin = 1 % Begin group ({). %^catcode
+\chardef \catend = 2 % End group (}). %^catcode
+\chardef \catmath = 3 % Math mode ($). %^catcode
+\chardef \catalign = 4 % Alignment tab (&). %^catcode
+\chardef \catendofline = 5 % End of line. %^catcode
+\chardef \catparameter = 6 % Parameter (#). %^catcode
+\chardef \catsuperscript = 7 % Superscript (^). %^catcode
+\chardef \catsubscript = 8 % Subscript (_). %^catcode
+\chardef \catignored = 9 % Ignored character. %^catcode
+\chardef \catspace = 10 % Space. %^catcode
+\chardef \catletter = 11 % Letter. %^catcode
+\chardef \catother = 12 % Other. %^catcode
+\chardef \catactive = 13 % Active character (tilde). %^catcode
+\chardef \catcomment = 14 % Comment (percent). %^catcode
+\chardef \catinvalid = 15 % Invalid character. %^catcode
+\chardef \catcsname = 16
+
+\catcode`\^ = \catsuperscript
+\catcode`\^^@ = \catinvalid
+\catcode`\^^I = \catinvalid
+\catcode`\^^L = \catactive
+\catcode`\^^M = \catendofline
+\catcode`\ = \catspace
+\catcode`\# = \catparameter
+\catcode`\$ = \catmath
+\catcode`\& = \catalign
+\catcode`\% = \catcomment
+\catcode`\@ = \catactive
+\catcode`\\ = \catescape
+\catcode`\_ = \catsubscript
+\catcode`\{ = \catbegin
+\catcode`\} = \catend
+\catcode`\~ = \catactive
+\catcode`\^^? = \catinvalid
+
+% Characters "80--"FF are catcoded as invalid in zzmisc.
+
+\outer \def ^^L{\par}
+
+% Atsign Commands
+% ------ --------
+
+
+% At-sign commands are reserved for extended commands within blocks.
+% \defineatsigncommand makes a local definition!
+
+
+\def \defineatsigncommand @#1{% char args {body}
+ \withname\def{\zat#1}}
+
+\def @#1{% char
+ %%%\relax % Stops \omit search in an alignment cell.
+ \if \undefinedp{\zat#1}%
+ \error{undefat}{The atsign command `\string@#1' is not defined
+ in this block}%
+ \fi
+ \name{\zat#1}}
+
+% Markers
+% -------
+
+
+% This command does nothing, but it provides a name on which to
+% hang a comment for ZzExplore.
+
+\def \definemarker #1{% {marker-name}
+ }
+
+% Paragraph Programs
+% --------- --------
+
+
+% We maintain a list of little programs that must be executed
+% at the beginning of every paragraph. A program is declared
+% with `\declareeverypar'. The programs are executed with
+% `\requiredeverypar'.
+
+\def \everyparlist {}
+
+\def \declareeverypar #1{% {code}
+ \append{#1}{\everyparlist}}
+
+\def \requiredeverypar {%
+ \maplist{##1}{\everyparlist}}
+
+% Modules
+% -------
+
+
+\def \zremovePlaindef #1{%
+ \let #1= \relax}
+
+\input zzprog % Must be first.
+\input zzreg % Must be second.
+\input zzerror
+\input zzhelp
+\input zzio
+\input zzfont
+\input zzvmode
+\input zzhmode
+\input zzhmodeb
+\input zzhyph
+\input zzltrspc
+\input zzblock
+\input zzxref
+\input zzdoc
+\input zzdiv
+\input zzpage
+\input zzoverlay
+\input zzindexv1 % Must precede body files.
+\input zzsect
+\input zztext
+\input zztabbing
+\input zznote
+\input zzlist
+\input zztabularv3
+\input zzfloat
+\input zzart
+\input zztag
+\input zzmath
+\input zzfront
+\input zzps
+\input zzhyper
+\input zzmisc % Must be next to last.
+\input zzplain % Must be last.
+
+% Identification
+% --------------
+
+
+\def \TeX {T\kern-.1667em \lower .55ex \hbox{E}\kern-.1em X}
+\def \ZzTeX {Z\kern -.02em z\kern -.05em \TeX}
+
+\input zzver\relax
+
+\everyjob = {\messagenl{__Welcome to ZzTeX version \ZzTeXversion__}}
+
+\def \fmtname {ZzTeX}
+\edef \fmtversion {\ZzTeXversion}
+
+
+\messagenl{__Welcome to ZzTeX version \ZzTeXversion__}
+
+\if \orp{\hmodep}{\posp{\pagetotal}}
+ \zzerror{Spurious paragraph text appears in the ZzTeX files}%
+\fi
diff --git a/macros/plain/contrib/zztex/tex/zztext.tex b/macros/plain/contrib/zztex/tex/zztext.tex
new file mode 100644
index 0000000000..8e37133039
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztext.tex
@@ -0,0 +1,935 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX General Text Facilities
+%
+% Synopsis: This module contains definitions for blocks that are used to
+% format text.
+%
+% Notes: The tabbing facility was implemented by Richard A. Wells and
+% integrated into ZzTeX on 8/16/94.
+%
+% Authors: Paul C. Anagnostopoulos and Richard A. Wells
+% Created: 14 March 1990
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Text Block
+% ---- -----
+
+
+\defineblock{\text}{\endtext}{\false}{}
+\resetinvcontext{\text}
+
+%~block text Type, Level
+% \abovepenalty = integer % Penalty above text.
+% \aboveskip = glue % Space b/b above text.
+% \def \beginformat {...} % Beginning of text formatter.
+% \belowpenalty = integer % Penalty below text.
+% \belowskip = glue % Space b/b below text.
+% \bodyfont = {font} % Body font.
+% \def \calloutformat ##1{...} % Callout formatter.
+% \calloutnumber = integer % Number of first callout.
+% \def \callouttext {...} % Callout text or \arg.
+% \defaulttabwidth = dimen % Default repeating tab width.
+% \setflag \enabletabbing = flag % Enable tabbing commands.
+% \def \endformat {...} % End of text formatter.
+% \leftindent = glue % Left indentation.
+% \parindent = dimen % Paragraph indentation.
+% \parrag = dimen % Paragraph raggedness.
+% \parskip = glue % Paragraph skip.
+% \rightindent = glue % Right indentation.
+% \textcolor = {...} % Color of text.
+% \setflag \verbatimlines = flag % Treat line breaks verbatim.
+% \width = dimen % Line width.
+%~end
+
+\definecount{\calloutnumber}{0}
+\setflag \enabletabbing = \false
+\definedimen{\defaulttabwidth}{0pt}
+\setflag \verbatimlines = \false
+
+
+\def \text #1{% {type}
+ \beginblockscope{text}%
+ \global\increment \textdepth
+ \abovepenalty = \breakgood %~default hard
+ \def \beginformat {}% %~default soft
+ \belowpenalty = \breakgood %~default hard
+ \calloutnumber = 1 %~default with
+ \def \callouttext {\number\calloutnumber}% %~default soft
+ \defaulttabwidth = \mindimen %~default soft
+ \setflag \enabletabbing = \false %~default soft
+ \def \endformat {}% %~default soft
+ \textcolor = {}% %~default soft
+ \setflag \verbatimlines = \false %~default soft
+ \processdesign{\text}{#1\romannumeral\textdepth}%
+ \global\increment \textnumber
+ \textformat
+ \def \zarg {\arg}%
+ \if \tokeqlp{\callouttext}{\zarg}%
+ \defineatsigncommand @##{\ztextcoformat}%
+ \else
+ \defineatsigncommand @##{\ztextcoformat{\callouttext}}%
+ \fi
+ \if \emptytoksp{\textcolor}%
+ \bgroup
+ \else
+ \color{\the\textcolor}%
+ \fi
+ \if \enabletabbing \ztabinittabbing \fi
+ \if \verbatimlines \obeylines \fi
+ \if \enabletabbing \ztabstarttabbing \fi}
+
+\def \endtext {%
+ % Must really be \par, not \endgraf, because might be redefined
+ % for tabbing.
+ \if \notp{\verbatimlines}%
+ % In \verbatimlines the line preceding \endtext{...} will put
+ % out a final \par, but if not we have to do it here.
+ \par
+ \fi
+ \if \enabletabbing \ztabfinaltabbing \fi
+ \if \emptytoksp{\textcolor}%
+ \egroup
+ \else
+ \endcolor
+ \fi
+ \futurelet\nexttoken \zendtext}
+
+\def \zendtext {%
+ \endtextformat
+ \global\decrement \textdepth
+ \endblockscope{text}%
+ \parnext}
+
+\def \textformat {%
+ \endgraf
+ \the\bodyfont
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \alterindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \setparrag{\parrag}%
+ \beginformat}
+
+\def \endtextformat {%
+ \endformat
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}
+
+\def \ztextcoformat #1{% {text}
+ \calloutformat{#1}%
+ \global\increment \calloutnumber}
+
+% Tabbing Commands
+% ------- --------
+
+% These commands are available in a text block if \enabletabbing is turned on.
+
+
+% \ztabinitalizetabbing
+% - Redefines \par
+% - Defines the @ commands for tabbing. (The real work is done in the
+% in the \ztabcmd* macros, defined below.)
+% - Initializes variables
+
+\def \ztabinittabbing {%
+ % Redefine \par to ship out the tabbed line, \endgraf it and start a
+ % new tabbed line
+ \let \par = \ztabpar
+ % Define tabbing commands
+ \def \adjusttabbing ##1{\ztabadjusttabbing{##1}}%
+ \defineatsigncommand @.{\ztabcmdset}%
+ \defineatsigncommand @>{\ztabcmdforwards}%
+ \defineatsigncommand @+{\ztabcmdindent}%
+ \defineatsigncommand @-{\ztabcmdoutdent}%
+ \defineatsigncommand @D{\ztabcmddiscard}%
+ \defineatsigncommand @C{\ztabcmdclear}%
+ \defineatsigncommand @E##1{\ztabcmdevery{##1}}%
+ % Initialize variables
+ \if \verbatimlines
+ % The line with \text{...} will put out the first \par, so we
+ % want to skip it.
+ \ztabdiscardtrue
+ \else
+ \ztabdiscardfalse
+ \fi
+ \global\ztabindentlevel=0\relax
+ % Clear all tab stops
+ \ztabcmdclear}
+
+\def \ztabparfinishpreviousline {%
+ % Set state checked by \ztabendtabcell
+ \ztabatnltrue
+ % End last tab cell with \ztabnltrue
+ \ztabendtabcell
+ \egroup% closes inner group started below in \ztabmaketabbedline
+ \egroup% closes outer group started below in \ztabmaketabbedline
+ % Unless discarding, deposit the line and remove the last box
+ \if \notp{\ztabdiscardp}%
+ \unvbox\zboxa\lastbox
+ \else
+ % Clear discarding flag
+ \ztabdiscardfalse
+ \fi
+ \endgroup% closes outermost group started by \ztabmaketabbedline
+ % We should be back in vertical mode now.
+ %
+ % Reset \ztabsbox. The new value is the set of tbd boxes
+ % followed by the done boxes. If not all of the tbd boxes were
+ % used this should result in the same set of boxes as the
+ % previous value of \ztabsbox. However, if the tbd boxes were used up
+ % then the done boxes may contain additional boxes built on the fly.
+ \setbox\ztabsbox\hbox{\unhbox\ztabstbdbox\unhbox\ztabsdonebox}}
+
+\def \ztabparstartnextline {%
+ \ztabmaketabbedline}
+
+\def \ztabpar {% macro used instead of \par in tabbing
+ \ztabparfinishpreviousline
+ \endgraf
+ \ztabparstartnextline}
+
+\def \ztabstarttabbing {%
+ \ztabparstartnextline}
+
+\def \ztabfinaltabbing {%
+ % Discard and finish last tabbed line started by last \ztabpar
+ \ztabdiscardtrue
+ \ztabparfinishpreviousline}
+
+
+
+% Variables shared by \ztab* macros
+
+% Counts and dimens for building tab boxes
+\definecount{\ztabindentlevel}{0}
+\definecount{\ztabindentcounter}{0}
+\definedimen{\ztabcolwidth}{0pt}
+\definedimen{\ztabtabpos}{0pt}
+\definedimen{\ztabdimenii}{0pt}
+
+% Conditionals
+% atnlp: are we at a \nl in tab processing?
+\def \ztabatnlfalse {\global\setflag \ztabatnlp=\false}%
+\def \ztabatnltrue {\global\setflag \ztabatnlp=\true}%
+% discardp: are we discarding this line's output?
+\def \ztabdiscardfalse {\global\setflag \ztabdiscardp=\false}%
+\def \ztabdiscardtrue {\global\setflag \ztabdiscardp=\true}%
+% settingp: are we setting?
+\def \ztabsettingfalse {\global\setflag \ztabsettingp=\false}%
+\def \ztabsettingtrue {\global\setflag \ztabsettingp=\true}%
+% tabbingp: are we tabbing?
+\def \ztabtabbingfalse {\global\setflag \ztabtabbingp=\false}%
+\def \ztabtabbingtrue {\global\setflag \ztabtabbingp=\true}%
+
+
+% Boxes to hold the tabs
+\definebox{\ztabsbox}% hbox of hboxes for each tab column
+\definebox{\ztabstbdbox}% hbox of hbox tab columns still "to be done"
+\definebox{\ztabsdonebox}% hbox of hbox tab columns already done
+\definebox{\ztabsindentbox}% hbox of indents
+
+
+% The macros that implement the tabbing commands. \ztabcmd* are the
+% top-level macros called by the @ commands. Other \ztab* macros are
+% helpers.
+
+\def \ztabcmdset {%
+ % Set state checked by \ztabendtabcell
+ \ztabsettingtrue
+ % End the current cell with \ztabsettingtrue
+ \ztabendtabcell
+ % Start the next cell
+ \ztabbegintabcell\noindent\ignorespaces}%
+
+\def \ztabcmdforwards {%
+ % Set state checked by \ztabendtabcell
+ \ztabtabbingtrue
+ % End the current cell with \ztabsettingtrue
+ \ztabendtabcell
+ % Start the next cell
+ \ztabbegintabcell\noindent\ignorespaces}%
+
+\def \ztabcmdindent {\global\increment \ztabindentlevel\relax}%
+
+
+\def \ztabcmdoutdent {%
+ \global\decrement \ztabindentlevel\relax
+ \if \negp{\ztabindentlevel}%
+ \zzerror{Attempt to tab dedent (with \string@-) to left of left margin}%
+ \fi}
+
+\def \ztabcmddiscard {%
+ \ztabdiscardtrue}%
+
+\def \ztabcmdclear {% {boolean: initialization}
+ % First clear all boxes
+ \ztabcleartabboxes
+ % Surprise! Clearing tabs might actually set them, if \defaulttabwidth
+ % has been set in the design
+ \if \neqlp{\defaulttabwidth}{\mindimen}%
+ \ztabcmdevery{\defaulttabwidth}%
+ \else
+ % Must clear indent level since we've cleared all tabs (note that
+ % we intentionally leave indent level alone if there is a
+ % \defaulttabwidth!)
+ \global\ztabindentlevel=0\relax
+ \fi\ignorespaces}%
+
+\def \ztabcmdevery #1{%
+ % First clear all tabs
+ \ztabcleartabboxes
+ % Set new tab columns of the specified width into \ztabsbox
+ \ztabsettabs{#1}%
+ % Re-init the boxes used by \ztabmaketabbedline
+ \ztabinittabboxes{\true}% Flag indicates this is a re-init
+ \ignorespaces}
+
+
+% Implementation of the above commands
+
+
+\def \ztabinittabboxes #1{% Init the tab boxes {boolean: re-init}
+ % First copy \ztabsbox into \ztabstbdbox and clear \ztabsdonebox
+ \global\setbox\ztabstbdbox\copy\ztabsbox
+ \global\setbox\ztabsdonebox\null
+ % Put all of the indent boxes that might be built into an hbox
+ % which we will emit later, but just before processing cells
+ \global\setbox\ztabsindentbox\hbox%
+ \bgroup%
+ % Initialize counter for loop
+ \ztabindentcounter=0\relax
+ % Iterate \ztabindentlevel times, moving tabboxes from \ztabstbdbox to
+ % \ztabsdone, maybe emitting hboxes per indent
+ \if \lssp{\ztabindentcounter}{\ztabindentlevel}%
+ \loop
+ \increment \ztabindentcounter\relax% increment loop counter
+ % Pull \lastbox off of \ztabstbdbox
+ \global\setbox\ztabstbdbox\hbox{%
+ \unhbox\ztabstbdbox
+ \global\setbox\zboxb\lastbox}%
+ \ifvoid\zboxb
+ % This is a problem. Not allowed to indent past set tabs.
+ \zzerror{Attempt to tab indent (with \string@+, [\the\ztabindentlevel]) past set tabs}%
+ \else
+ % Nothing wrong with the box: push it on \ztabsdonebox
+ % and maybe emit it
+ \global\setbox\ztabsdonebox\hbox{\copy\zboxb\unhbox\ztabsdonebox}%
+ \if \notp{#1}% Not re-initializing
+ \box\zboxb
+ \fi
+ \fi
+ % Loop test
+ \if \lssp{\ztabindentcounter}{\ztabindentlevel}\repeat
+ \fi
+ % End hbox
+ \egroup}
+
+\def \ztabcleartabboxes {% Clear the tab boxes and indent level
+ \setbox\ztabsbox\null
+ \global\setbox\ztabstbdbox\null
+ \global\setbox\ztabsdonebox\null}
+
+\def \ztabsettabs #1{% Deposit tab stops of a specified width in \ztabsbox
+ \ztabcolwidth=#1\relax
+ \ztabtabpos=0pt\relax
+ % Loop while \ztabtabpos is less than \hsize, setting another tab
+ \loop
+ \ztabsetanother
+ \if \dimlssp{\ztabtabpos}{\hsize}\repeat}
+
+\def \ztabsetanother {% Helper for \ztabsettabs, immediately preceding
+ % Advance the counter
+ \advance \ztabtabpos by \ztabcolwidth
+ % Set another tab by "pushing" another hbox into the \ztabsbox hbox
+ % followed by its old set of hboxes
+ \setbox\ztabsbox\hbox{\hbox to\ztabcolwidth{}\unhbox\ztabsbox}}
+
+\def \ztabmaketabbedline {% Build a line of tabbed text
+ % Start outermost group that redefines \nl
+ \begingroup
+ % Inittab boxes (this also builds \ztabsindentbox)
+ \ztabinittabboxes{\false}% Flag indicates NOT a re-init
+ % \nl is a synonym for modified \par
+ \let\nl=\par
+ % \zboxa will contain the entire tabbed line in a vbox.
+ % (It is unvboxed in \nl and may be discarded if a @D is encountered.)
+ \setbox\zboxa\vbox%
+ % start outer group closed by \nl that holds state of \ztabatnlp
+ \bgroup%
+ % don't want to indent a tabbed line
+ \noindent
+ % Init conditionals
+ \ztabatnlfalse
+ \ztabsettingfalse
+ \ztabtabbingfalse
+ % start inner group closed by \nl that surrounds set of tabboxes
+ % and uses \zboxc as an hbox for the current cell.
+ \bgroup%
+ % emit indentation box
+ \box\ztabsindentbox
+ % start the first cell
+ \ztabbegintabcell}
+ % material for a cell will follow here and be ended by
+ % either a @ command or \nl, all of which will deposit
+ % \ztabendtabcell. The @ commands will begin another tab cell and
+ % \nl will also finish all of the groups started by
+ % \ztabmaketabbedline and put out the line.
+
+\def \ztabbegintabcell {%
+ % \zboxc contains an hbox as the current cell of tabbed material.
+ % (It is deposited at the end of \ztabendtabcell.)
+ \setbox\zboxc\hbox%
+ \bgroup% opens group closed in \ztabendtabcell
+ \ignorespaces}
+
+\def \ztabendtabcell {%
+ \if \ztabatnlp
+ % Processing last cell in this row. Close group opened in
+ % \ztabbegintabcell w/o bothering to re-set tabboxes.
+ \egroup
+ \else
+ % Close this cell's group (opened in \ztabbegintabcell) with \hss,
+ % since this is not the last cell.
+ \hss\egroup
+ % "Pop" current tabbox from \ztabstbdbox, measure it, deposit tabbed
+ % material into properly sized box and then "push" tabbox onto \ztabsdonebox
+ % "Pop" from the end of \ztabstbdbox using \lastbox into \zboxb
+ \global\setbox\ztabstbdbox\hbox{%
+ \unhbox\ztabstbdbox
+ \global\setbox\zboxb\lastbox}%
+ % Process the current tabbox
+ \ifvoid\zboxb
+ \if \ztabtabbingp
+ \zzerror{Attempt to tab (with \string@>) past set tabs}%
+ \else
+ % The current tabbox is void, so we set it to a box that is the
+ % natural width of \zboxc (which contains the cell material).
+ \global\setbox\zboxb\hbox to\wd\zboxc{}%
+ \fi
+ \else
+ \if \ztabsettingp
+ % Re-set previously stored tabbox to natural width of the cell (\zboxc)
+ \global\setbox\zboxb\hbox to\wd\zboxc{}%
+ \fi
+ % Re-deposit the cell material into \zboxc using the width of the
+ % current tabbox.
+ \setbox\zboxc\hbox to\wd\zboxb{\unhbox\zboxc}%
+ \fi
+ % "Push" the current tabbox measure onto the \ztabsdonebox set of boxes.
+ % (Note that this might have come from \ztabstbdbox or been measured from
+ % \zboxc if there were no more tabboxes, so this is where an "on-the-fly"
+ % tab is added to \ztabsdone, which will later be copied back into
+ % \ztabsbox for the next line.)
+ \global\setbox\ztabsdonebox\hbox{\box\zboxb\unhbox\ztabsdonebox}%
+ \fi
+ % Clear conditional variables
+ \ztabsettingfalse
+ \ztabtabbingfalse
+ % emit box for this cell
+ \box\zboxc}
+
+\def \ztabadjusttabbing #1{% {vertical-mode material}
+ % Close and discard currently open tabbed line (empty, but started
+ % by end of previous line).
+ \ztabcmddiscard
+ \ztabparfinishpreviousline
+ % Insert vertical material
+ #1\relax
+ % If in verbatimlines must set this line to be discarded by
+ % the newline which ends the \adjusttabbing{...} line, which will also
+ % start the next line.
+ \if \verbatimlines
+ \ztabdiscardtrue
+ \fi
+ % Start next tabbed line
+ \ztabparstartnextline}
+
+% Builtin Text Blocks
+% ------- ---- ------
+
+% The following text block formats text in a completely normal fashion.
+% It can be used with \with to make small changes to the text format.
+
+\def \textnormalidesign {%
+ \calculate \aboveskip = {\enclosingbaselineskip,+,\enclosingparskip}%
+ \belowskip = \aboveskip
+ \bodyfont = {}%
+ \leftindent = \enclosingleftss
+ \parindent = \enclosingparindent
+ \parrag = \enclosingparrag
+ \parskip = \enclosingparskip
+ \rightindent = \enclosingrightss
+ \setflag \verbatimlines = \false
+ \width = \naturalwidth}
+
+\def \textnormaliidesign {%
+ \textnormalidesign}
+\def \textnormaliiidesign {%
+ \textnormalidesign}
+\def \textnormalivdesign {%
+ \textnormalidesign}
+
+\def \setflushingleft {%
+ \leftindent = 0pt
+ \parfillskip = \normalparfillskip
+ \parindent = 0pt
+ \rightindent = 0pt
+ \width = \naturalwidth}
+
+
+% This text block centers text relative to the current left and right
+% indentation.
+
+\def \textcenteridesign {%
+ \textnormalidesign
+ \setcentering}
+
+\def \textcenteriidesign {%
+ \textcenteridesign}
+\def \textcenteriiidesign {%
+ \textcenteridesign}
+\def \textcenterivdesign {%
+ \textcenteridesign}
+
+\def \setcentering {%
+ \leftindent = \centerindent
+ \parfillskip = 0pt
+ \parindent = 0pt
+ \rightindent = \centerindent
+ \width = \naturalwidth}
+
+
+% This text block positions text flush right.
+
+\def \textflushrightidesign {%
+ \textnormalidesign
+ \setflushingright}
+
+\def \textflushrightiidesign {%
+ \textflushrightidesign}
+\def \textflushrightiiidesign {%
+ \textflushrightidesign}
+\def \textflushrightivdesign {%
+ \textflushrightidesign}
+
+\def \setflushingright {%
+ \leftindent = \centerindent
+ \parfillskip = 0pt
+ \parindent = 0pt
+ \rightindent = 0pt
+ \width = \naturalwidth}
+
+% This text block squares off the last line of paragraphs.
+
+\def \textflushendidesign {%
+ \textnormalidesign
+ \parfillskip = 0pt}
+
+\def \textflushendiidesign {%
+ \textflushendidesign}
+\def \textflushendiiidesign {%
+ \textflushendidesign}
+\def \textflushendivdesign {%
+ \textflushendidesign}
+
+\def \flushendpar {%
+ \zskipa = \parfillskip
+ \parfillskip = 0pt
+ \par
+ \parfillskip = \zskipa}
+
+% This text block sets text in the full type width.
+
+\def \texttypeareaidesign {%
+ \textnormalidesign
+ \leftindent = -\oddlefttextmargin
+ \width = \typeareawidth}
+
+\def \texttypeareaiidesign {%
+ \texttypeareaidesign}
+
+% This command centers a single line or sets multiple lines in block format.
+
+\def \centerorblockpar #1#2{% {width}{text}
+ \measuretextwidth{\tdimena}{#2}%
+ \if \dimlssp{\tdimena}{#1}%
+ \centerline{#2}%
+ \else
+ \noindent #2\par
+ \fi}
+
+% Code Block
+% ---- -----
+
+
+\defineblock{\code}{\endcode}{\false}{}
+
+%~block code Type
+% \abovepenalty = integer % Penalty above code.
+% \aboveskip = glue % Space b/b above code.
+% \setflag \allowbreaks = boolean % Page breaks allowed?
+% \setflag \allowatsigncommands = boolean % Allow at-sign commands.
+% \setflag \allowcallouttag = boolean % Allow \tag for callout numbers.
+% \setflag \allowTeXcommands = boolean % Allow commands with \ { }
+% \setflag \allowTeXmath = boolean % Allow math with $ _ ^
+% \setflag \autocallout = boolean % Automatically number lines?
+% \def \beginformat {...} % Beginning of code formatter.
+% \belowpenalty = integer % Penalty below code.
+% \belowskip = glue % Space b/b below code.
+% \bodyfont = {...} % Font for text.
+% \def \calloutformat ##1{...} % Callout formatter.
+% \calloutnumber = integer % Number of first callout.
+% \def \callouttext {...} % Callout text or \arg.
+% \codegapskip = glue % Standard code gap (see \codegap).
+% \def \endformat {...} % End of code formatter.
+% \hfuzz = dimen % Amount text can exceed \hsize.
+% \indentcolumns = integer % Standard indentation amount.
+% \leftindent = glue % Left indentation.
+% \metafont = {font} % Font for metasyntactic names.
+% \rightindent = glue % Right indentation.
+% \textcolor = {...} % Color of text.
+% \setflag \verbatimchars = flag % Take all characters verbatim?
+% \setflag \verbatimspaces = flag % Take all spaces verbatim?
+% \width = dimen % Width of code.
+%~end
+
+\defineskip{\codegapskip}{0pt}
+\definecount{\indentcolumns}{0}
+\definetoks{\metafont}
+
+\definecount{\codelinenumber}{0}
+
+\definecount{\zcodehyph}{0} % To remember hyphen character.
+
+\def \code #1{% {type}
+ \blockcantbein{\code}{\code}%
+ \beginblockscope{code}%
+ \global\increment \codedepth
+ \abovepenalty = \breakgood %~default hard
+ \setflag \allowatsigncommands = \false %~default soft
+ \setflag \allowcallouttag = \false %~default soft
+ \setflag \allowTeXcommands = \true %~default soft
+ \setflag \allowTeXmath = \false %~default soft
+ \setflag \autocallout = \false %~default soft
+ \def \beginformat {}% %~default soft
+ \belowpenalty = \breakbetter %~default hard
+ \calloutnumber = 1 %~default with
+ \def \callouttext {\number\calloutnumber}% %~default soft
+ \codegapskip = \mindimen %~default soft
+ \def \endformat {}% %~default soft
+ \indentcolumns = 3 %~default soft
+ \textcolor = {}% %~default soft
+ \setflag \verbatimchars = \true %~default soft
+ \setflag \verbatimspaces = \true %~default soft
+ \codelinenumber = 1\relax
+ \processdesign{\code}{#1}%
+ \global\increment \codenumber
+ \codeformat
+ \let \par = \zcodepar
+ \obeylines
+ \if \verbatimspaces \obeyspaces \fi
+ \let \zrealincl = \include
+ \let \include = \zcodeincl
+ \let \zrealfn = \footnote
+ \let \footnote = \zcodefn
+ \def \zarg {\arg}%
+ \if \tokeqlp{\callouttext}{\zarg}%
+ \def \!{\zcodecoformat}%
+ \else
+ \def \!{\zcodecoformat{\callouttext}}%
+ \fi
+ \settaginfo{}{}% % No tag information so far.
+ \if \notp{\emptytoksp{\textcolor}}\color{\the\textcolor}\fi
+ \begingroup % So we can undo the following things.
+ \if \autocallout \everyparagraph = {\!}\fi
+ \if \verbatimchars
+ \uncatcode{\allowTeXcommands}{\allowatsigncommands}{\allowTeXmath}
+ \fi
+ \zcodeflushline}
+
+{\catcode`\^^M = \catactive
+\gdef \zcodeflushline #1^^M{}%
+
+\gdef \endcode^^M{%
+%%% \columnbreak{\breakallowed}% % Allow break after last line.
+ \endgroup % Undo the \uncatcode,
+ \if \notp{\emptytoksp{\textcolor}}\endcolor \fi%
+ \futurelet\nexttoken \zendcode}% % and grab onto the next character.
+} % \catcode
+
+\def \zendcode {%
+ \hyphenchar\font = \zcodehyph
+ \setlist \zcodeadjlist = {}%
+ \endformat
+ \forcenextpenalty
+ \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}%
+ \global\decrement \codedepth
+ \endblockscope{code}%
+ \parnext}
+
+\def \codeformat {%
+ \endgraf
+ \alterindentation{\leftindent}{\rightindent}%
+ \settextwidth{\width}%
+ \setparrag{0pt}%
+ \the\bodyfont
+ \zcodehyph = \hyphenchar\font
+ \hyphenchar\font = -1
+ \parskip = 0pt \parindent = 0pt
+ \bbskipabove{\abovepenalty}{\aboveskip}
+ \beginformat}
+
+\def \zcodepar {%
+ \increment \codelinenumber
+ \if \hmodep
+ \endgraf
+ \if \notp{\allowbreaks}\nobreak \relax \fi
+ \zchkcodeadj
+ \else
+ \if \notp{\allowbreaks}\nobreak \relax \fi
+ \zchkcodeadj
+ \vskip \baselineskip
+ \fi}
+
+% This macro allows the compositor to noninvasively adjust pages between
+% lines of code.
+
+\setlist \zcodeadjlist = {}
+
+\long\def \codeadjustment #1#2{% {line-number}{commands}
+ \append{{#1}{#2}}{\zcodeadjlist}}
+
+\long\def \zchkcodeadj {%
+ \maplist{\zchkcodeadjb##1}{\zcodeadjlist}}
+
+\long\def \zchkcodeadjb #1#2{% {line-number}{commands}
+ \if \eqlp{#1}{\codelinenumber}%
+ #2\relax
+ \fi}
+
+\def \zcodecoformat #1{% {text}
+ \ensurepar
+ {\ztoksa = {}%
+ \zcodecocln #1\zmark
+ \calloutformat{\the\ztoksa}}%
+ \if \allowcallouttag \settaginfo{#1}{???}\fi
+ \global\increment \calloutnumber}
+
+\def \zcodecocln #1#2\zmark{%
+ \ifx #1\ \else \ztoksa = \expandafter{\the\ztoksa#1}\fi
+ \if \notp{\emptyargp{#2}}\zcodecocln #2\zmark \fi}
+
+% Code Tools
+% ---- -----
+
+
+%~ This command is used to place a math expression in a
+%~ code block that doesn't allow dollar signs.
+
+\def \codemath {% $math$ %^code
+ $%
+ \catcodemath
+ \let \znext = } % Discard opening $.
+
+%~ This command produces a vertical ellipsis in code,
+%~ with optional text explaining the omission.
+
+\def \codeellipsis #1{% {text} %^code
+ \ensurepar
+ {\lower .85\baselineskip \hbox{%
+ \vbox{\baselineskip = .5\baselineskip \lineskiplimit = 0pt
+ \kern \baselineskip \hbox{.}\hbox{.}\hbox{.}\kern \baselineskip}}%
+ \unbreakable\quad {\the\metafont #1}}}%
+
+{\catcode`\^^M = \catactive
+
+% The \include macro is redefined to use this version, which eats
+% the newline at the end of the line.
+
+\gdef \zcodeincl #1^^M{\zrealincl{#1}}%
+
+% The \footnote macro is redefined so that it turns off \obeylines.
+
+\gdef \zcodefn {%
+ \bgroup%
+ \let ^^M = \space%
+ \zcodefnb}%
+
+\gdef \zcodefnb #1{%
+ \zrealfn{#1}%
+ \egroup}%
+
+%~ This command allows a vertical adjustment between two lines
+%~ of code. A typical use would be
+%~ \adjustcode{\fullpagebreak}
+
+\gdef \adjustcode #1#2^^M{#1}% {command} %^code
+
+%~ Blank lines in code should be produced with this command.
+%~ A regular blank line produces too much space.
+
+\gdef \codegap #1^^M{% %^code
+ \if \dimnegp{\codegapskip}%
+ \vspace{\baselineskip}%
+ \else%
+ \vspace{\codegapskip}%
+ \fi}%
+
+} % \catcode
+
+% Code Fragment
+% ---- --------
+
+
+%~ A "code fragment" is a short sequence of program code in the running text.
+%~ Most books use |\mono|, which is defined in terms of this command.
+
+\def \codefragment #1#2#3#4{% {prefix}{suffix}{font}{text}
+ {#1%
+ \measurespacewidth{\tdimena}%
+ #3%
+ \if \monoencodingp \spaceskip = 1.2\tdimena \fi
+ \relax #4%
+ #2}}
+
+% Multicolumn Block
+% ----------- -----
+
+
+\defineblock{\multicolumn}{\endmulticolumn}{\false}{}
+
+%~block multicolumn Type
+% \abovepenalty = integer % Penalty above block.
+% \aboveskip = glue % Visual space above block.
+% \belowpenalty = integer % Penalty below block.
+% \belowskip = glue % Visual space below block.
+% \brokenpenalty = penalty % For hyphenation at bottom of column.
+% \columngutter = dimen % Width of column gutter.
+% \columnrulecolor = {color} % Color of rule separating columns.
+% \columnrulewidth = dimen % Width of rule.
+% \columns = integer % Number of columns.
+% \setflag \flushbottom = flag % Should bottoms be flush?
+% \leftindent = glue % Indentation for left edge.
+% \margins = {left,right,top,bottom} % Four margins.
+% \parrag = dimen % Paragraph raggedness.
+% \setflag \preservelistdepth = flag % Preserve list depth?
+% \siderulecolor = {color} % Color of rules on sides.
+% \siderulewidth = dimen % Width of rules.
+% \vshift = dimen % Vertical shift for entire element.
+% \width = dimen % Width of each column.
+%~end
+
+\definetoks{\columnrulecolor}
+\definedimen{\columnrulewidth}{0pt}
+\definecount{\columns}{0}
+\definetoks{\margins}
+\definetoks{\siderulecolor}
+\definedimen{\siderulewidth}{0pt}
+
+\definebox{\zmctext}
+\definecount{\zmccolumn}{0}
+\definecount{\zentrylistdepth}{0}
+\definebox{\zmccoli}
+\definebox{\zmccolii}
+\definebox{\zmccoliii}
+\definebox{\zmccoliv}
+\definebox{\zmccolv}
+\definebox{\zmccolvi}
+\definebox{\zmccolvii}
+\definebox{\zmccolviii}
+\definedimen{\zmcmaxht}{0pt}
+\definebox{\zmcbox}
+
+
+\def \multicolumn #1{% {type}
+ \beginblockscope{multicolumn}%
+ \global\increment \multicolumndepth
+ \abovepenalty = \breakgood %~default hard
+ \belowpenalty = \breakgood %~default hard
+ \brokenpenalty = \breaknever %~default soft
+ \setflag \preservelistdepth = \false %~default soft
+ \vshift = 0pt %~default soft
+ \processdesign{\multicolumn}{#1}%
+ \global\increment \multicolumnnumber
+ \expandafter\zmcparse \the\margins\zmark
+ \setbox \zmctext = \vtop\bgroup
+ \zentrylistdepth = \listdepth
+ \zpushvcontext
+ \if \preservelistdepth \global\listdepth = \zentrylistdepth \fi
+ \settextwidth{\width}%
+ \setparrag{\parrag}}
+
+\def \endmulticolumn {%
+ \endgraf
+ \zpopvcontext
+ \egroup % \vtop
+ \zbuildmc
+ \global\decrement \multicolumndepth
+ \endblockscope{multicolumn}}
+
+\def \zbuildmc {%
+ \splitmaxdepth = \dp\strutbox
+ \vbadness = 10000 % Do we want this?
+ \setbox \zmctext = \vbox{%
+ \vskip \splittopskip
+ \vskip -\ht\zmctext
+ \unvbox \zmctext
+ \unskip \unpenalty \unskip}%
+ \zbuildmca
+ \zbuildmcb
+ \bbskipabove{\abovepenalty}{\aboveskip}%
+ \hfuzz=999pc
+ \hindent{\leftindent} \lower \vshift \box\zmcbox \par
+ \prevdepth = 0pt % Nothing better to do.
+ \bbskipbelowblock{\belowpenalty}{\belowskip}}
+
+\def \zbuildmca {%
+ \zmccolumn = \columns
+ \zmcmaxht = 0pt
+ \loop
+ \calculate \tdimena =
+ {\ht\zmctext,-,\splittopskip,/,\zmccolumn,+,\splittopskip}%
+ \setbox \name{\zmccol\romannumeral\zmccolumn} =
+ \if \onep{\zmccolumn}\box\zmctext \else
+ \vsplit \zmctext to \tdimena \fi
+ \tdimena = \ht\name{\zmccol\romannumeral\zmccolumn}%
+ \if \dimgtrp{\tdimena}{\zmcmaxht}\zmcmaxht = \tdimena \fi
+ \decrement \zmccolumn
+ \if \posp{\zmccolumn}\repeat}
+
+\def \zbuildmcb {%
+ \setbox \zmcbox = \hbox{%
+ \vrule width \siderulewidth
+ \hskip -\siderulewidth
+ \hskip \zmcleft
+ \zmccolumn = \columns
+ \loop
+ \tdimena = \dp\name{\zmccol\romannumeral\zmccolumn}%
+ \setbox \zboxa = \vbox to \zmcmaxht {%
+ \unvbox \name{\zmccol\romannumeral\zmccolumn}%
+ \if \notp{\flushbottom}\vfil \fi
+ \vskip -\tdimena
+ \vskip \zmcbottom}%
+ \calculate \tdimena = {\ht\zboxa,-,\splittopskip}%
+ \lower \tdimena \hbox{\box\zboxa}%
+ \if \gtrp{\zmccolumn}{1}%
+ \hskip .5\columngutter
+ \hskip -.5\columnrulewidth
+ \vrule width \columnrulewidth
+ \hskip -.5\columnrulewidth
+ \hskip .5\columngutter
+ \fi
+ \decrement \zmccolumn
+ \if \posp{\zmccolumn}\repeat
+ \hskip \zmcright
+ \hskip -\siderulewidth
+ \vrule width \siderulewidth}}
+
+\def \zmcparse #1,#2,#3,#4\zmark{%
+ \def \zmcleft {#1\relax}%
+ \def \zmcright {#2\relax}%
+ \splittopskip = #3\relax
+ \def \zmcbottom {#4\relax}}
diff --git a/macros/plain/contrib/zztex/tex/zzttladj.tex b/macros/plain/contrib/zztex/tex/zzttladj.tex
new file mode 100644
index 0000000000..d23439bfe3
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzttladj.tex
@@ -0,0 +1,78 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX New Title Adjustment Scheme
+%
+% Synopsis: The new title adjustment scheme is an improvement over the
+% original scheme provided by \adjusttitle.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 9 July 1997
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Title Adjustment Commands
+% ----- ---------- --------
+
+
+%~ This command provides an adjustment to the enclosing title
+%~ when it appears in the body of the book. The argument text
+%~ is included only when the title appears in the body.
+
+\def \adjustbodytitle #1{% {text} %^title_adj
+ \if \eqlp{\zadjtitle}{\zadjtitlebody}#1\fi}
+
+%~ This command provides an adjustment to the enclosing title
+%~ when it appears in a running head or foot. The argument text
+%~ is included only when the title appears in a runner.
+
+\def \adjustmarktitle #1{% {text} %^title_adj
+ \if \eqlp{\zadjtitle}{\zadjtitlemark}#1\fi}
+
+%~ This command provides an adjustment to the enclosing title
+%~ when it appears in the table of contents. The argument text
+%~ is included only when the title appears in the ToC.
+
+\def \adjusttoctitle #1{% {text} %^title_adj
+ \if \eqlp{\zadjtitle}{\zadjtitletoc}#1\fi}
+
+%~ This command provides an adjustment to the enclosing title
+%~ when it appears in a mini-Toc. The argument text
+%~ is included only when the title appears in a mini-ToC.
+
+\def \adjustminitoctitle #1{% {text} %^title_adj
+ \if \eqlp{\zadjtitle}{\zadjtitleminitoc}#1\fi}
+
+\def \adjusttitle {%
+ \error{obsolete}{The \noexpand\adjusttitle command is obsolete}}
+
+% Common Adjustment Commands
+% ------ ---------- --------
+
+
+%~ This command is equivalent to |\adjustbodytitle{\nl}|.
+
+\def \titlenl;{\adjustbodytitle{\nl}} %^title_adj
+
+%~ This command is equivalent to |\adjustbodytitle{\tl}|.
+
+\def \titletl;{\adjustbodytitle{\tl}} %^title_adj
+
+%~ This command is equivalent to |\adjusttoctitle{\nl}|.
+
+\def \tocnl;{\adjusttoctitle{\nl}} %^title_adj
+
+%~ This command is equivalent to |\adjusttoctitle{\tl}|.
+
+\def \toctl;{\adjusttoctitle{\tl}} %^title_adj
+
+%~ This command is equivalent to |\adjustminitoctitle{\nl}|.
+
+\def \minitocnl;{\adjustminitoctitle{\nl}} %^title_adj
+
+%~ This command is equivalent to |\adjustminitoctitle{\tl}|.
+
+\def \minitoctl;{\adjustminitoctitle{\tl}} %^title_adj
+
diff --git a/macros/plain/contrib/zztex/tex/zztures.tex b/macros/plain/contrib/zztex/tex/zztures.tex
new file mode 100644
index 0000000000..60f86eb367
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zztures.tex
@@ -0,0 +1,24 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX TeXtures Interface
+%
+% Synopsis: This module provides replacement definitions for things
+% that are different in TeXtures.
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 17 March 1994
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Unencodable Characters
+% ----------- ----------
+
+
+\def \PSbackslash {$\backslash$}
+\def \PSbar {$\vert$}
+\def \PSbullet {$\bullet$}
+\def \PSdollar {\char "24}
+\def \PSunderscore {\kern .06em \vbox{\hrule width .3em}}
diff --git a/macros/plain/contrib/zztex/tex/zzver.tex b/macros/plain/contrib/zztex/tex/zzver.tex
new file mode 100644
index 0000000000..7b3fd2bfa2
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzver.tex
@@ -0,0 +1 @@
+\def \ZzTeXversion {17.7}
diff --git a/macros/plain/contrib/zztex/tex/zzvmode.tex b/macros/plain/contrib/zztex/tex/zzvmode.tex
new file mode 100644
index 0000000000..a81b33d2bd
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzvmode.tex
@@ -0,0 +1,380 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Vertical Mode Facilities
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 21 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Interline Skip
+% --------- ----
+
+
+\def \nointerlineskip {%
+ \prevdepth = -1000pt}
+
+\def \offinterlineskip {%
+ \baselineskip = -1000pt
+ \lineskip = 0pt
+ \lineskiplimit = \maxdimen}
+
+% Vertical Skiping Environment
+% -------- ------- -----------
+
+
+% The following registers make up the vertical skiping environment.
+
+\definecount{\zvskenvtype}{0} % Previous vertical skip type.
+\definecount{\zvskenvpen}{0} % Previous columnbreak penalty.
+\defineskip{\zvskenvreq}{0pt} % Previous required base-to-base skip.
+\defineskip{\zvskenvskip}{0pt} % Previous actual skip amount.
+
+\chardef \zvskenvdiscard = 0 % Just initialized the environment.
+\chardef \zvskenvpar = 1 % Previous element was a paragraph.
+\chardef \zvskenvabove = 2 % Just finished an above skip.
+\chardef \zvskenvbelow = 3 % Just finished a below skip.
+\chardef \zvskenvmath = 4 % Previous element was a paragraph ending
+ % with a math display.
+
+\definecount{\zvskenvnopen}{20000\relax}
+
+\let \noskip = \mindimen
+
+
+% The vertical skiping environment is maintained in the vertical context.
+
+\zdeclareeveryvcontext{\zvskenvvcontext}
+
+\def \zvskenvvcontext {%
+ \zsavevcontext{\zvskenvtype=\the\zvskenvtype
+ \zvskenvpen=\the\zvskenvpen
+ \zvskenvreq=\the\zvskenvreq
+ \zvskenvskip=\the\zvskenvskip}%
+ \zvskpar
+ \global\zvskenvtype = \zvskenvdiscard}
+
+% Base-to-Base Skiping
+% ------------ -------
+
+
+\declareeverypar{\zvskpar}
+
+\def \zvskpar {%
+ \global\zvskenvtype = \zvskenvpar
+ \global\zvskenvpen = \zvskenvnopen
+ \global\zvskenvreq = \parskip \global\advance \zvskenvreq by \baselineskip
+ \global\zvskenvskip = 0pt}
+
+
+%~ This command produces vertical space so that the base-to-base
+%~ distance above the next element is equal to the *glue*. The
+%~ space is preceded by the specified *penalty*. If there is a font
+%~ change for the next element, it must be specified before this command.
+
+\def \bbskipabove #1#2{% {penalty}{glue} %^vspace
+ \if \neqlp{\zvskenvtype}{\zvskenvdiscard}%
+ {\zvskprevmath{\parskip}{\baselineskip}%
+ \zparseglue #2\zmark
+ \setflag \znosk = {\dimeqlp{\zskipa}{\noskip}}%
+ \vpenalty{#1}%
+ \ifcase \zvskenvtype
+ \relax
+ \or
+ \if \znosk \zskipa = \zvskenvreq \fi
+ \or
+ \zskipa = \zvskenvreq
+ \or
+ \if \dimlssp{\zskipa}{\zvskenvreq}\zskipa = \zvskenvreq \fi
+ \or
+ \if \dimlssp{\zskipa}{\zvskenvreq}\zskipa = \zvskenvreq \fi
+ \fi
+ \if \notp{\dimzerop{\zvskenvskip}}\vskip -\zvskenvskip \fi
+ \zskipb = \zskipa
+ \advance \zskipb by -\parskip
+ \advance \zskipb by -\baselineskip
+ \vskip \zskipb
+ \if \notp{\znosk}%
+ \global\zvskenvtype = \zvskenvabove
+ \global\zvskenvreq = \zskipa
+ \fi
+ \global\zvskenvskip = \zskipb}%
+ \fi}
+
+%~ This command produces vertical space so that the base-to-base
+%~ distance below the current element is equal to the *glue*. The
+%~ space is preceded by the specified *penalty*.
+
+\def \bbskipbelow #1#2{% {penalty}{glue} %^vspace
+ \zvskbelow{#1}{#2}{\parskip}{\baselineskip}}
+
+\def \bbskipbelowblock #1#2{% {penalty}{glue}
+ \zvskbelow{#1}{#2}{\enclosingparskip}{\enclosingbaselineskip}}
+
+% This macro "returns" a value in \parnext:
+% \noindent if next token does not start a new paragraph.
+% empty if next token starts a new paragraph.
+
+\def \bbskipbelowblockpar #1#2#3{% {token}{penalty}{glue}
+ {\setflag \znext = \false % Set \true if token starts new paragraph.
+ \ifcat \noexpand#1\relax \setflag \znext = \true \fi
+ \ifcat \noexpand#1\endgraf \setflag \znext = \true \fi
+ \ifcat \noexpand#1\egroup \setflag \znext = \true \fi
+ \ifcat \noexpand#1&\setflag \znext = \true \fi
+ \ifx #1\noindent \setflag \znext = \false \fi
+ \xdef \parnext {\if \znext \else \noindent \fi}%
+ \zskipa = #3\relax
+ \if \andp{\znext}{\dimneqlp{#3}{\noskip}}%
+ \tdimena = \zskipa
+ \advance \zskipa by -\tdimena
+ \advance \zskipa by \enclosingparskip
+ \advance \zskipa by \enclosingbaselineskip
+ \if \dimlssp{\zskipa}{#3}\zskipa = #3\fi
+ \fi
+ \zvskbelow{#2}{\zskipa}{\enclosingparskip}{\enclosingbaselineskip}}}
+
+\def \zvskbelow #1#2#3#4{% {penalty}{glue}{parskip}{baselineskip}
+ {\zvskprevmath{#3}{#4}%
+ \zparseglue #2\zmark
+ \setflag \znosk = {\dimeqlp{\zskipa}{\noskip}}%
+ \vpenalty{#1}%
+ \ifcase \zvskenvtype
+ \zzerror{Skiping type is discard}%
+ \or
+ \if \znosk \zskipa = #3 \advance \zskipa by #4\fi
+ \or
+ \error{skipab}{A `skip below' follows a `skip above'}%
+ \or
+ \if \znosk \zskipa = \zvskenvreq \fi
+ \or
+ \if \dimlssp{\zskipa}{\zvskenvreq}\zskipa = \zvskenvreq \fi
+ \fi
+ \if \notp{\dimzerop{\zvskenvskip}}\vskip -\zvskenvskip \fi
+ \zskipb = \zskipa
+ \advance \zskipb by -#3%
+ \advance \zskipb by -#4%
+ \vskip \zskipb
+ \if \notp{\znosk}%
+ \if \neqlp{\zvskenvtype}{\zvskenvmath}% % Stay as math type so
+ \global\zvskenvtype = \zvskenvbelow % subsequent below skip
+ \fi % won't override.
+ \global\zvskenvreq = \zskipa
+ \fi
+ \global\zvskenvskip = \zskipb}}
+
+\def \zvskprevmath #1#2{% {parskip}{baselineskip}
+ \if \eqlp{\mathdisplayprevgraf}{\prevgraf}%
+ \global\zvskenvtype = \zvskenvmath
+ \global\zvskenvpen = \mathdisplayprevpenalty
+ \global\zvskenvreq = \mathdisplayprevskip
+ \global\advance \zvskenvreq by #1
+ \global\advance \zvskenvreq by #2
+ \global\zvskenvskip = \mathdisplayprevskip
+ \global\mathdisplayprevgraf = -1\relax
+ \fi}
+
+%~ This command forces the next base-to-base skip command
+%~ regardless of the relationship between the previous element
+%~ and the next one.
+
+\def \forcenextbbskip {% %^vspace
+ \global\zvskenvtype = \zvskenvpar
+ \global\mathdisplayprevgraf = -1\relax}
+
+\definecount{\zvpen}{0}
+
+\def \vpenalty #1{% {penalty}
+ \zvpen = \if \emptyargp{#1}\breaknever \else #1\fi
+ \if \orp{\eqlp{\zvskenvpen}{\zvskenvnopen}}
+ {\eqlp{\zvpen}{\breaknever}}%
+ \columnbreak{\zvpen}%
+ \global\zvskenvpen = \zvpen\relax
+ \else \if \andp{\posp{\zvskenvpen}}{\gtrp{\zvpen}{\zvskenvpen}}%
+ \columnbreak{\zvpen}%
+ \global\zvskenvpen = \zvpen\relax
+ \fi\fi}
+
+\def \forcenextpenalty {%
+ \global\zvskenvpen = \zvskenvnopen}
+
+\def \repeatpenalty {%
+ \if \neqlp{\zvskenvpen}{\zvskenvnopen}%
+ \columnbreak{\zvskenvpen}%
+ \fi}
+
+%~ This command inserts the specified amount of extra vertical space
+%~ between the previous element and the next one.
+
+\def \vspace #1{% {glue} %^vspace
+ \if \neqlp{\zvskenvtype}{\zvskenvdiscard}%
+ \zparseglue #1\zmark
+ \vskip \zskipa
+ \fi}
+
+%~ This command inserts extra vertical space between the previous element
+%~ and the next one. The space is measured in lines; a fractional number
+%~ is allowed.
+
+\def \linespace #1{\vspace{#1\baselineskip}}% {lines} %^vspace
+
+\def \zparseglue #1#2\zmark{% {token}{tokens...}
+ \def \znext {#1}%
+ \def \zskip {\skip}%
+ \if \tokeqlp{\znext}{\zskip}%
+ \setskip \zskipa = #2\relax
+ \else
+ \zskipa = #1#2\relax
+ \fi}
+
+% Top to Text Skipping
+% --- -- ---- --------
+
+
+% These commands use \zskipb so as not to screw up \fakepar.
+
+\def \vsinkfromtypearea #1{% {sinkage}
+ \endgraf
+ \nobreak % So \fakepar can't break.
+ \fakepar % So \bbskipabove won't discard.
+ \vbox{}% % Force start of page if not already.
+ \kern -\pagetotal
+ \kern -\headerheight
+ \bbskipabove{\breaknever}{#1}}
+
+\let \vsink = \vsinkfromtypearea
+
+\def \vsinkfromtrim #1{% {sinkage}
+ \zskipb = #1\relax
+ \advance \zskipb by -\headmargin
+ \vsinkfromtypearea{\zskipb}}
+
+\def \vsinkfromtextarea #1{% {sinkage}
+ \zskipb = #1\relax
+ \advance \zskipb by \headerheight
+ \if \topdeltaadjustment
+ \advance \zskipb by \topdelta
+ \fi
+ \vsinkfromtypearea{\zskipb}}
+
+% Rules
+% -----
+
+
+\def \parrule #1#2{% {shift}{dimensions}
+ \endgraf
+ {\if \notp{\baselinetoprules}\zadjrule{#2}\fi
+ \hfuzz = 100pc
+ \noindent \hspace{#1}\vbox{\hrule height 0pt depth 0pt #2}\endgraf}}
+
+\def \colorparrule #1#2#3{% {color}{shift}{dimensions}
+ \endgraf
+ {\if \notp{\baselinetoprules}\zadjrule{#3}\fi
+ \hfuzz = 100pc
+ \noindent \hspace{#2}%
+ \color{#1}\vbox{\hrule height 0pt depth 0pt #3}\endcolor \endgraf}}
+
+\def \scotchrule #1#2#3{% {shift}{width}{height,gap,...}
+ \endgraf
+ {\hfuzz = 100pc
+ \commalist{\zscotchlist}{#3}%
+ \tcounta = 1\relax
+ \maplist{\zscotchb{#1}{#2}{##1}}{\zscotchlist}}}
+
+\def \zscotchb #1#2#3{% {shift}{width}{dimension}
+ \if \andp{\eqlp{\tcounta}{1}}{\notp{\baselinetoprules}}%
+ \zadjrule{height #3 depth 0pt}%
+ \fi
+ \if \oddp{\tcounta}
+ \noindent \hspace{#1}\vbox{\hrule height #3 depth 0pt width #2}\endgraf
+ \parskip = 0pt
+ \else
+ \nobreak
+ \vspace{#3}%
+ \nointerlineskip
+ \fi
+ \increment \tcounta}
+
+\def \zadjrule #1{% {dimensions}
+ \if \notp{\innermodep}%
+ \fakepar
+ \tdimena = \baselineskip
+ \advance \tdimena by -\prevdepth
+ \setbox \zboxa = \hbox{\vrule #1}%
+ \advance \tdimena by -\ht\zboxa
+ \vskip \tdimena
+ \vskip \topskip
+ \rule{height 0pt depth 0pt width 0pt}%
+ \penalty \breaknever
+ \vskip -\topskip
+ \parskip = 0pt \baselineskip = \ht\zboxa
+ \fi}
+
+% Vertical Alignment
+% -------- ---------
+
+
+\def \bottomout {%
+ \hrule width 0pt height 0pt % Make sure \vskip isn't discarded.
+ \vskip 0pt plus 1filll}
+
+% Counting Lines
+% -------- -----
+
+
+\definecount{\zlinect}{0}
+
+
+\def \countlines #1#2#3#4{% {\count}{width}{font}{text}
+ \setbox\zboxa = \vbox{%
+ \hsize = #2%
+ #3%
+ #4\par}%
+ \global\zlinect = 0
+ \setbox\zboxa = \vbox{\unvbox\zboxa \zscanvbox}%
+ #1=\zlinect}
+
+\def \zscanvbox {%
+ \loop
+ \setflag \zscanagain = \false
+ \setbox\zboxa = \lastbox
+ \if \hboxp{\zboxa}%
+ \global\increment \zlinect
+ \setflag \zscanagain = \true
+ \else\if \notp{\dimzerop{\lastskip}}%
+ \unskip
+ \setflag \zscanagain = \true
+ \else\if \notp{\dimzerop{\lastkern}}%
+ \unkern
+ \setflag \zscanagain = \true
+ \else\if \notp{\zerop{\lastpenalty}}%
+ \unpenalty
+ \setflag \zscanagain = \true
+ \fi\fi\fi\fi
+ \if \zscanagain \repeat}
+
+% Special Boxes
+% ------- -----
+
+
+\definedimen{\zibprevdepth}{0pt}
+
+
+\long\def \interjectbox #1#2{% {right-shift}{content}
+ {\zibprevdepth = \prevdepth
+ \penalty \breaknever
+ \nointerlineskip
+ \moveright #1 \vbox to 0pt{%
+ \zpushvcontext
+ #1\relax
+ \zpopvcontext}%
+ \prevdepth = \zibprevdepth}}
+
+\long\def \smashbox #1{%
+ \vbox to 0pt{%
+ #1\relax
+ \vss}} \ No newline at end of file
diff --git a/macros/plain/contrib/zztex/tex/zzxref.tex b/macros/plain/contrib/zztex/tex/zzxref.tex
new file mode 100644
index 0000000000..a0771f3910
--- /dev/null
+++ b/macros/plain/contrib/zztex/tex/zzxref.tex
@@ -0,0 +1,245 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Module: ZzTeX Cross-Referencing Facilities
+%
+% Synopsis:
+%
+% Author: Paul C. Anagnostopoulos
+% Created: 19 September 1989
+%
+% Copyright 1989--2020 by Paul C. Anagnostopoulos
+% under The MIT License (opensource.org/licenses/MIT)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Data Structures
+% ---- ----------
+
+
+\definewrite{\zxrootfile}
+
+\definewrite{\zxdivfile}
+\setflag \zxdivopen = \false
+
+\definewrite{\zxcompfile}
+\setflag \zxcompavail = \false
+
+\chardef \xrefbadmode = 0 % Invalid mode.
+\chardef \xrefrunmode = 1 % Normal running environment.
+\chardef \xrefsnapmode = 2 % Taking a division snapshot.
+\chardef \xrefcopymode = 3 % Copying cross-reference files.
+\chardef \xrefloadmodes = 4 % Beginning of load modes:
+\chardef \xrefloadtagmode = 5 % Load tag definitions.
+\chardef \xrefloadtocmode = 6 % Load table of contents.
+\chardef \xrefloadauxmode = 7 % Create BibTeX auxiliary file.
+\chardef \xrefloadendmode = 8 % Load endnotes.
+\chardef \xrefloadcitemode = 9 % Load citation folios.
+
+\let \xrefmode = \xrefbadmode % Default mode.
+
+% Comment Lines
+% ------- -----
+
+
+{\catcode`\%=\catother
+\gdef \zcomment {%\space}
+} % \catcode
+
+
+\def \zxwritecomment #1#2#3{% {file}{keyword}{values}
+ \immediate\write #1 {\zcomment #2: #3}}
+
+% Initialization
+% --------------
+
+
+\def \zxrefinit {%
+ \zxcompinit
+ \zxopenroot
+ \let \xrefmode = \xrefrunmode}
+
+\def \zxcompinit {%
+ \checkfile{\zxcompavail}{\jobname.zzc}%
+ \if \zxcompavail
+ \zxloadcomp{\xrefloadtagmode}%
+ \else
+ \checkfile{\zxcompavail}{\jobname.zzx}%
+ \if \zxcompavail
+ \zxgencomp
+ \zxloadcomp{\xrefloadtagmode}%
+ \else
+ \remark{There is no cross-reference file available for this run.}%
+ \fi
+ \fi}
+
+\def \zxopenroot {%
+ \immediate\openout \zxrootfile = \jobname.zzx\relax
+ \zxwritecomment{\zxrootfile}{root}{\jobname}}
+
+% Division Handling
+% -------- --------
+
+
+\def \zxdivinit #1#2{% {division-name}{setting-it?}
+ \immediate\write \zxrootfile {\noexpand\zinputzzx{#1}}%
+ \if #2%
+ \immediate\openout \zxdivfile = #1.zzx\relax
+ \global\setflag \zxdivopen = \true
+ \zxwritecomment{\zxdivfile}{division}{#1}%
+ \immediate\write \zxdivfile
+ {\noexpand\xref{div}{}{}{}{\the\divisionname}\zcomment}%
+ \fi}
+
+% There is nothing to do with each entry in the cross-reference file.
+
+\def \xrefdiv #1#2#3#4{}
+
+
+\def \zxdivfinal #1{%
+ \if \zxdivopen
+ \ztakesnap
+ \zxwritecomment{\zxdivfile}{end}{#1}%
+ \immediate\closeout \zxdivfile
+ \global\setflag \zxdivopen = \false
+ \fi}
+
+% Finalization
+% ------------
+
+
+\def \zxreffinal {%
+ \zxwritecomment{\zxrootfile}{end}{\jobname}%
+ \immediate\closeout \zxrootfile
+ \zxgencomp}
+
+% Generate Composite File
+% -------- --------- ----
+
+
+\def \zxgencomp {%
+ \remark{Generating composite cross-reference file:}%
+ \immediate\openout \zxcompfile = \jobname.zzc\relax
+ \zxwriteinfo{\true}{jobname}{\jobname}{}%
+ \zxwriteinfo{\true}{time}{\number\year.\number\month.\number\day}{\formattime}%
+ \zxwriteinfo{\true}{version}{\ZzTeXversion}{}%
+ \zxwriteinfo{\true}{author}{\bookauthor}{}%
+ \zxwriteinfo{\true}{title}{\booktitle}{}%
+ \zxwriteinfo{\true}{publisher}{\bookpublisher}{}%
+ \zxwriteinfo{\true}{ISBN}{\bookISBN}{}%
+ \zxwriteinfo{\true}{art-root}{\zartroot}{}%
+ \zxwriteinfo{\true}{place-art}{\zplaceart}{}%
+ \zxwriteinfo{\true}{PDF-hyperlinks}{\PDFhyperlinks}{}%
+ \zxwriteinfo{\true}{proof}{\the\zproofid}{}%
+ \zxwriteinfo{\true}{compositor}{\ininame}{\iniorganization}%
+ \zxwriteinfo{\true}{trim}{\the\trimwidth}{\the\trimheight}%
+ \zxwriteinfo{\true}{head-margin}{\the\headmargin}{}%
+ \zxwriteinfo{\true}{inner-margin}{\the\eveninnermargin}{\the\oddinnermargin}%
+ \let \zxmodesave = \xrefmode
+ \let \xrefmode = \xrefcopymode
+ \input \jobname.zzx\relax
+ \let \xrefmode = \zxmodesave
+ \zxwritecomment{\zxcompfile}{end}{\jobname}%
+ \immediate\closeout \zxcompfile}
+
+% This macro writes an information entry in the composite cross-reference
+% file.
+
+\def \zxwriteinfo #1#2#3#4{% {composite?}{key}{value1}{value2}
+ \if #1%
+ \immediate\write \zxcompfile {\noexpand\xref{info}{}{#2}{#3}{#4}\zcomment}%
+ \else
+ \zbeginhidewrite
+ \edef \znext {\noexpand\xref{info}{\noexpand\folio}%
+ {#2}%
+ {#3}
+ {#4}}%
+ \znext
+ \zendhidewrite
+ \fi}
+
+%%% \immediate\write #1{\noexpand\xref{info}{#2}{#3}{#4}{\noexpand\folio}\zcomment}}
+
+% There is nothing to do when info entries are executed.
+
+\def \xrefinfo #1#2#3#4{}
+
+% This macro is used in the root cross-reference file to suck in the
+% division cross-reference files.
+
+\def \zinputzzx #1{%
+ \checkfile{\znext}{#1.zzx}%
+ \if \znext \input #1.zzx \fi}
+
+% Load Composite File
+% ---- --------- ----
+
+
+\def \zxloadcomp #1{% {xref-mode}
+ \if \zxcompavail
+ \let \zxmodesave = \xrefmode
+ \let \xrefmode =#1%
+ \input \jobname.zzc\relax
+ \let \xrefmode = \zxmodesave
+ \fi}
+
+\def \zxloadothercomp #1#2{% {file}{xref-mode}
+ \let \zxmodesave = \xrefmode
+ \let \xrefmode = #2%
+ \input #1\relax
+ \let \xrefmode = \zxmodesave}
+
+\def \loadrelatedxref #1{% {file}
+ \zxloadothercomp{#1}{\xrefloadtagmode}}
+
+% Cross-Reference Macro
+% --------------- -----
+
+
+% Here's how the arguments are treated in each of the modes:
+%
+% Mode type page arg3 title arg5
+%
+% load expanded --- passed to appropriate \xrefxxx macro ---
+% copy expanded expanded expanded unexpanded expanded
+% run expanded unexpanded expanded unexpanded expanded
+% snap expanded expanded expanded expanded expanded
+
+% This macro is written for speed.
+
+\long\def \xref #1#2#3#4#5{% {type}{page-number}{arg3}{title}{arg5}
+ \ifnum \xrefmode>\xrefloadmodes
+ \name{\xref#1}{#2}{#3}{#4}{#5}%
+ \else\ifnum \xrefmode=\xrefcopymode
+ {\def \zxtitle {#4}%
+ \immediate\write \zxcompfile {\noexpand\xref{#1}{#2}{#3}%
+ {\expandafter\zdefof \meaning\zxtitle\zmark}{#5}\zcomment}}%
+ \name{\xref#1}{#2}{#3}{#4}{#5}% In case they want to do something.
+ \else\ifnum \xrefmode=\xrefrunmode
+ {\def \zxtitle {#4}%
+ \edef \znext {\noexpand\noexpand\noexpand\xref
+ {#1}{\noexpand#2}{#3}%
+ {\expandafter\zdefof \meaning\zxtitle\zmark}{#5}}%
+ \expandafter\zxwrite\expandafter{\znext\zcomment}}%
+ \if \vmodep \repeatpenalty \fi % In case glue follows write.
+ \else\ifnum \xrefmode=\xrefsnapmode
+ \immediate\zxwrite{\noexpand\xref{#1}{#2}{#3}{#4}{#5}\zcomment}%
+ \else
+ \zxnomode
+ \fi\fi\fi\fi}
+
+\def \zxwrite {%
+ \if \zxdivopen \write \zxdivfile \else \write \zxrootfile \fi}
+
+\def \zxnomode {%
+ \zzerror{No cross-reference mode is set}}
+
+% Page Hints
+% ---- -----
+
+
+\def \pagehint #1{%
+ \xref{hint}{\noexpand\folio}{}{#1}{}}
+
+% There is nothing to do when hint entries are executed.
+
+\def \xrefhint #1#2#3#4{}