diff --git a/jfp-paper/amsfonts.sty b/jfp-paper/amsfonts.sty new file mode 100644 index 0000000000000000000000000000000000000000..5d563d6254209c12bab4fda5444903fde2161129 --- /dev/null +++ b/jfp-paper/amsfonts.sty @@ -0,0 +1,190 @@ +%% +%% This is file `amsfonts.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% amsfonts.dtx +%% +%%% ==================================================================== +%%% @LaTeX-file{ +%%% filename = "amsfonts.dtx", +%%% version = "2.2f", +%%% date = "2001/10/25", +%%% time = "11:51:34 EDT", +%%% checksum = "12894 459 2125 19071", +%%% author = "American Mathematical Society", +%%% copyright = "Copyright 2001 American Mathematical Society, +%%% all rights reserved. Copying of this file is +%%% authorized only if either: +%%% (1) you make absolutely no changes to your copy, +%%% including name; OR +%%% (2) if you do make changes, you first rename it +%%% to some other name.", +%%% address = "American Mathematical Society, +%%% Technical Support, +%%% Publications Technical Group, +%%% P. O. Box 6248, +%%% Providence, RI 02940, +%%% USA", +%%% telephone = "401-455-4080 or (in the USA and Canada) +%%% 800-321-4AMS (321-4267)", +%%% FAX = "401-331-3842", +%%% email = "tech-support@ams.org (Internet)", +%%% codetable = "ISO/ASCII", +%%% keywords = "latex, amslatex, ams-latex, amsfonts, msam, +%%% msbm, eufm, blackboard bold", +%%% supported = "yes", +%%% abstract = "This file is part of the AMSFonts distribution. +%%% It provides easy access in \LaTeXe{} to certain +%%% math fonts for extra math symbols, fraktur +%%% letters, and blackboard bold letters. See the +%%% AMSFonts user's guide for more information.", +%%% docstring = "The checksum field above contains a CRC-16 +%%% checksum as the first value, followed by the +%%% equivalent of the standard UNIX wc (word +%%% count) utility output of lines, words, and +%%% characters. This is produced by Robert +%%% Solovay's checksum utility.", +%%% } +%%% ==================================================================== +\NeedsTeXFormat{LaTeX2e}% LaTeX 2.09 can't be used (nor non-LaTeX) +[1994/12/01]% LaTeX date must be December 1994 or later +\ProvidesPackage{amsfonts}[2001/10/25 v2.2f] +\DeclareOption{psamsfonts}{% + \ifnum\cmex@opt=7 \def\cmex@opt{10}% + \else \def\cmex@opt{0}\fi + \DeclareFontFamily{U}{msa}{}% + \DeclareFontShape{U}{msa}{m}{n}{<-6>msam5<6-8>msam7<8->msam10}{}% + \DeclareFontFamily{U}{msb}{}% + \DeclareFontShape{U}{msb}{m}{n}{<-6>msbm5<6-8>msbm7<8->msbm10}{}% + \DeclareFontFamily{U}{euf}{}% + \DeclareFontShape{U}{euf}{m}{n}{<-6>eufm5<6-8>eufm7<8->eufm10}{}% + \DeclareFontShape{U}{euf}{b}{n}{<-6>eufb5<6-8>eufb7<8->eufb10}{}% +} +\@ifundefined{cmex@opt}{\def\cmex@opt{1}}{} +\ProcessOptions\relax +\ifnum\cmex@opt=1 \relax + \DeclareFontShape{OMX}{cmex}{m}{n}{<-8>cmex7<8>cmex8<9>cmex9% + <10><10.95><12><14.4><17.28><20.74><24.88>cmex10}{}% + \expandafter\let\csname OMX/cmex/m/n/10\endcsname\relax +\else + \ifnum\cmex@opt=10 % need to override cmex7 fontdef from amsmath + \begingroup + \expandafter\let\csname OMX+cmex\endcsname\relax + \fontencoding{OMX}\fontfamily{cmex}% + \try@load@fontshape + \endgroup + \expandafter\let\csname OMX/cmex/m/n/10\endcsname\relax + \def\cmex@opt{0}% + \fi +\fi +\providecommand*{\@mathmeasure}[3]{% + \setbox#1\hbox{\frozen@everymath\@emptytoks\m@th$#2#3$}} +\@ifundefined{@emptytoks}{\csname newtoks\endcsname\@emptytoks}{} +\DeclareSymbolFont{AMSa}{U}{msa}{m}{n} +\DeclareSymbolFont{AMSb}{U}{msb}{m}{n} +\@ifundefined{yen}{% + \edef\yen{\noexpand\mathhexbox{\hexnumber@\symAMSa}55} +}{} +\@ifundefined{checkmark}{% + \edef\checkmark{\noexpand\mathhexbox{\hexnumber@\symAMSa}58} +}{} +\@ifundefined{circledR}{% + \edef\circledR{\noexpand\mathhexbox{\hexnumber@\symAMSa}72} +}{} +\@ifundefined{maltese}{% + \edef\maltese{\noexpand\mathhexbox{\hexnumber@\symAMSa}7A} +}{} +\begingroup \catcode`\"=12 +\DeclareMathDelimiter{\ulcorner}{\mathopen} {AMSa}{"70}{AMSa}{"70} +\DeclareMathDelimiter{\urcorner}{\mathclose}{AMSa}{"71}{AMSa}{"71} +\DeclareMathDelimiter{\llcorner}{\mathopen} {AMSa}{"78}{AMSa}{"78} +\DeclareMathDelimiter{\lrcorner}{\mathclose}{AMSa}{"79}{AMSa}{"79} +\xdef\widehat#1{\noexpand\@mathmeasure\z@\textstyle{#1}% + \noexpand\ifdim\noexpand\wd\z@>\tw@ em% + \mathaccent"0\hexnumber@\symAMSb 5B{#1}% + \noexpand\else\mathaccent"0362{#1}\noexpand\fi} +\xdef\widetilde#1{\noexpand\@mathmeasure\z@\textstyle{#1}% + \noexpand\ifdim\noexpand\wd\z@>\tw@ em% + \mathaccent"0\hexnumber@\symAMSb 5D{#1}% + \noexpand\else\mathaccent"0365{#1}\noexpand\fi} +\DeclareMathSymbol{\dabar@}{\mathord}{AMSa}{"39} +\xdef\dashrightarrow{\mathrel{\dabar@\dabar@ + \mathchar"0\hexnumber@\symAMSa 4B}}% +\xdef\dashleftarrow{\mathrel{\mathchar"0\hexnumber@\symAMSa 4C\dabar@ + \dabar@}}% +\global\let\dasharrow\dashrightarrow +\global\let\rightleftharpoons\undefined +\DeclareMathSymbol{\rightleftharpoons}{\mathrel}{AMSa}{"0A} +\global\let\angle\undefined +\DeclareMathSymbol{\angle} {\mathord}{AMSa}{"5C} +\global\let\hbar\undefined +\DeclareMathSymbol{\hbar} {\mathord}{AMSb}{"7E} +\global\let\sqsubset\undefined +\DeclareMathSymbol{\sqsubset} {\mathrel}{AMSa}{"40} +\global\let\sqsupset\undefined +\DeclareMathSymbol{\sqsupset} {\mathrel}{AMSa}{"41} +\global\let\mho\undefined +\DeclareMathSymbol{\mho} {\mathord}{AMSb}{"66} +\endgroup +\DeclareMathAlphabet{\mathfrak}{U}{euf}{m}{n} +\SetMathAlphabet{\mathfrak}{bold}{U}{euf}{b}{n} +\DeclareSymbolFontAlphabet{\mathbb}{AMSb} +\DeclareFontEncodingDefaults{\relax}{\def\accentclass@{7}} +\DeclareRobustCommand{\frak}[1]{% + {\@subst@obsolete{amsfonts}\frak\mathfrak{#1}}} +\DeclareRobustCommand{\Bbb}[1]{% + {\@subst@obsolete{amsfonts}\Bbb\mathbb{#1}}} +\DeclareRobustCommand{\bold}[1]{% + {\@subst@obsolete{amsfonts}\bold\mathbf{#1}}} +\begingroup \catcode`\"=12 \relax +\gdef\newsymbol#1#2#3#4#5{% + \@obsolete{amsfonts}\newsymbol\DeclareMathSymbol + \@ifdefinable#1{% + \edef\next@ + {\ifcase #2 \or + \hexnumber@\symAMSa\or + \hexnumber@\symAMSb\fi}% + \ifx\next@\@empty + \PackageError{amsfonts}{\Invalid@@\newsymbol}\@ehd% + \else + \global\mathchardef#1"#3\next@#4#5 + \fi}} +\endgroup +\long\def\@gobblethree#1#2#3{} +\if@compatibility + \let\@obsolete\@gobblethree +\else + \def\@obsolete#1#2#3{\PackageWarning{#1}{% + Obsolete command \protect#2; \protect#3 should be used instead}}% +\fi +\def\@subst@obsolete#1#2#3{\@obsolete{#1}#2#3\gdef#2{#3}#2} +\begingroup \catcode`\"=12 +\DeclareMathSymbol{\square} {\mathord}{AMSa}{"03} +\DeclareMathSymbol{\lozenge} {\mathord}{AMSa}{"06} +\DeclareMathSymbol{\vartriangleright} {\mathrel}{AMSa}{"42} +\DeclareMathSymbol{\vartriangleleft} {\mathrel}{AMSa}{"43} +\DeclareMathSymbol{\trianglerighteq} {\mathrel}{AMSa}{"44} +\DeclareMathSymbol{\trianglelefteq} {\mathrel}{AMSa}{"45} +\DeclareMathSymbol{\rightsquigarrow} {\mathrel}{AMSa}{"20} +\@ifpackageloaded{latexsym}{\@tempswafalse}{\@tempswatrue} +\if@tempswa + \global\let\Box\square + \global\let\Diamond\lozenge + \global\let\leadsto\rightsquigarrow + \global\let\lhd\@@undefined + \global\let\unlhd\@@undefined + \global\let\rhd\@@undefined + \global\let\unrhd\@@undefined + \DeclareMathSymbol{\lhd} {\mathbin}{AMSa}{"43} + \DeclareMathSymbol{\unlhd} {\mathbin}{AMSa}{"45} + \DeclareMathSymbol{\rhd} {\mathbin}{AMSa}{"42} + \DeclareMathSymbol{\unrhd} {\mathbin}{AMSa}{"44} +\xdef\Join{\mathrel{\mathchar"0\hexnumber@\symAMSb 6F\mkern-13.8mu% + \mathchar"0\hexnumber@\symAMSb 6E}} +\fi +\endgroup +\endinput +%% +%% End of file `amsfonts.sty'. \ No newline at end of file diff --git a/jfp-paper/bm.sty b/jfp-paper/bm.sty new file mode 100644 index 0000000000000000000000000000000000000000..57a736d697a948e97e143541a7a0b69ed2a9b467 --- /dev/null +++ b/jfp-paper/bm.sty @@ -0,0 +1,423 @@ +%% +%% This is file `bm.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% bm.dtx (with options: `package') +%% +%% This is a generated file. +%% +%% Copyright 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 +%% The LaTeX3 Project and any individual authors listed elsewhere +%% in this file. +%% +%% This file was generated from file(s) of the Standard LaTeX `Tools Bundle'. +%% -------------------------------------------------------------------------- +%% +%% It may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2003/12/01 or later. +%% +%% This file may only be distributed together with a copy of the LaTeX +%% `Tools Bundle'. You may however distribute the LaTeX `Tools Bundle' +%% without such generated files. +%% +%% The list of all files belonging to the LaTeX `Tools Bundle' is +%% given in the file `manifest.txt'. +%% +%% Copyright 1996 1997 1998 1999 2002 2003 2004 David Carlisle Frank Mittelbach +%% +%% Development of this package was commissioned by Y&Y Inc. +%% http://www.yandy.com +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{bm} + [2004/02/26 v1.1c Bold Symbol Support (DPC/FMi)] +\def\bm#1#2{% + \let\bm@pmb\install@mathalphabet + \let\bm@pmb@\getanddefine@fonts + \let\bm@pmb@@\or + \edef\bm@general{\f@encoding/\f@family/\f@series/\f@shape/\f@size}% + \@tempcnta#2% + \count@-\count18% + \advance\count@-\@tempcnta + \advance\count@15\relax + \ifnum\count@<\z@ + \advance\@tempcnta\count@ + \fi + \let\or\relax + \expandafter\let\csname bm@#1table\endcsname\@gobble + \def\bm@define##1{% + \expandafter\xdef\csname bm@#1table\endcsname{% + \csname bm@#1table\endcsname\or##1}}% + \def\getanddefine@fonts##1##2{% + \def\@tempa{##2}% + \def\@tempb####1##1####2####3\@nil{\def\@tempb{####2}}% + \expandafter\expandafter\expandafter + \@tempb\csname mv@#1\endcsname\@nil + \ifx\@tempa\@tempb + \bm@define\m@ne + \else + \edef\@tempa{sym#1\expandafter\@gobblefour\string##1}% + \ifnum\@tempcnta<% + \expandafter\ifx\csname\@tempa\endcsname\relax + \@ne + \else + \m@ne + \fi + \bm@define\z@ + \else + \expandafter\ifx\csname\@tempa\endcsname\relax + \begingroup + \escapechar\m@ne + \edef\@tempb{\endgroup + \noexpand\split@name + \expandafter\string\@tempb}% + \@tempb/\@nil + \expandafter\ifx + \csname symbold\expandafter\@gobblefour\string##1\endcsname + \relax + \expandafter\new@mathgroup\csname\@tempa\endcsname + \expandafter\new@symbolfont\csname\@tempa\endcsname + \f@encoding\f@family\f@series\f@shape + \advance\@tempcnta\m@ne + \else + \def\bm@expand####1##1####2####3\@nil{\def\bm@expand{####2}}% + \expandafter\expandafter\expandafter + \bm@expand\csname mv@bold\endcsname\@nil + \ifx\bm@expand\@tempb + \expandafter\let\csname\@tempa\expandafter\endcsname + \csname symbold\expandafter + \@gobblefour\string##1\endcsname + \else + \expandafter\new@mathgroup\csname\@tempa\endcsname + \expandafter\new@symbolfont\csname\@tempa\endcsname + \f@encoding\f@family\f@series\f@shape + \advance\@tempcnta\m@ne + \fi + \fi + \else + \PackageInfo{bm}% + {Symbol font \@tempa\space already defined.\MessageBreak + Not overwriting it}% + \fi + \count@\csname\@tempa\endcsname + \advance\count@-##1% + \bm@define{\the\count@\relax}% + \fi + \fi}% + \let\install@mathalphabet\@gobbletwo + \mv@normal + \expandafter\xdef\csname bm@#1table\endcsname{% + \noexpand\ifcase\@tempcnta + \csname bm@#1table\endcsname + \noexpand\else + \z@ + \noexpand\fi}% + \expandafter\split@name\bm@general\@nil + \let\install@mathalphabet\bm@pmb + \let\getanddefine@fonts\bm@pmb@ + \let\or\bm@pmb@@} +\ifx\bmmax\@undefined + \chardef\bmmax=4 +\fi +\ifx\mv@bold\@undefined + \def\bm@boldtable{\m@ne} + \AtEndOfPackage{% + \def\bm@gr@up#1#2{% + \bm@pmb{#2}}} +\else + \bm{bold}\bmmax + \@ifundefined{symboldoperators} + {} + {\DeclareSymbolFontAlphabet\mathbf{boldoperators}} +\fi +\ifx\hmmax\@undefined + \chardef\hmmax=3 +\fi +\ifx\mv@heavy\@undefined +\else + \bm{heavy}\hmmax +\fi +\begingroup +\catcode`\'=\active +\@firstofone{\endgroup +\def\bm@general#1#2#3#4#5{% + \begingroup + \let\bm\@firstofone + \let\hm\@firstofone + \global\let\bm@command\@empty + \let\@let@token\@empty + \let\protect\@empty + \let\@typeset@protect\@empty + \def\bm@mathchoice{\bm@m@thchoice#1}% + \def\bm@group{\bm@gr@up#1}% + \let\bm@table#2% + \let\left\holdinginserts + \let\right\left + \let\mskip\mkern + \let\hskip\kern + \let\bm@prime\copy + \def'{\bm@prime\prime\relax}% + \def\@ifnextchar##1##2##3##4{% + \if##1##4% + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + {##2##4}{##3{##4}}}% + \def\GenericWarning##1##2{% + \unvcopy{\GenericWarning{##1}{##2}}}% + \def\GenericError##1##2##3##4{% + \unvcopy{\GenericError{##1}{##2}{##3}{##4}}}% + \let\DN@\copy + \let\FN@\copy + \let\next@\copy + \global\let\bm@first\@empty + \ifx\uproot@\undefined\else + \def\root##1\of##2{{\root##1\of{##2}}}% + \fi + \def\mathaccentV##1{\mathaccent"\accentclass@}% + \let\@ifnext\@ifnextchar + \let\measure@lhs\copy + \let \rel@break\copy + \let \bin@break\copy + \let \after@open\copy + \let \after@close\copy + \let\ifmmode\iftrue + \let\install@mathalphabet\def + \let\getanddefine@fonts\@gobbletwo + #3% + \def\select@group##1##2##3##4{{% + \protect##1{##4}}}% + \def\use@mathgroup##1##2##3{{% + \protect\use@mathgroup##1{##2}{##3}}}% + \bm@expand#5\bm@end + \endgroup + #4} +} +\DeclareRobustCommand\bm{% + \bm@general\boldmath\bm@boldtable\mv@bold\bm@command} +\protected@edef\bm#1{\bm{#1}} +\def\DeclareBoldMathCommand{\@testopt\bm@declare{bold}} +\def\bm@declare[#1]#2{% + \expandafter\bm@general + \csname #1math\expandafter\endcsname + \csname bm@#1table\expandafter\endcsname + \csname mv@#1\endcsname + {\bm@define#2}} +\def\bmdefine{\DeclareBoldMathCommand[bold]} +\ifx\mv@heavy\@undefined + \let\hm\bm + \let\heavymath\boldmath + \let\bm@heavytable\bm@boldtable +\else + \DeclareRobustCommand\hm{% + \bm@general\heavymath\bm@heavytable\mv@heavy\bm@command} + \protected@edef\hm#1{\hm{#1}} + \def\hmdefine{\DeclareBoldMathCommand[heavy]} +\fi +\outer\def\bm@end{\@@end} +\def\bm@expand{\afterassignment\bm@exp@nd\count@`\a} +\def\bm@exp@nd{\afterassignment\bm@test\count@`\a} +\def\bm@test{% + \let\bm@previous\@let@token + \futurelet\@let@token\bm@test@} +\def\bm@test@{% + \ifx\@let@token\bgroup + \expandafter\bm@group + \else + \expandafter\bm@test@token + \fi} +\def\bm@gr@up#1#2{% + \bm@add{{\bm@gr@@p#1{{#2}}}}} +\def\bm@gr@@p#1#2{% + \ifmmode + \bm@mchoice#1{#2}{#2}{#2}{#2}% + \else + \bfseries#1#2% + \fi} +\def\bm@test@token#1{% + \let\bm@next\@empty + \ifx#1\@@end + \else\ifx#1\mathchoice + \let\bm@next\bm@mathchoice + \else\ifx#1\mathchar + \afterassignment\bm@mathchar\count@ + \else\ifx#1\mathaccent + \afterassignment\bm@mathaccent\count@ + \else\ifx#1\delimiter + \afterassignment\bm@delimiter\count@ + \else\ifx#1\radical + \afterassignment\bm@radical\count@ + \else\ifx#1\mkern + \bm@register#1{\muskip\z@}% + \else\ifx#1\kern + \bm@register#1\skip@ + \else\ifx#1\penalty + \bm@register#1\count@ + \else\ifx#1\unvcopy + \let\bm@next\bm@add + \else\ifcat\noexpand#1\relax + \xdef\meaning@{\meaning#1}% + \expandafter\bm@mchar@test\meaning@""\@nil#1% + \else\ifcat.\ifcat a#1.\else#1\fi + \count@\mathcode`#1\relax + \ifnum\count@=\mathcode`\'% + \begingroup\uccode`\~`#1\uppercase{\endgroup + \def\bm@next{\bm@expand~}}% + \else + \ifx\bm@previous\left + \count@\delcode`#1\relax + \bm@delimiter + \else + \bm@mathchar + \fi + \fi + \else + \bm@add{#1}% + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \bm@next} +\def\bm@define#1{% + \begingroup + \ifx\bm@command\@gtempa + \def\mathchar{\global\mathchardef#1}% + \bm@command + \else + \toks@\expandafter{\bm@command}% + \xdef#1{\bm@first\noexpand\bm@protect\noexpand#1{\the\toks@}}% + \fi + \endgroup} +\def\bm@protect#1{% + \ifx\protect\@typeset@protect + \expandafter\@firstofone + \else + \protect#1\expandafter\@gobble + \fi} +\def\bm@mchoice#1#2#3#4#5{% + \mathchoice{\hbox{#1$\displaystyle\m@th#2$}}% + {\hbox{#1$\textstyle\m@th#3$}}% + {\hbox{#1$\scriptstyle\m@th#4$}}% + {\hbox{#1$\scriptscriptstyle\m@th#5$}}} +\def\bm@m@thchoice#1#2#3#4#5{% + \bm@add{\bm@mchoice#1{#2}{#3}{#4}{#5}}} +\def\bm@register#1#2{% + \def\@tempa{#1\the#2}% + \afterassignment\bm@r@gister#2} +\def\bm@r@gister{% + \bm@xadd{\@tempa\space}} +\def\bm@mathchar{% + \@tempcntb\count@ + \let\@tempa\bm@group + \bm@changefam{}% + \ifnum\count@>\@tempcntb + \ifx\bm@command\@empty + \xdef\@gtempa{\mathchar\the\count@\space}% + \fi + \bm@xadd{\mathchar\the\count@\space}% + \else + \begingroup + \divide\count@"1000 + \let\bm@expand\relax + \bm@xadd\bm@class + \endgroup + \edef\@tempb{% + \noexpand\@tempa{\mathchar\the\count@\space}}% + \@tempb + \fi} +\def\bm@pmb#1{% + \bm@add{\bm@pmb@{#1}}} +\def\bm@pmb@#1{{% + \setbox\tw@\hbox{$\m@th\mkern.4mu$}% + \mathchoice + \bm@pmb@@\displaystyle\@empty{#1}% + \bm@pmb@@\textstyle\@empty{#1}% + \bm@pmb@@\scriptstyle\defaultscriptratio{#1}% + \bm@pmb@@\scriptscriptstyle\defaultscriptscriptratio{#1}}} +\def\bm@pmb@@#1#2#3{{% + \setbox\z@\hbox{$\m@th#1#3$}% + \dimen@#2\wd\tw@ + \rlap{\copy\z@}% + \kern\dimen@ + \raise1.5\dimen@\rlap{\copy\z@}% + \kern\dimen@ + \box\z@}}% +\def\bm@class{% + \ifcase\count@ + \or + \mathop\or + \mathbin\or + \mathrel\or + \mathopen\or + \mathclose\or + \mathpunct\or + \fi} +\def\bm@add#1{% + \begingroup + \toks@\expandafter{\bm@command#1}% + \xdef\bm@command{\the\toks@}% + \endgroup + \bm@expand} +\def\bm@xadd#1{% + \begingroup + \toks@\expandafter{\bm@command}% + \xdef\bm@command{\the\toks@#1}% + \endgroup + \bm@expand} +\def\bm@mathaccent{% + \bm@changefam{}% + \begingroup + \def\bm@group##1{\endgroup\bm@xadd{\bgroup}##1\egroup}% + \def\bm@test@token{\endgroup\bm@test@token}% + \let\relax\@empty + \bm@xadd{\mathaccent\the\count@\space}} +\def\bm@delimiter{% + \ifnum\count@>\z@ + \bm@changefam{}% + \bm@changefam{000}% + \fi + \bm@xadd{\delimiter\the\count@\space}}% +\def\bm@radical{% + \bm@changefam{}% + \bm@changefam{000}% + \bm@xadd{\radical\the\count@\space}}% +\edef\bm@mchar@{\meaning\mathchar} +\def\bm@mchar@test#1"#2"#3\@nil#4{% + \xdef\meaning@{#1}% + \ifx\meaning@\bm@mchar@ + \count@"#2\relax + \bm@mathchar + \else + \ifx\bm@previous\@empty + \ifx\relax#4% + \gdef\bm@first{#4}% + \fi + \fi + \bm@add{#4}% + \fi} +\def\bm@changefam#1{% + \@tempcnta\count@ + \divide\@tempcnta"1000#1 % + \multiply\@tempcnta"1000#1 % + \advance\@tempcnta-\count@ + \divide\@tempcnta-"100#1 % + \@tempcnta\bm@table + \ifnum\@tempcnta=\m@ne + \let\@tempa\bm@pmb + \else + \multiply\@tempcnta"100#1 % + \advance\count@\@tempcnta + \fi} +\def\bm@prime{^\bgroup + \let\bm@prime'% + \def\prim@s##1\relax{##1\futurelet\@let@token\pr@m@s}% + \prim@s} +\let\boldsymbol\bm +\let\heavysymbol\hm +\endinput +%% +%% End of file `bm.sty'. \ No newline at end of file diff --git a/jfp-paper/jfp-gtt.tex b/jfp-paper/jfp-gtt.tex new file mode 100644 index 0000000000000000000000000000000000000000..8665fc9bc8dbdeb3982f33c1a66522b3b1c2a873 --- /dev/null +++ b/jfp-paper/jfp-gtt.tex @@ -0,0 +1,44 @@ +\documentclass{jfp1} + +\title{Gradual Type Theory} + +\author[M.S. New] + {Max S. New\\ + Northeastern University\\ + %% \email{maxnew@ccs.neu.edu} + } + +\author[D.R. Licata] + {Daniel R. Licata \\ + Wesleyan University\\ + %% \email{drlicata@wesleyan.edu} + } + +\author[A. Ahmed] + {Amal Ahmed \\ + Northeastern University\\ + %% \email{amal@ccs.neu.edu} + } + +\jdate{September 2001, update April 2007} +\pubyear{2001} +\pagerange{\pageref{firstpage}--\pageref{lastpage}} +\doi{S0956796801004857} + +\newtheorem{lemma}{Lemma}[section] + +\begin{document} +\label{firstpage} +\maketitle + +\begin{abstract} + foo bar +\end{abstract} + +\section{Introduction} + +hi + +\label{lastpage} + +\end{document} diff --git a/jfp-paper/jfp.bst b/jfp-paper/jfp.bst new file mode 100644 index 0000000000000000000000000000000000000000..d0fdaa0cab574114598e7d1d82924c216d4dfb56 --- /dev/null +++ b/jfp-paper/jfp.bst @@ -0,0 +1,1316 @@ +% CUP Journal of Functional Programming bibliography style +% v1.0, released 22nd May 1995 +% Copyright 1994,1995 Cambridge University Press + +% This BibTeX 0.99 style file is intended for documents that use the +% author-date citation system. It should be used in conjunction with the +% authordate1-4.sty (or equivalent) LaTeX style-option. +% +% In deciding on the bibliography layout to be implemented, the following +% works have been consulted: +% 1. British Standard 5605: "Citing publications by bibliographic +% references", 1978. +% 2. British Standard 1629: "Bibliographic references", 1976. +% (Note: There is now a 1989 edition.) +% 3. "Copy-editing" by Judith Butcher, Cambridge University Press, 1981. +% 4. "The Oxford Dictionary for Writers and Editors", Oxford University +% Press, 1981 (for abbreviations). +% 5. "The Chicago Manual of Style", Chicago University Press, 1982. +% +% Discretion has been used in certain matters. In particular: +% - Titles are italic except when there is a "contribution title" and +% a "main publication title", in which case the "contribution title" +% is roman while the "main publication title" is italic. +% - When there is a PUBLISHER, it is assumed that ADDRESS contains "place of +% publication"; output is of the form "place-of-publication: publisher". +% When there is an ORGANIZATION as well as a PUBLISHER, output is of the +% form "place-of-publication: publisher, for organization". Otherwise, +% it is assumed that ADDRESS is a postal address, and output is of the +% form "institution, address", "organization, address", "school, address" +% or "howpublished, address". +% - If there is a MONTH but no VOLUME or NUMBER for a journal-article, the +% MONTH is used on the assumption that it contains information that is +% equivalent to VOLUME or NUMBER. MONTH is ignored for other documents +% that have a PUBLISHER, but output after YEAR for anything else. +% - When CHAPTER and/or PAGES are specified with INBOOK, it is assumed that +% these fields are being used to pick out particular pages of interest +% (as an alternative to using the optional [...] argument of \cite); +% the information is put at the very end of the entry, in line with BS 1629. +% When CHAPTER and/or PAGES are specified for INCOLLECTION or INPROCEEDINGS, +% it is assumed that the fields are being used to specify the location of +% the part/article of interest; the information is put before the +% BOOKTITLE, in line with Chicago's treatment of "parts" and "chapters". +% - Since "volume" can be used in various ways (see page 219 of Butcher), +% this file assumes that, when there is a SERIES, any VOLUME and NUMBER +% refer to position in the SERIES (i.e. Butcher's meaning 4). +% If there is a VOLUME but no SERIES, it is assumed that VOLUME refers +% to a volume within a particular work (i.e. Butcher's meaning 1, 2 or 3). +% For INPROCEEDINGS and INCOLLECTION, this information goes after the +% BOOKTITLE. (If you prefer to have volume information before EDITOR, +% as on page 449 of Chicago, you can set TYPE = "Vol." with INCOLLECTION.) +% +% This file differs from authordate1.bst, authordate3.bst and +% authordate4.bst in that: +% - Titles of journals, articles and boooks are "downstyle". Apart from the +% first character, and the first character following : and white space, +% uppercase letters are converted to lowercase unless protected by {}. +% - Author's and editor's names are in roman. +% +% The combination of authordate2.bst and authordate1-4.sty allows citations +% of the form \shortcite{bloggs-60} as well as the usual \cite{bloggs-60}. +% When +% ... \cite{bloggs-60} ... \shortcite{bloggs-60} ... +% appears in the input file, +% ... (Bloggs, 1960) ... (1960) ... +% appears in the final document. +% +% This file was developed from apalike.bst. It also uses code taken from +% acm.bst, aaai-named.bst, btxbst.doc, ieeetr.bst and siam.bst. +% +% David Rhead +% Cripps Computing Centre +% Nottingham University +% March 1990 +% + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label extra.label sort.label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.year.month.check} +{ year empty$ + { "empty year in " cite$ * warning$ } + { add.period$ write$ + month empty$ + { " (" year * extra.label * ")" * % ajw + after.sentence 'output.state := + } + { " " year * extra.label * " (" * month * ")." * + after.sentence 'output.state := + } + if$ + } + if$ +} + +FUNCTION {output.year.check} +{ year empty$ + { "empty year in " cite$ * warning$ } + { add.period$ write$ + " (" year * extra.label * ")" * % ajw + after.sentence 'output.state := + } + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem[" write$ + label write$ + "]{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {boldface} +{ duplicate$ empty$ + { pop$ "" } + { "{\bf " swap$ * "}" * } + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{vv~}{ll}{, jj}{, ff}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { t "others" = + { ", {\em et~al.\ }\relax" * } + { ", \& " * t * } % Butcher, pages + if$ % 186-189. + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.key} +{ empty$ + { key field.or.null } + { "" } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > % Use ODWE abbrevs. + { " (eds)" * } % to avoid + { " (ed)" * } % ambiguity between + if$ % "editor" and + } % "edition". + if$ +} + +FUNCTION {format.title} % Howells example +{ title empty$ % in BS 5605 comes + { "" } % out wrong because + { title "t" change.case$ } % Patashnik + if$ % capitalizes +} % after a colon. + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.btitle} +{ title empty$ + { "" } + { title "t" change.case$ emphasize } + if$ +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.numberinseries} +{ number empty$ + { "" } + { number multi.page.check + { ", nos. " number n.dashify tie.or.space.connect } + { ", no. " number tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {booklike.series.volume.number} % Chicago, pages +{ series empty$ % 450-451. + { volume empty$ + { " " } + { " Vol. " volume * } + if$ + } + { + volume empty$ + { number empty$ + { series } + { series format.numberinseries * } + if$ + } + { number empty$ + { series ", vol. " volume * * } + { series ", vol. " * volume * format.numberinseries * } + if$ + } + if$ + } + if$ +} + +FUNCTION {incollectionlike.series.volume.number} +{ series empty$ + { volume empty$ + { " " } + { " vol. " volume * } + if$ + } + { new.block + volume empty$ + { number empty$ + { series } + { series format.numberinseries * } + if$ + } + { number empty$ + { series ", vol. " volume * * } + { series ", vol. " * volume * format.numberinseries * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edn." * } + { edition "t" change.case$ " edn." * } + if$ + } + if$ +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "" pages n.dashify tie.or.space.connect } + { "" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.pagesinbook} % By the time the +{ pages empty$ % reader has read + { "" } % address, pub'r, + { pages multi.page.check % note (where the + { "Pages " pages n.dashify tie.or.space.connect } % note may end with + { "Page " pages tie.or.space.connect } % numbers), s/he + if$ % may not recognise + } % a number-range as + if$ % meaning pages. +} % Avoid ambiguity + % (Butcher, p.181). + +FUNCTION {format.vol.num.date.pages} +{ volume empty$ + { month empty$ + { "" } + { month } + if$ + } + { volume boldface field.or.null + number empty$ + { month empty$ + 'skip$ + { "(" month * ")" * * } + if$ + } + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ", " * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages.inbook} +{ chapter empty$ + 'format.pagesinbook + { type empty$ + { "Chap." } + { type } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pagesinbook "l" change.case$ * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages.incoll} +{ chapter empty$ + { pages empty$ + { " " } % ajw + { "{\em " format.pagesinbook " of:} " * * } + if$ + } + { type empty$ + { "{\em Chap. " chapter * } + { "{\em " type * " " * chapter * } + if$ + pages empty$ + { " of:} " * } + { ", " * format.pagesinbook "l" change.case$ " of:} " * * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} % Achieves effect +{ booktitle empty$ % shown in 16.51 + { "" } % of Chicago, at + { editor empty$ % expense of not + { format.chapter.pages.incoll % achieving effects + booktitle emphasize * } % shown in 16.50 + { format.chapter.pages.incoll % of Chicago, on + format.editors * ", " * % page 189 of + booktitle emphasize * } % Butcher and in + if$ % 4.4 of BS 1629. + } + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Tech. rept." } % ODWE abbrevs. + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.addr.pub} +{ publisher empty$ + { "" } + { address empty$ + { "" } + { address ": " * } + if$ + publisher * + } + if$ +} + +FUNCTION {format.addr.pub.org} % If there's an +{ address empty$ % an organization + { publisher * ", for " * organization * } % and a publisher + { address ": " * publisher * ", for " * organization * } % too. + if$ +} + +FUNCTION {format.addr.inst} +{ address empty$ + { institution empty$ + { "" } + { institution } + if$ + } + { institution empty$ + { "" } + { institution ", " * } + if$ + address * + } + if$ +} + +FUNCTION {format.addr.org} +{ address empty$ + { organization empty$ + { "" } + { organization } + if$ + } + { organization empty$ + { "" } + { organization ", " * } + if$ + address * + } + if$ +} + +FUNCTION {format.article.crossref} +{ "{\em In:}" + " \cite{" * crossref * "}" * +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "{\em In:}" + } + { " Vol." volume tie.or.space.connect + " of " * + } + if$ + "\cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ "{\em In:}" + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + author format.key output + output.year.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal "t" change.case$ emphasize + "journal" output.check + format.vol.num.date.pages output + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + editor format.key output + } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + output.year.check + new.block + format.btitle "title" output.check + crossref missing$ + { new.sentence + format.edition output + new.block + booklike.series.volume.number output + new.block + format.addr.pub "publisher" output.check + } + { new.block + format.book.crossref output.nonnull + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + author format.key output + output.year.month.check + new.block + format.btitle "title" output.check + new.block + howpublished output + address output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + editor format.key output + } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + output.year.check + new.block + format.btitle "title" output.check + crossref missing$ + { new.sentence + format.edition output + new.block + booklike.series.volume.number output + new.block + format.addr.pub "publisher" output.check + } + { new.block + format.book.crossref output.nonnull + } + if$ + new.block + note output + new.block % BS 1629 (rather + format.chapter.pages.inbook "chapter and pages" output.check + fin.entry % than Chicago, +} % p. 451) + +FUNCTION {incollection} +{ output.bibitem + author empty$ + { format.editors "editor" output.check + editor format.key output } + { format.authors "author" output.check + author format.key output } + if$ + output.year.check + new.block + format.title "title" output.check + new.block + crossref missing$ % Chapter and/or + { format.in.ed.booktitle output % page numbers can + format.edition output % come out via this + incollectionlike.series.volume.number output % route, too. + new.block + format.addr.pub "publisher" output.check + } + { format.incoll.inproc.crossref output.nonnull + new.block + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + author format.key output + publisher empty$ + { output.year.month.check } + { output.year.check } + if$ + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + incollectionlike.series.volume.number output + new.block + publisher empty$ + { + organization empty$ + 'skip$ + { format.addr.org output } + if$ + } + { + organization empty$ + { format.addr.pub output } + { format.addr.pub.org output } + if$ + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + format.authors output + author format.key output + output.year.month.check + new.block + format.btitle "title" output.check + new.sentence + format.edition output + new.block + organization address new.block.checkb + format.addr.org output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + author format.key output + output.year.month.check + new.block + format.btitle "title" output.check + new.block + "M.Phil. thesis" format.thesis.type output.nonnull % ODWE abbrev. + school "school" output.check + address output + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + author format.key output + output.year.month.check + new.block + format.btitle output + new.block + howpublished output + new.block + note output + fin.entry +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + author format.key output + output.year.month.check + new.block + format.btitle "title" output.check + new.block + "Ph.D. thesis" format.thesis.type output.nonnull % Butcher, + school "school" output.check % page 174. + address output + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + format.editors "author and editor" output.check + editor format.key output + publisher empty$ + { output.year.month.check } + { output.year.check } + if$ + new.block + format.btitle "title" output.check + new.block + booklike.series.volume.number output + new.block + publisher empty$ + { + organization empty$ + 'skip$ + { format.addr.org output } + if$ + } + { + organization empty$ + { format.addr.pub output } + { format.addr.pub.org output } + if$ + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + author format.key output + output.year.month.check + new.block + format.btitle "title" output.check + new.block + format.tr.number output.nonnull + new.sentence + format.addr.inst "institution" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + author format.key output + output.year.month.check + new.block + format.btitle "title" output.check + new.block + note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"Jan."} % ODWE, "months", & + % Chicago, p. 383. +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sept."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {format.lab.names} +{ 's := + s #1 "{vv~}{ll}" format.name$ + s num.names$ duplicate$ + #2 > +%%%%% { pop$ " {\em et~al.\ }\relax" * } + { pop$ " {\em et~al.}\relax" * } + { #2 < + 'skip$ + { s #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " {\em et~al.\ }\relax" * } + { " \& " * s #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {author.key.label} +{ author empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.editor.key.label} +{ author empty$ + { editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key + if$ + } + { editor format.lab.names } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {editor.key.label} +{ editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key + if$ + } + { editor format.lab.names } + if$ +} + +FUNCTION {calc.label} + { type$ "book" = + type$ "inbook" = + type$ "incollection" = % For sensible + or or % treatment of + 'author.editor.key.label % Singer in + { type$ "proceedings" = % BS 1629. + 'editor.key.label + 'author.key.label + if$ + } + if$ + duplicate$ + year empty$ + { + "\protect\citename{" swap$ * ", }" * + "n.d." * 'label := % Chicago, + } % page 457. + { + "\protect\citename{" swap$ * ", }" * + year + * + 'label := + } + if$ + year field.or.null purify$ * + sortify 'sort.label := +} + + +FUNCTION {sort.format.names} % To produce the +{ 's := % order of entries + #1 'nameptr := % specified in item + "" % (3) on page 187 + s num.names$ 'numnames := % of Butcher. + numnames 'namesleft := + { namesleft #0 > nameptr #3 < and } % Only 1st 2 names + { nameptr #1 > % matter for + { " " * } % sorting. + 'skip$ + if$ % Anything that's + nameptr #2 = numnames #2 > and % "et al" goes + { "zzzzz" * } % after works by 2 + { % authors. + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.sort} +{ editor empty$ + { key empty$ + { "to sort, need editor or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} % Two sorting +{ calc.label % passes, from + label sortify % apalike.bst. + " " + * + type$ "book" = + type$ "inbook" = + type$ "incollection" = % For Singer + or or % in BS 1629. + 'author.editor.sort + { type$ "proceedings" = + 'editor.sort + 'author.sort + if$ + } + if$ + #1 entry.max$ substring$ + 'sort.label := + sort.label + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { last.label next.extra } + +INTEGERS { last.extra.num } + +FUNCTION {initialize.extra.label.stuff} +{ #0 int.to.chr$ 'last.label := + "" 'next.extra := + #0 'last.extra.num := +} + +FUNCTION {forward.pass} +{ last.label label = + { last.extra.num #1 + 'last.extra.num := + last.extra.num int.to.chr$ 'extra.label := + } + { "a" chr.to.int$ 'last.extra.num := + "" 'extra.label := + label 'last.label := + } + if$ +} + +FUNCTION {reverse.pass} +{ next.extra "b" = + { "a" 'extra.label := } + 'skip$ + if$ % Code needed here + % if \citeauthor + % and \citeyear + label extra.label * 'label := % were supported. + extra.label 'next.extra := +} + +EXECUTE {initialize.extra.label.stuff} + +ITERATE {forward.pass} + +REVERSE {reverse.pass} + +FUNCTION {bib.sort.order} +{ sort.label + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {bib.sort.order} + +SORT + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{}" write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} \ No newline at end of file diff --git a/jfp-paper/jfp1.cls b/jfp-paper/jfp1.cls new file mode 100644 index 0000000000000000000000000000000000000000..ca9c813ad6328e666112182c2e9a2288e2edd27a --- /dev/null +++ b/jfp-paper/jfp1.cls @@ -0,0 +1,1894 @@ +%% +%% This is file `jfp.cls' +%% +%% CUP Journal of Functional Programming document class +%% Copyright 2001 Cambridge University Press +%% +%% by Mark A. Reed +%% based on JFP.STY v1.24. +%% +%% Incorporating parts of authordate.sty +%% by David Rhead, Cripps Computing Centre (Feb 1990). +%% +%% Bugs (in the case of unchanged files) should be reported to +%% texline@cambridge.org +%% +%% This software may only be used in the preparation of journal articles +%% or books or parts of books to be published by Cambridge University Press. +%% Any other use constitutes an infringement of copyright. +%% +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%% + +\NeedsTeXFormat{LaTeX2e}[1997/12/01] +\ProvidesClass{jfp}[2001/09/27 v1.02 Journal of Functional Programming + ^^Jdocument class] + +\newif\ifprodtf +\newif\ifonepage\global\onepagefalse% +\newif\ifonline +\onlinefalse +% +\newif\ifcompmod\global\compmodfalse +% +\newif\ifincremental\incrementalfalse +%% +\newif\ifindex +\newif\ifdraft +\newif\ifnoquery +\newif\ifbookreview +\newif\ifsptitle +% +\newif\ifsplissue +\global\splissuefalse +% +\newif\ifprinter +\newdimen\draftrule +\newdimen\trimrule +\global\draftrule0pt +\trimrule.1pt +% +\newdimen\trimwidth +\newdimen\trimheight +\newdimen\typewidth +\newdimen\typeheight + +\newdimen\tempdimen +\newdimen\normaltextheight +\newskip\normalbaselineskip +\newdimen\blindfoliodrop +\newif\ifprinter +\global\printerfalse +%% +\DeclareOption{compmod}{\compmodtrue} +% +\DeclareOption{splissue}{\splissuetrue} +% +% +\DeclareOption{incremental}{\incrementaltrue} +\DeclareOption{index}{\indextrue} +\DeclareOption{bookreview}{\bookreviewtrue} +\DeclareOption{noquery}{\noquerytrue} +\DeclareOption{oneside}{\relax} +\DeclareOption{twoside}{\@twosidetrue \@mparswitchtrue} +\DeclareOption{draft}{\draftrule.5pt\setlength\overfullrule{5\p@}} +\DeclareOption{final}{\setlength\overfullrule{\z@}} +\DeclareOption{onecolumn}{\@twocolumnfalse} +\DeclareOption{onepage}{\global\onepagetrue} +\DeclareOption{twocolumn}{\relax} +\DeclareOption{titlepage}{\relax} +\DeclareOption{notitlepage}{\relax} +\DeclareOption{leqno}{\relax} +\DeclareOption{fleqn}{\relax} +\DeclareOption{prodtf}{\prodtftrue} +\DeclareOption{sptitle}{\sptitletrue} +\DeclareOption{printer}{\printertrue} +\DeclareOption{online}{\onlinetrue} +% +\ExecuteOptions{twoside,final,onecolumn} +\ProcessOptions\relax + +\newif\ifCUPmtlplainloaded +%% \ifprodtf +%% \CUPmtlplainloadedtrue +%% \RequirePackage{CUPTimes,jfp2esym} +%% % \RequirePackage{Times,jfp2esym} %%% TB +%% \fi +%%%%%%%%%%%%%%%% +% +\def\trkdefault{trk}% All trk +\DeclareRobustCommand\trkshape + {\not@math@alphabet\trkshape\mathrm + \fontshape\trkdefault\selectfont} +% +\def\spchapterfont{\fontsize{18}{21}\selectfont}%\trkshape} +\def\subtitlefont{\normalfont\fontsize{12}{14}\selectfont\itshape}% +% +\def\splissuefont{\fontsize{12}{14}\itshape\selectfont}%\trkshape} +% +\DeclareFontFamily{OT1}{mtr}{} +\DeclareFontShape{OT1}{mtr}{m}{n}{<->mtr10}{} +\DeclareFontShape{OT1}{mtr}{m}{trk}{<->mtr10[track+140]}{} +\DeclareFontShape{OT1}{mtr}{m}{sl}{<->mtsl10}{} +\DeclareFontShape{OT1}{mtr}{m}{it}{<->mtti10}{} +\DeclareFontShape{OT1}{mtr}{m}{sc}{<->mtcsc10}{} +% +% Warning: please note that the upright shape below is +% used for the \pounds symbol of LaTeX. So this +% font definition shouldn't be removed. +% +\DeclareFontShape{OT1}{mtr}{m}{ui}{<->mtu10}{} +% +%%%%%%% bold series +\DeclareFontShape{OT1}{mtr}{b}{n}{<->sub * cmr/b/n}{} +% +%%%%%%%% bold extended series +\DeclareFontShape{OT1}{mtr}{bx}{n}{<->mtbx10}{} +\DeclareFontShape{OT1}{mtr}{bx}{sl}{<->mtbxsl10}{} +\DeclareFontShape{OT1}{mtr}{bx}{it}{<->mtbxti10}{} +% +% Again this is necessary for a correct \pounds symbol in +% the cmr fonts Hopefully the dc/ec font layout will take +% over soon. +% +\DeclareFontShape{OT1}{mtr}{bx}{ui}{<->ssub * mtr/m/ui}{} +% +%%%%% For mathfrak ... updated on 26th of April 2006 +% +\DeclareFontFamily{U}{eufa}{}% +\DeclareFontShape{U}{eufa}{m}{n}{<-6>eufm5<6-8>eufm7<8->eufm10}{}% +\DeclareFontShape{U}{eufa}{b}{n}{<-6>eufb5<6-8>eufb7<8->eufb10}{}% +% +%%\newcommand{\mathfrak}[1]{{\protect\pmathfrak#1}} +%%\newcommand{\pmathfrak}{\@fontswitch{\relax}{\mfraknew}} +\DeclareMathAlphabet\mfraknew{U}{eufa}{m}{n} +\SetMathAlphabet\mfraknew{normal}{U}{eufa}{m}{n} +\SetMathAlphabet\mfraknew{bold}{U}{eufa}{b}{n} +%%%% + +%%%%%%%%%%%%%%%% +\setlength\lineskip{1\p@} +\setlength\normallineskip{1\p@} +\renewcommand\baselinestretch{} + +\renewcommand\normalsize{% +\ifbookreview +\@setfontsize\small\@ixpt{11}% +\else +\@setfontsize\normalsize\@xpt{13}% +\fi + \abovedisplayskip 6.5\p@ \@plus 1\p@ \@minus 1\p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip 3\p@ \@plus 1\p@ + \belowdisplayshortskip \abovedisplayshortskip + \let\@listi\@listI} + +\normalsize + +\newcommand\small{% + \@setfontsize\small\@ixpt{11}% + \abovedisplayskip 6\p@ \@plus 1\p@ \@minus 1\p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip 3\p@ \@plus 1\p@ + \belowdisplayshortskip \abovedisplayshortskip + \def\@listi{\leftmargin\leftmargini + \topsep 6\p@ \@plus 1\p@ \@minus 1\p@ + \parsep \z@ \itemsep \parsep}% +} + +\newcommand\footnotesize{% + \@setfontsize\footnotesize\@ixpt\@xpt + \abovedisplayskip 5\p@ \@plus 1\p@ \@minus 1\p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip \z@ \@plus 1\p@ + \belowdisplayshortskip \abovedisplayshortskip + \def\@listi{\leftmargin\leftmargini + \topsep 4.5\p@ \@plus 1\p@ \@minus 1\p@ + \parsep \z@ \itemsep \parsep}% +} + +\newcommand\scriptsize{\@setfontsize\scriptsize\@viiipt\@ixpt} +\newcommand\tiny{\@setfontsize\tiny\@vpt\@vipt} +\newcommand\large{\@setfontsize\large\@xiipt{14}} +\newcommand\Large{\@setfontsize\Large\@xvpt{18}} +\ifprodtf + \newcommand\LARGE{\@setfontsize\LARGE{19}{21}}% +\else + \newcommand\LARGE{\@setfontsize\LARGE{18}{21}}% +\fi +\newcommand\huge{\@setfontsize\huge\@xxpt{25}} +\newcommand\Huge{\@setfontsize\Huge\@xxvpt{30}} +% +\def\sluglinefont{\fontsize{7.5}{10}\selectfont} +% +\newcommand\affilsize{\@setfontsize\affilsize\@viiipt\@xpt} +\newcommand\onlineaffilsize{\@setfontsize\affilsize\@viipt\@ixpt} +\let\authorsize\normalsize + +\DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm} +\DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf} +\DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt} +\DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf} +\DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit} +\DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl} +\DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc} +\DeclareRobustCommand*\cal{\@fontswitch\relax\mathcal} +\DeclareRobustCommand*\mit{\@fontswitch\relax\mathnormal} + + \setlength\topmargin{11mm} +\setlength\trimheight{247mm} +\setlength\trimwidth{174mm} +% +\setlength\typeheight{50.5pc} +\setlength\typewidth{30pc} + +\setlength\marginparwidth{2.0cm} +\setlength\marginparsep{10\p@} + +\setlength\headheight{6\p@} +\setlength\headsep{18\p@} +\setlength\topskip{6\p@} +\setlength\footskip{26\p@} + +\setlength\textheight{48.5pc} +\addtolength\textheight{-8.8pt} +\addtolength\textheight{\topskip} +\setlength\normaltextheight{\textheight} + +\setlength\textwidth{30pc} +\setlength\columnsep{10\p@} +\setlength\columnseprule{\z@} + +\setlength\oddsidemargin{21mm}%5pc} +\setlength\evensidemargin\trimwidth +\addtolength\evensidemargin{-\textwidth} +\addtolength\evensidemargin{-\oddsidemargin} + +\setlength\footnotesep{\z@} +\setlength{\skip\footins}{19.5\p@ \@plus 12\p@ \@minus 1\p@} + +\setlength\floatsep{13\p@ \@plus 6.5\p@ \@minus 1\p@} +\setlength\textfloatsep{15\p@ \@plus 4.5\p@ \@minus 3\p@} +\setlength\intextsep{13\p@ \@plus 6.5\p@ \@minus 2\p@} +\setlength\dblfloatsep{13\p@ \@plus 6.5\p@ \@minus 2\p@} +\setlength\dbltextfloatsep{15\p@ \@plus 4.5\p@ \@minus 3\p@} +\setlength\@fptop{\z@ \@plus 0fil} +\setlength\@fpsep{13\p@ \@plus 0fil} +\setlength\@fpbot{\z@ \@plus 3fil} +\setlength\@dblfptop{\z@ \@plus 0fil} +\setlength\@dblfpsep{13\p@ \@plus 0fil} +\setlength\@dblfpbot{\z@ \@plus 3fil} +\setlength\marginparpush{5\p@} + +\setlength\parskip{\z@}% \@plus .3\p@} +\setlength\parindent{10pt} +\setlength\partopsep{\z@ \@plus 1\p@} +\@lowpenalty 51 +\@medpenalty 151 +\@highpenalty 301 +\@beginparpenalty -\@lowpenalty +\@endparpenalty -\@lowpenalty +\@itempenalty -\@lowpenalty +\clubpenalty\@M%z@ +\widowpenalty\@M +\hyphenpenalty8000 + +% +\def\cleardoublepage{\clearpage\if@twoside \ifodd\c@page\else + \hbox{}\thispagestyle{empty}\newpage\if@twocolumn\hbox{}\newpage\fi\fi\fi} +% +\newcommand\partname{Part} +\newcommand\part{\par\addvspace{4ex}\@afterindentfalse \secdef\@part\@spart} + +\def\@part[#1]#2{% + \ifnum \c@secnumdepth >\m@ne + \refstepcounter{part}% + \addcontentsline{toc}{part}{\partname\ \thepart: #1}% + \else + \addcontentsline{toc}{part}{#1}% + \fi + {\parindent \z@ \centering + \ifnum \c@secnumdepth >\m@ne + \normalfont\large\rmfamily \MakeUppercase{\partname}\ % + \ifcase\thepart \or ONE \or TWO \or THREE \or FOUR \or FIVE + \or SIX \or SEVEN \or EIGHT \or NINE \or TEN \else \fi + \par \nobreak + \fi + \normalfont\LARGE\rmfamily #2 \markboth{}{}\par}% + \nobreak \vskip 3ex \@afterheading +} + +\def\@spart#1{% + {\parindent \z@ \centering\normalfont\LARGE\rmfamily #1\par}% + \nobreak \vskip 3ex \@afterheading +} + +\newcommand\section{% + \@startsection {section}{1}{\z@}% + {-19.5\p@ \@plus -6.5\p@ \@minus -3.25\p@}% + {6.5\p@ \@plus \z@ \@minus 1\p@} + {\normalfont\normalsize\bfseries\centering}% +} + +\newcommand\subsection{% + \@startsection{subsection}{2}{\z@} + {-19.5\p@ \@plus -3.25\p@ \@minus -3.25\p@} + {6.5\p@ \@plus \z@ \@minus 1\p@} + {\normalfont\normalsize\bfseries\itshape\centering}% +} + +\newcommand\subsubsection{% + \@startsection{subsubsection}{3}{\z@} + {-19.5\p@ \@plus -3.25\p@ \@minus -3.25\p@} + {6.5\p@ \@plus \z@ \@minus 1\p@} + {\normalfont\normalsize\itshape\centering}% +} + +\newcommand\paragraph{% + \@startsection{paragraph}{4}{\z@} + {-13\p@ \@plus -1.5\p@ \@minus -1.5\p@} + {-0.5em} + {\normalfont\normalsize\bfseries\raggedright}% +} + +\newcommand\subparagraph{% + \@startsection{subparagraph}{4}{\parindent} + {-13\p@ \@plus -3.25\p@ \@minus -3.25\p@} + {-0.5em} + {\normalfont\normalsize\rmfamily\raggedright}% +} + +\def\@seccntformat#1{\csname the#1\endcsname\hskip5pt}% + +\newcommand\appendixname{Appendix} + +\newcommand\appendix{\par + \@addtoreset{equation}{section}% + \@addtoreset{figure}{section}% + \@addtoreset{table}{section}% + \setcounter{section}\z@ + \renewcommand\thesection{\@Alph\c@section}% + \renewcommand\theequation{\thesection\,\@arabic\c@equation}% + \renewcommand\thefigure{\thesection\,\@arabic\c@figure}% + \renewcommand\thetable{\thesection\,\@arabic\c@table}% +} + +\setcounter{secnumdepth}{3} + +\newcounter{part} +\newcounter{section} +\newcounter{subsection}[section] +\newcounter{subsubsection}[subsection] +\newcounter{paragraph}[subsubsection] +\newcounter{subparagraph}[paragraph] +\renewcommand\thepart {\@arabic\c@part} +\renewcommand\thesection {\@arabic\c@section} +\renewcommand\thesubsection {\thesection.\@arabic\c@subsection} +\renewcommand\thesubsubsection {\thesubsection.\@arabic\c@subsubsection} +\renewcommand\theparagraph {\thesubsubsection.\@arabic\c@paragraph} +\renewcommand\thesubparagraph {\theparagraph.\@arabic\c@subparagraph} + +\newskip\@leftskip \@leftskip=\z@ + +\setlength\leftmargini {13pt} +\setlength\leftmarginii {15.2pt} +\setlength\leftmarginiii {1.5em} +\setlength\leftmarginiv {1.5em} +\setlength\leftmarginv {1em} +\setlength\leftmarginvi {1em} +\setlength\leftmargin {\leftmargini} +\setlength\labelsep {5\p@} +\setlength\labelwidth {\leftmargini} +\addtolength\labelwidth {-\labelsep} + +\newcommand\makeRLlabel[1]{\rlap{#1}\hss} +\newcommand\makeRRlabel[1]{\hss\llap{#1}} + +\def\@listI{\leftmargin\leftmargini\advance\leftmargin11.5pt + \parsep \z@ \topsep 6.5\p@ \@plus 3\p@ \@minus 3\p@ + \itemsep \z@ \@plus 1\p@ \@minus 1\p@ + \let\makelabel\makeRLlabel} + +\def\@listii{\leftmargin\leftmarginii + \labelwidth\leftmarginii + \advance\labelwidth-\labelsep + \topsep 3\p@ \@plus 1\p@ \@minus 1\p@ + \parsep \z@ \itemsep \parsep + \let\makelabel\makeRLlabel} + +\def\@listiii{\leftmargin\leftmarginiii + \labelwidth\leftmarginiii + \advance\labelwidth-\labelsep + \topsep 3\p@ \@plus 1\p@ \@minus 1\p@ + \parsep \z@ \partopsep \z@ + \itemsep \topsep + \let\makelabel\makeRLlabel} + +\def\@listiv{\leftmargin\leftmarginiv + \labelwidth\leftmarginiv + \advance\labelwidth-\labelsep + \let\makelabel\makeRLlabel} + +\def\@listv{\leftmargin\leftmarginv + \labelwidth\leftmarginv + \advance\labelwidth-\labelsep + \let\makelabel\makeRLlabel} + +\def\@listvi{\leftmargin\leftmarginvi + \labelwidth\leftmarginvi + \advance\labelwidth-\labelsep + \let\makelabel\makeRLlabel} + +\let\@listi\@listI +\@listi + +\def\itemize{% FROM LATEX.LTX + \ifnum \@itemdepth >\thr@@ \@toodeep\else + \advance\@itemdepth \@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \expandafter + \list + \csname\@itemitem\endcsname + {\let\makelabel\makeRRlabel\advance\itemindent0pt\advance\leftmargin.5pt}% + \fi +} + +\newif\ifhyphen\global\hyphenfalse + +\newcommand\labelitemi{\ifhyphen \normalfont\bfseries ---\else +$\m@th\bullet$\fi} + +%\newcommand\labelitemi{$\m@th\bullet$} +\newcommand\labelitemii{\normalfont\bfseries ---} +\newcommand\labelitemiii{\normalfont\bfseries --} +\newcommand\labelitemiv{$\m@th\cdot$} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% unnumlist %%%%%%%%%%%%%%%%%%%%%%%%%%%%% TB +% +\def\unnumlistfont{\fontsize{10}{13}\selectfont} + +\newenvironment{unnumlist}{\par% + \unnumlistfont% + \list{}{% + \topsep6pt plus2pt + \itemindent-10pt + \leftmargin10pt + \parsep0pt + \itemsep0pt + \partopsep0pt} + \def\makelable##1{##1}% +}{% + \endlist% +}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% unnumlist %%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\enumerate{% FROM LATEX.LTX + \ifnum \@enumdepth >\thr@@ \@toodeep\else + \advance\@enumdepth \@ne + \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \fi + \@ifnextchar [{\@enumeratetwo}{\@enumerateone}% +} + +\def\@enumerateone{% + \expandafter + \list + \csname label\@enumctr\endcsname + {\usecounter{\@enumctr}% + \let\makelabel\makeRRlabel}% +} + +\def\@enumeratetwo[#1]{% + \expandafter + \list + \csname label\@enumctr\endcsname + {\usecounter{\@enumctr}% + \settowidth\labelwidth{\normalfont\rmfamily #1}% + \itemindent0pt\leftmargin\labelwidth\advance\leftmargin\labelsep\advance\leftmargin13pt + \let\makelabel\makeRRlabel}% +} + +\newcommand\labelenumi {{\normalfont\rmfamily\theenumi.}} +\newcommand\labelenumii {{\normalfont\rmfamily(\theenumii)}} +\newcommand\labelenumiii{{\normalfont\rmfamily\theenumiii}} +\newcommand\labelenumiv {{\normalfont\rmfamily\theenumiv}} + +\renewcommand\theenumi{\@arabic\c@enumi} +\renewcommand\theenumii{\@alph\c@enumii} +\renewcommand\theenumiii{\@roman\c@enumiii} +\renewcommand\theenumiv{\@Alph\c@enumiv} + +\renewcommand\p@enumii{\theenumi} +\renewcommand\p@enumiii{\theenumi(\theenumii)} +\renewcommand\p@enumiv{\p@enumiii\theenumiii} + +\newcommand*\descriptionlabel[1]{\hspace\labelsep \normalfont\bfseries #1} + +\newenvironment{description} + {\list{}{\leftmargin 1em \labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\descriptionlabel}} + {\endlist} + +\newenvironment{verse} + {\let\\=\@centercr + \list{}{\itemsep\z@ + \itemindent -2.5em% + \listparindent \itemindent + \rightmargin\leftmargin + \advance\leftmargin 2.5em}\item[]} + {\endlist} + +\newenvironment{extract} %quotation + {\list{}{\vskip6pt\listparindent\parindent + \topsep6pt\itemindent\listparindent + \leftmargin\z@ \rightmargin\leftmargin + \parsep \z@ \@plus 1\p@}\item[]% + \normalfont\small\rmfamily} + {\endlist} + + +\newenvironment{quote} %quotation + {\par\vskip5pt\itshape\leftskip0pt plus1fill\rightskip0pt plus 0fill} + {\par} + +\newenvironment{qtsource} %quotation source + {\par\leftskip0pt plus1fill\rightskip0pt plus 0fill} + {\par} + +\def\quotespace{\vspace*{6.5pt}} + +\newenvironment{letter} %quotation + {\list{}{\listparindent\z@ + \topsep6pt\itemindent\listparindent + \leftmargin24pt \rightmargin\z@ + \parsep \z@ \@plus 1\p@}\item[]% + \normalfont\itshape} + {\endlist} + + +\newif\ifrembrks +\newcommand\removebrackets{\rembrkstrue} + +\def\@begintheorem#1#2{% FROM LATEX.LTX + \normalfont\rmfamily + \trivlist + \item[\hskip \labelsep{\normalfont\itshape #1\ #2}]% + \item[]% +} + +\def\@opargbegintheorem#1#2#3{% FROM LATEX.LTX + \normalfont\rmfamily + \trivlist + \item[\hskip \labelsep{\normalfont\itshape #1\ #2\ % + \ifrembrks #3\/\global\rembrksfalse\else {\upshape(}#3\/{\upshape)}\fi}]% + \item[]% +} + +\newsavebox{\proofsavebox} + + +%% \newtheorem{lemma}{Lemma}[section] +%% \newtheorem{example}{Example}[section] +%% \newtheorem{theorem}{Theorem}[section] +%% \newtheorem{definition}{Definition}[section] +%% \newtheorem{corollary}{Corollary}[section] + + + \sbox{\proofsavebox} + {\unitlength 1pt\begin{picture}(6.5,6.5)% + \put(0,0){\framebox(6.5,6.5){}}\end{picture}} + \newcommand\proofbox{\usebox{\proofsavebox}\relax} + +\newcommand\mathproofbox{\rlap{\quad\proofbox}} + +\def\@nprf{\normalfont\rmfamily \trivlist + \item[\hskip \labelsep {\normalfont\itshape Proof}]% + \item[]} + +\def\@oprf[#1]{\normalfont\rmfamily \trivlist + \item[\hskip \labelsep {\normalfont\itshape #1\ }]% + \item[]} + +\newenvironment{proof} + {\@ifnextchar[{\@oprf}{\@nprf}} + {\hspace*{15pt}\hbox{\proofbox}\endtrivlist} + +\newenvironment{proof*} + {\proof} + {\endtrivlist} + +\renewcommand\theequation{\@arabic\c@equation} + +\setlength\arraycolsep{5\p@} +\setlength\tabcolsep{0\p@} +\setlength\arrayrulewidth{.5\p@} +\setlength\doublerulesep{1.5\p@} +\setlength\tabbingsep{\labelsep} +\setlength{\skip\@mpfootins}{\skip\footins} +\setlength\fboxsep{3\p@} +\setlength\fboxrule{.5\p@} + +\newcommand\maketitle{\@ifnextchar [{\m@ketitleone}{\m@ketitleone[n]}} + +\def\m@ketitleone[#1]{\par + \begingroup + \newpage + \global\@topnum\z@ + \titlefntrue + \def\thefootnote{\@fnsymbol\c@footnote}% + \def\@makefnmark{\hbox{$\@thefnmark$}}% + \@maketitle{#1}% + \thispagestyle{titlepage}\@thanks + \endgroup + \global\let\@maketitle\relax + \global\let\@thanks\@empty + \global\let\@title\@empty + \global\let\@author\@empty + \global\let\maketitle\relax + \global\let\thanks\relax + \setcounter{footnote}\z@ +} + +\def\pe@rl#1{% + \if t#1 {\tpe@rl}\else + \if T#1 {\Tpe@rl}\else + \if f#1 {\fpe@rl}\else + \if F#1 {\Fpe@rl}\else + \if e#1 {\edpe@rl}\else + \if E#1 {\Edpe@rl}\else + \if o#1 {\otherpearl}\else + \vspace*{32\p@}% + \fi + \fi + \fi + \fi + \fi + \fi + \fi +} +% +\newenvironment{bookrevauthor}{\par\vskip5pt\noindent\ignorespaces}{\par} + +\def\bookreventryfont{\fontsize{10}{13}\selectfont} +\newenvironment{bookreventry}{\par\bookreventryfont\noindent\leftskip18pt\rightskip18pt\ignorespaces}{\vskip7pt\@endparenv\@ignoretrue} +\newenvironment{question}{\par\vskip6.5pt\tablefont\noindent\ignorespaces}{\vskip6.5pt\@endparenv\@ignoretrue} +% +\def\spe@rl{\vspace*{32\p@}\normalfont\LARGE\rmfamily} +\def\epe@rl#1{\par\vspace*{6.5\p@}\xdef\@shorttitle{#1}} + +\def\tpe@rl{\spe@rl T\ls H\ls E\ls O\ls R\ls E\ls T\ls + I\ls C\ls A\ls L\ns P\ls E\ls A\ls R\ls L\ls S% + \epe@rl{Theoretical pearls}% +} + +\def\Tpe@rl{\spe@rl T\ls H\ls E\ls O\ls R\ls E\ls T\ls + I\ls C\ls A\ls L\ns P\ls E\ls A\ls R\ls L% + \epe@rl{Theoretical pearl}% +} + +\def\fpe@rl{\spe@rl F\ls U\ls N\ls C\ls T\ls I\ls O\ls + N\ls A\ls L\ns P\ls E\ls A\ls R\ls L\ls S% + \epe@rl{Functional pearls}% +} + +\def\Fpe@rl{\spe@rl F\ls U\ls N\ls C\ls T\ls I\ls O\ls + N\ls A\ls L\ns P\ls E\ls A\ls R\ls L% + \epe@rl{Functional pearl}% +} + +\def\edpe@rl{\spe@rl E\ls D\ls U\ls C\ls A\ls T\ls I\ls O\ls N\ls A\ls L\ns + P\ls E\ls A\ls R\ls L\ls S% + \epe@rl{Educational pearls}% +} + +\def\Edpe@rl{\spe@rl E\ls D\ls U\ls C\ls A\ls T\ls I\ls O\ls N\ls A\ls L\ns + P\ls E\ls A\ls R\ls L% + \epe@rl{Educational pearl}% +} + +\def\otherpearl{\spe@rl + \@ifundefined{othrpearl} + {Please define {\normalfont\ttfamily\char92 othrpearl} to obtain\\ the correct title!} + {\othrpearl}% + \epe@rl{Short title--please redefine with {\normalfont\ttfamily\char92 shorttitle}}% +} + +\def\authormark#1{\xdef\@authormark{#1}} + +\def\author{\@ifnextchar [{\@authortwo}{\@authorone}} +\def\@authortwo[#1]#2{\@author{#2}\xdef\@authormark{#1}} +\def\@authorone#1{\@author{#1}\xdef\@authormark{#1}} +% +%\def\@author#1{\global\advance\authorcount by 1 +% \expandafter\xdef\csname author\romannumeral\the\authorcount\endcsname{#1}\affil{}} +% +\def\@author#1{\global\advance\authorcount by 1 + \expandafter\gdef\csname author\romannumeral\the\authorcount\endcsname{#1}} +% +\def\affil#1{\expandafter\gdef\csname affil\romannumeral\the\authorcount\endcsname{#1}} +\def\email#1{\expandafter\gdef\csname email\romannumeral\the\authorcount\endcsname{\normalfont\rmfamily + \itshape\textup{(}e-mail: \textup{\texttt{#1})}}} +% +\def\and{{\reset@font and}} +% +\def\authorsep{\unskip, } +\newcount\authorcount\authorcount=0 +\newcount\tempcount +\newcount\authortempcount +% +\def\@authors{% + \ifnum\authorcount>0% %%%% Authors available + \tempcount=1% + \loop% + \ifnum\authorcount>0% + \noindent{\reset@font\authorsize\csname author\romannumeral\the\tempcount \endcsname}\par\vskip3pt% + \noindent{\baselineskip10pt\normalfont\reset@font\affilsize\itshape\csname affil\romannumeral\the\tempcount \endcsname\par}% + \noindent{\baselineskip10pt\normalfont\affilsize\itshape\csname email\romannumeral\the\tempcount \endcsname\par}% +% \ifnum\authorcount>1\ifnum\authorcount>2\ \else \ \and\ \fi\fi% + \global\advance\authorcount by -1% + \advance\tempcount by 1 % + \vskip7pt + \repeat + \global\authortempcount\tempcount + \fi}% +% +\def\spchapter{\@ifnextchar[{\@@spchapter}{\@@spchapter[]}} + +\def\@@spchapter[#1]#2{\gdef\@spchapter{#2}} +\spchapter{} +% +\ifindex + \def\@maketitle#1{\cleardoublepage\bgroup% + {\vspace*{18pt}\indexheadfont +\indexname\par}\vskip43pt + \egroup + }% +\else +\def\@maketitle#1{% + \newpage\null + \ifbookreview\vskip-29pt\else\vskip-25\p@\fi% + {\centering \sloppy + \pe@rl{#1}% + \ifsptitle + \ifx\@spchapetr\@empty\else{\spchapterfont\@spchapter}\par\vskip7pt\fi% + \else + \ifsplissue + \ifx\@spchapetr\@empty\else{\splissuefont\@spchapter}\par\fi% + \else + \fi + \fi + {\normalfont\LARGE\itshape \@title\par}% + \ifx\@subtitle\@empty% + \else% + \vskip8pt% + {\subtitlefont \@subtitle\par}% +% \vskip4pt% + \fi% + \vskip 16\p@ + {% + \@authors + \par}% + }% + \ifsptitle\vspace*{-4\p@}\else\vskip 13.5\p@ \fi\ifbookreview\vskip26.5pt\fi%\@plus 2\p@ \@minus 1\p@ +} +\fi +\def\abs@header#1{% + \vbox{\hrule \@height .25pt \@width30.05pc + \vskip 8\p@ \@plus 3\p@ \@minus 1\p@ + \centerline{\normalfont\normalsize\bfseries #1}}% +} + +\def\abs@body{% + \list{}{\leftmargin\z@ \rightmargin\leftmargin + \listparindent 1em \parsep \z@ \@plus 1\p@ + \topsep 8\p@ %\@plus 3\p@ \@minus 1\p@ + }% + \item[]\normalfont\small\rmfamily +} + +\newcommand\abstractname{Abstract} +\newenvironment{abstract} + {\ifsptitle\vspace*{17.3\p@}\else\fi\abs@header{\abstractname}\abs@body} + {\endlist\vbox{\hrule \@height .25pt \@width 30.05pc}% + \gdef\abs@header##1{\vskip 2\p@ + \centerline{\normalfont\normalsize\bfseries ##1}}} + +\newcommand\capsulename{Capsule Review} +\newenvironment{capsule} + {\abs@header{\capsulename}\abs@body} + {\endabstract} + + +\mark{{}{}} + +\newcommand\shortauthor[1]{\gdef\@shortauthor{#1}} +\gdef\@shortauthor{} + +\renewcommand\title{\@ifnextchar [{\@titletwo}{\@titleone}} +\def\@titleone#1{\gdef\@title{#1}\xdef\@shorttitle{#1}} +\def\@titletwo[#1]#2{\gdef\@title{#2}\xdef\@shorttitle{#1}} +\gdef\@title{\mbox{}} + +\newcommand\subtitle[1]{\xdef\@subtitle{#1}} +\subtitle{} + +\newcommand\shorttitle[1]{\xdef\@shorttitle{#1}} + +\newcommand\volume[1]{\gdef\@volume{#1}} +\gdef\@volume{{\normalfont\bfseries 1} (1):} + +\newcommand\pagerange[1]{\gdef\@pagerange{#1}} +\gdef\@pagerange{1--000} + +\newcommand\pubyear[1]{\gdef\@year{#1}} +\gdef\@year{19XX} + +\newcommand\jdate[1]{\gdef\@jdate{#1}} +\gdef\@jdate{January \@year} + +\newcommand\doi[1]{\gdef\@doi{10.1017/#1}} +\gdef\@doi{10.1017/S0000000000000000} + +%% TB + +\def\Copyright{\raise.2pt\hbox{\fontsize{8}{8}\selectfont\ooalign{\hfil\raise.9pt\hbox{\hskip-.3pt{\normalfont\fontsize{7.5}{7.5}\selectfont +c}}% + \hfil\crcr\mathhexbox20D}}} + +\newcommand\journal[1]{\gdef\@journal{#1}} +% +\def\pubonline#1{\gdef\@pubonline{#1}} +\def\@pubonline{} +% +\ifonline + \def\@journal{% + \vbox to 8.6\p@{\noindent\parbox[t]{4.8in}{\normalfont\onlineaffilsize\rmfamily + {\itshape JFP\/}\ {\bf \@volume}\ (\@issue):\ \ifonepage\thepage\else\thepage--\pageref{lastpage}\fi* % + (First pubd online \@cpyyear)\hskip5pt \Copyright\ + \@cpyyear\ Cambridge University Press\ doi:\@doi\\[2\p@] + *Provisional -- final page numbers to be inserted when paper edition is published}% published + \vss}} +\else + \ifincremental + \def\@journal{% + \vbox to 8.6\p@{\noindent\parbox[t]{4.8in}{\sluglinefont% + {\it JFP\kern-1pt{:}\/}\ page \ifonepage\thepage\else\thepage\ of\ \pageref{lastpage}\fi.\hskip7.5pt % + \Copyright\ \@cpyyear\ Cambridge University Press\\[2\p@] + doi:\@doi}% + \vss}}% +\else + \def\@journal{% + \vbox to 8.6\p@{\noindent\parbox[t]{4.8in}{\sluglinefont% + {\itshape JFP\/}\ {\bf \@volume}\ (\@issue):\ \ifonepage\thepage\else\thepage--\pageref{lastpage}\fi, % + \@pubyear.\hskip7.5pt \Copyright\ + \@cpyyear\ Cambridge University Press\\[2\p@] + doi:\@doi\hskip5pt \ifx\@pubonline\empty\else First published online \@pubonline\fi\hskip5pt {Printed in the United Kingdom}}%{Printed in the United Kingdom}}% + \vss}% +} +\fi\fi + +\def\@underjournal{% + \vbox to 5.6\p@{\noindent\parbox[t]{4.8in}{\normalfont\affilsize\rmfamily + {\itshape Under consideration for publication in + J.\ Functional Programming\/}\\[2.5\p@] + \ }% + \vss}% +} +%% +\def\bookrevmark#1{\gdef\@bookrevmark{#1}} +\bookrevmark{Book review} +% +\def\rhfont{\fontsize{11}{11}\selectfont} +%% +\def\ps@headings{\let\@mkboth\markboth + \def\@oddhead{\hfil{\ifbookreview\fontsize{10}{13}\selectfont\fi\itshape\@shorttitle}\hfil \llap{\rhfont\thepage}}% + \def\@evenhead{\rlap{\rhfont\thepage}\hfil\ifbookreview{\fontsize{10}{13}\selectfont\itshape\@bookrevmark}\else\itshape\@authormark\fi\hfil}% + \let\@oddfoot\@empty + \let\@evenfoot\@oddfoot + \def\sectionmark##1{\markboth{##1}{}}% + \def\subsectionmark##1{\markright{##1}}% +} + +\def\ps@Empty{% + \def\@oddfoot{}% + \let\@evenfoot\@oddfoot + \def\@evenhead{}% + \def\@oddhead{}% + \let\@mkboth\markboth + \let\chaptermark\@gobble + \let\sectionmark\@gobble% +} + +\def\ps@myheadings{\let\@mkboth\@gobbletwo + \def\@oddhead{\hfil{\itshape\rightmark}\hfil \llap{\rhfont\thepage}}% + \def\@evenhead{\rlap{\rhfont\thepage}\hfil\itshape\leftmark\hfil}% + \let\@oddfoot\@empty + \let\@evenfoot\@oddfoot + \let\sectionmark\@gobble + \let\subsectionmark\@gobble +} + +\def\@indjournal{% + \vbox to 6.5\p@{\noindent\parbox[t]{4.8in}{\normalfont\affilsize\rmfamily + {\itshape J. Functional Programming\/}\ {\bf \@volume}\ (\@issue):\ +\thepage--\pageref{lastpage}, \@pubyear\hskip7.5pt {Printed in +United Kingdom}}% + \vss}% +} + +\ifprodtf + \let\@j@urnal\@journal +\else + \let\@j@urnal\@underjournal +\fi + +\def\ps@titlepage{\leftskip\z@ \let\@mkboth\@gobbletwo + \def\@oddhead{\ifindex\@indjournal +\hfil\hbox{\llap{\rhfont\thepage}}\else\@j@urnal \hfil\raise1.6pt\hbox{\llap{\rhfont\thepage}}\fi}% + \let\@evenhead\@oddhead + \let\@oddfoot\@empty + \let\@evenfoot\@oddfoot + \let\sectionmark\@gobble + \let\subsectionmark\@gobble +} + +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{2} + +\def\@dottedtocline#1#2#3#4#5{% FROM LATEX.LTX + \ifnum #1>\c@tocdepth \else + \vskip \z@ \@plus.2\p@ + {\leftskip #2\relax \rightskip \@tocrmarg \parfillskip -\rightskip + \parindent #2\relax\@afterindenttrue + \interlinepenalty\@M + \leavevmode + \@tempdima #3\relax + \advance\leftskip \@tempdima \null\hskip -\leftskip + {#4}\nobreak + \leaders\hbox{$\m@th + \mkern \@dotsep mu\hbox{\phantom{.}}\mkern \@dotsep + mu$}\hfill + \nobreak + \hb@xt@\@pnumwidth{\hfil\normalfont \normalcolor #5}% + \par}% + \fi} + +\newcommand\contentsname{Contents} + +\newcommand\tableofcontents{% + \section*{\contentsname}% + \@starttoc{toc}\par + \vspace{13\p@}% +} + +\newcommand*\l@part[2]{% + \ifnum \c@tocdepth >-2\relax + \addpenalty{-\@highpenalty}% + \addvspace{.5\baselineskip \@plus 1\p@}% + \begingroup + \parindent \z@ \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + {\leavevmode + \normalfont\rmfamily + #1\hfil \hb@xt@\@pnumwidth{\hfil}}\par + \nobreak + \if@compatibility + \global\@nobreaktrue + \everypar{\global\@nobreakfalse\everypar{}}% + \fi + \endgroup + \vskip .25\baselineskip \@plus 1\p@ + \fi +} + +\newcommand*\l@section[2]{% + \ifnum \c@tocdepth >\z@ + \addpenalty\@secpenalty + \setlength\@tempdima{1.5em}% + \begingroup + \parindent \z@ \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + \leavevmode \normalfont\rmfamily + \advance\leftskip\@tempdima + \hskip -\leftskip + {\bfseries #1}\nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss #2}\par + \endgroup + \fi} + +\newcommand*\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\newcommand*\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\newcommand*\l@paragraph{\@dottedtocline{4}{7.0em}{4.1em}} +\newcommand*\l@subparagraph{\@dottedtocline{5}{10em}{5em}} + +\newcommand\listfigurename{List of Figures} +\newcommand\listoffigures{% + \section*{\listfigurename}% + \@starttoc{lof}\par + \vskip 13\p@ +} + +\newcommand*\l@figure{\@dottedtocline{1}{1.5em}{2.3em}} + +\newcommand\listtablename{List of Tables} +\newcommand\listoftables{% + \section*{\listtablename}% + \@starttoc{lot}\par + \vskip 13\p@ +} + +\let\l@table\l@figure + +\renewcommand\footnoterule{% + \kern-3\p@ + \hrule \@width .4\columnwidth height \z@ + \kern 3\p@} + +\newif\iftitlefn + +%% +\newbox\tempbox +\newdimen\@footmax +\def\footmax#1{% + \setbox\tempbox\hbox{\footnotesize$^{#1}$}% + \global\@footmax\wd\tempbox\global\advance\@footmax.5em} +% +\footmax{0} +%% +\newcommand\@makefntext[1]{% + \leavevmode\@hangfrom{\hb@xt@ \@footmax{\hss$\iftitlefn\else^\fi{\@thefnmark}\hskip.5em$}}#1} +%% + +\ifprodtf \else \let\highast\ast\fi + +\def\@fnsymbol#1{\ensuremath{% FROM LATEX.LTX + \ifcase#1\or \hbox{$\highast$}\or \dagger\or \ddagger\or + \mathchar "278\or \mathchar "27B\or \|\or \hbox{$\highast\highast$}\or + \dagger\dagger\or \ddagger\ddagger\or \mathchar "278\mathchar "278\or + \mathchar "27B\mathchar "27B\or \|\|\or \else\@ctrerr\fi}% +} + +\renewcommand\@makefnmark{\hbox{$^{\@thefnmark}$}}% FROM LATEX.LTX +\renewcommand\thefootnote{\@arabic\c@footnote}% FROM LATEX.LTX +\renewcommand\thempfootnote{\mathit{\@alph\c@mpfootnote}}% FROM LATEX.LTX + +\setcounter{topnumber}{2} +\renewcommand\topfraction{.9} +\setcounter{bottomnumber}{1} +\renewcommand\bottomfraction{.9} +\setcounter{totalnumber}{3} +\renewcommand\textfraction{.1} +\renewcommand\floatpagefraction{.9} +\setcounter{dbltopnumber}{2} +\renewcommand\dbltopfraction{.9} +\renewcommand\dblfloatpagefraction{.5} + +\newcounter{table} +\renewcommand\thetable{\@arabic\c@table} +\def\fps@table{tbp} +\def\ftype@table{1} +\def\ext@table{lot} +\newcommand\tablename{Table} +\def\fnum@table{\tablename\ \thetable} + +\newenvironment{table} + {\@float{table}} + {\end@float} + +\newenvironment{table*} + {\@dblfloat{table}} + {\end@dblfloat} + +\def\fstyle@table{\normalfont\small\rmfamily} +\def\fjust@table{\centering} +\def\fcapjust@table{\centering} +\def\fcapsize@table{\normalfont\normalsize\rmfamily} +\def\fcapstyle@table{\normalfont\normalsize\itshape} + +\newcommand\contname{(cont.)} +\newcommand\continuedfigure{% + \addtocounter{figure}\m@ne + \let\curr@thefigure\thefigure + \def\thefigure{\curr@thefigure\ \contname}% +} + +\newcommand\continuedtable{% + \addtocounter{table}\m@ne + \let\curr@thetable\thetable + \def\thetable{\curr@thetable\ \contname}% +} + +\newif\ifrem@fullpt +\newcommand\removefullpoint{\global\rem@fullpttrue} + +\newif\ifbot@fig +\newenvironment{bottomfigure}{\def\fps@figure{b}% + \setcounter{bottomnumber}{1}% + \global\bot@figtrue + \@float{figure}\fstyle@figure} + {\end@float} + +\newbox\@tempboxb + +\def\enskip{\hskip4.5pt} +\long\def\@makecaption#1#2{% + \ifbot@fig \rule{30.05pc}{.25\p@}\fi + \vskip 0\p@ %\@plus .4\p@ \@minus .4\p@ + \begingroup + \setbox\@tempboxb\hbox{#2}% + \def\@xtra{\ifdim\wd\@tempboxb>\z@ \ifrem@fullpt\else .\enskip\fi\fi}% + \setbox\@tempboxa\hbox{#1\@xtra #2}% + \ifdim\wd\@tempboxa>\tw@\textwidth + {\let\centering\relax #1\@xtra #2\par}% + \else + #1\@xtra #2\par + \fi + \endgroup + \global\bot@figfalse + \global\rem@fullptfalse +} + +\newcounter{figure} +\renewcommand\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{2} +\def\ext@figure{lof} +\newcommand\figurename{Fig.} +\def\fnum@figure{\figurename\ \thefigure} + +\newenvironment{figure} + {\@float{figure}} + {\end@float} + +\newenvironment{figure*} + {\@dblfloat{figure}} + {\end@dblfloat} + +\def\fstyle@figure{\normalfont\small\rmfamily} +\def\fjust@figure{\centering} +\def\fcapjust@figure{\centering} +\def\fcapsize@figure{\normalfont\small\rmfamily} +\def\fcapstyle@figure{\normalfont\small\rmfamily} + +\long\def\@caption#1[#2]#3{% FROM LATEX.LTX + \par + \addcontentsline{\csname ext@#1\endcsname}{#1}% + {\protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}}% + \begingroup + \@parboxrestore + \if@minipage + \@setminipage + \fi + \normalsize + \@makecaption{\csname fcapjust@#1\endcsname + \csname fcapsize@#1\endcsname + \csname fnum@#1\endcsname}% + {\csname fcapstyle@#1\endcsname \ignorespaces #3}\par + \endgroup +} + +\def\@xfloat #1[#2]{% FROM LATEX.LTX + \@nodocument + \def\@captype {#1}% + \def\@fps {#2}% + \@onelevel@sanitize \@fps + \def \reserved@b {!}% + \ifx \reserved@b \@fps + \@fpsadddefault + \else + \ifx \@fps \@empty + \@fpsadddefault + \fi + \fi + \ifhmode + \@bsphack + \@floatpenalty-\@Mii + \else + \@floatpenalty-\@Miii + \fi + \ifinner + \@parmoderr\@floatpenalty\z@ + \else + \@next\@currbox\@freelist + {% + \@tempcnta \sixt@@n + \expandafter \@tfor \expandafter \reserved@a + \expandafter :\expandafter =\@fps + \do + {% + \if \reserved@a h% + \ifodd \@tempcnta + \else + \advance \@tempcnta \@ne + \fi + \fi + \if \reserved@a t% + \@setfpsbit \tw@ + \fi + \if \reserved@a b% + \@setfpsbit 4% + \fi + \if \reserved@a p% + \@setfpsbit 8% + \fi + \if \reserved@a !% + \ifnum \@tempcnta>15 + \advance\@tempcnta -\sixt@@n\relax + \fi + \fi + }% + \@tempcntb \csname ftype@\@captype \endcsname + \multiply \@tempcntb \@xxxii + \advance \@tempcnta \@tempcntb + \global \count\@currbox \@tempcnta + }% + \@fltovf + \fi + \global \setbox\@currbox + \color@vbox + \normalcolor + \vbox \bgroup + \hsize\columnwidth + \@parboxrestore + \@floatboxreset + \csname fstyle@\@captype\endcsname + \csname fjust@\@captype\endcsname +} + +\let\oldtabular\tabular +\let\endoldtabular\endtabular + +\def\tabular{% FROM LATEX.LTX + \def\@halignto{to \textwidth}\tabskip\tabcolsep \@plus 1fil\@ttabular +} + +\def\@ttabular{\leavevmode \hbox \bgroup $\let\@acol\@tabacol + \let\@classz\@tabclassz + \let\@classiv\@tabclassiv \let\\\@tabularcr\@ttabarray} + +\def\@ttabarray{\m@th\@ifnextchar[\@tarray{\@ttarray}} + +\def\@tarray[#1]#2{\t@barray[#1]{@{\tabskip\tw@\tabcolsep \@plus 3\p@}#2}} +\def\@ttarray#1{\t@barray[c]{@{\tabskip\tw@\tabcolsep \@plus 3\p@}#1}} + +\def\t@barray[#1]#2{% + \if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi + \bgroup + \setbox\@arstrutbox\hbox{% + \vrule \@height\arraystretch\ht\strutbox + \@depth\arraystretch \dp\strutbox + \@width\z@}% + \@mkpream{#2}% + \edef\@preamble{% + \halign \noexpand\@halignto + \bgroup \tabskip\z@skip \@arstrut \@preamble \tabskip\tabcolsep \@plus 1fil\cr}% + \let\@startpbox\@@startpbox \let\@endpbox\@@endpbox + \let\tabularnewline\\% + \let\par\@empty + \let\@sharp##% + \set@typeset@protect + \lineskip\z@skip\baselineskip\z@skip + \@preamble} + +\newcommand\ls{\kern.15em\relax} +\newcommand\ns{\kern.55em\relax} + +\def\hline{% FROM LATEX.LTX + \noalign{\ifnum0=`}\fi \vskip 6\p@ + \hrule \@height \arrayrulewidth \vskip 6\p@ + \futurelet \reserved@a\@xhline} + +\def\@xhline{% FROM LATEX.LTX + \ifx\reserved@a\hline + \vskip -12\p@ + \vskip\doublerulesep + \fi + \ifnum0=`{\fi}} + +\newcommand\today{} +\edef\today{\number\day\ \ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December + \fi \ \number\year} + +\renewcommand\@biblabel[1]{}% FROM LATEX.LTX +\newcommand\newblock{\hskip .11em \@plus .33em \@minus .07em} + +\newcommand\refname{References} +\newenvironment{thebibliography}[1] + {\section*{\refname}% + \normalfont\small\rmfamily + \addcontentsline{toc}{section}{\refname}% + \list{}{\usecounter{enumiv}\labelwidth\z@ \leftmargin 9pt \itemindent -9pt}% + \parindent\z@ + \parskip 2\p@ \@plus .1\p@ + \sloppy\clubpenalty\z@ \widowpenalty\@M + \sfcode`\.\@m\relax} + {\def\@noitemerr + {\@latex@warning{Empty `thebibliography' environment}}% + \endlist} +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End Bibliography Section %%%%%%%%%%%%%%%% +\def\@citex[#1]#2{% FROM LATEX.LTX + \let\@citea\@empty + \@cite{\@for\@citeb:=#2\do + {\@citea\def\@citea{; }% + \edef\@citeb{\expandafter\@firstofone\@citeb}% + \if@filesw\immediate\write\@auxout{\string\citation{\@citeb}}\fi + \@ifundefined{b@\@citeb}{\mbox{\reset@font\bfseries ?}% + \G@refundefinedtrue + \@latex@warning + {Citation `\@citeb' on page \thepage \space undefined}}% + {\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{{\if@tempswa #2\else (#1)\fi}}% FROM LATEX.LTX + +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\DeclareRobustCommand\shortcite{\def\citename##1{}\@internalcite} + +\newif\iffontfound +\newcommand\checkfont[1]{% + \batchmode + \font\test=#1\relax + \errorstopmode + \fontfoundfalse + \ifx\test\nullfont \else \fontfoundtrue\fi +} +%%%%%%%%%%% +% +\def\ct@indenttext#1{\parindent24pt{\par\hangindent48pt #1\par}} +\def\ct@Indenttext#1{\parindent48pt{\par\hangindent48pt #1\par}} +% +% +% +\newcount\minute +\newcount\hour +\def\currenttime{% + \minute\time + \hour\minute + \divide\hour60 + \the\hour:\multiply\hour60\advance\minute-\hour\the\minute} +%%%%% +\def\gray{\special{color CMYK 0 0 0 0.5}} +\def\@questionmark{\vbox to 0pt{\vskip13pc\hskip-5pc + \hbox to \textwidth{\special{color push}\gray\fontsize{270}{270}\selectfont ? + \special{color pop}\hss}}} +\def\questionmark#1{\xdef\@questionmark{#1}}% +% +\def\@TotalChars{} +\def\TotalChars#1{\xdef\@TotalChars{#1}}% +%% +\def\document{\endgroup + \ifx\@unusedoptionlist\@empty\else + \@latex@warning@no@line{Unused global option(s):^^J% + \@spaces[\@unusedoptionlist]}% + \fi + \@colht\textheight + \@colroom\textheight \vsize\textheight + \columnwidth\textwidth + \@clubpenalty\clubpenalty + \if@twocolumn + \advance\columnwidth -\columnsep + \divide\columnwidth\tw@ \hsize\columnwidth \@firstcolumntrue + \fi + \hsize\columnwidth \linewidth\hsize + \begingroup\@floatplacement\@dblfloatplacement + \makeatletter\let\@writefile\@gobbletwo + \global \let \@multiplelabels \relax + \@input{\jobname.aux}% + \endgroup + \if@filesw + \immediate\openout\@mainaux=\jobname.aux + \immediate\write\@mainaux{\relax} + \fi + \process@table + \let\glb@currsize\@empty %% Force math initialization. + \normalsize + \everypar{}% + \ifx\normalsfcodes\@empty + \ifnum\sfcode`\.=\@m + \let\normalsfcodes\frenchspacing + \else + \let\normalsfcodes\nonfrenchspacing + \fi + \fi + \@noskipsecfalse + \let \@refundefined \relax + \let\AtBeginDocument\@firstofone + \@begindocumenthook + \ifdim\topskip<1sp\global\topskip 1sp\relax\fi + \global\@maxdepth\maxdepth + \global\let\@begindocumenthook\@undefined + \ifx\@listfiles\@undefined + \global\let\@filelist\relax + \global\let\@addtofilelist\@gobble + \fi + \gdef\do##1{\global\let ##1\@notprerr}% + \@preamblecmds + \global\let \@nodocument \relax + \global\let\do\noexpand + \ignorespaces} +% +%% +\def\enddocument{\label{lastpage}% + \@checkend{document}% + \@enddocumenthook + \ifodd\c@page\cleardoublepage\else\clearpage\fi + \begingroup + \if@filesw + \immediate\write\@mainaux{\string\questionmark{}}% + \immediate\closeout\@mainaux + \let\@setckpt\@gobbletwo + \let\@newl@bel\@testdef + \@tempswafalse + \makeatletter + \catcode`\\0 + \catcode`\{1 + \catcode`\}2 + \catcode`\^=7 + \catcode`\_=8 + \catcode`\&=4 + \catcode`\$=3 + \catcode`\@11 + \catcode`\#6 + \catcode`\"=12 + \input\jobname.aux + \fi + \@dofilelist + \ifdim \font@submax >\fontsubfuzz\relax + \@font@warning{Size substitutions with differences\MessageBreak + up to \font@submax\space have occured.\@gobbletwo}% + \fi + \@defaultsubs + \@refundefined + \if@filesw + \ifx \@multiplelabels \relax + \if@tempswa + \@latex@warning@no@line{Label(s) may have changed. + Rerun to get cross-references right}% + \fi + \else + \@multiplelabels + \fi + \fi + \endgroup + \deadcycles\z@\@@end} +%% +\def\@outputpage{% +\begingroup % the \endgroup is put in by \aftergroup + \let \protect \noexpand + \@resetactivechars + \@parboxrestore + \shipout \vbox{% + \set@typeset@protect + \aftergroup \endgroup + \aftergroup \set@typeset@protect + % correct? or just restore by ending + % the group? + \if@specialpage + \global\@specialpagefalse\@nameuse{ps@\@specialstyle}% + \fi + \if@twoside + \ifodd\count\z@ \let\@thehead\@oddhead \let\@thefoot\@oddfoot + \let\@themargin\oddsidemargin + \else \let\@thehead\@evenhead + \let\@thefoot\@evenfoot \let\@themargin\evensidemargin + \fi + \fi + \reset@font + \normalsize + \normalsfcodes + \let\label\@gobble + \let\index\@gobble + \let\glossary\@gobble + \baselineskip\z@skip \lineskip\z@skip \lineskiplimit\z@ + \@begindvi\trimmarks + \vskip \topmargin + \moveright\@themargin \vbox {% + \setbox\@tempboxa \vbox to\headheight{% + \vfil + \color@hbox + \normalcolor + \hb@xt@\textwidth{\@thehead}% + \color@endbox + }% %% 22 Feb 87 + \dp\@tempboxa \z@ + \box\@tempboxa + \vskip \headsep + \box\@outputbox + \baselineskip \footskip + \color@hbox + \normalcolor + \hb@xt@\textwidth{\@thefoot}% + \color@endbox + }% + }% + \global \@colht \textheight + \stepcounter{page}% + \let\firstmark\botmark + \ifodd\c@page + \ifspreadlong\global\spreadlongfalse + \enlargethispage{\@spreadlong}\fi + \fi +} +%%%%% +\newif\ifspreadlong +\def\spreadlong#1{\ifodd\c@page\wlog{Ignoring spreadlong} + \else + \spreadlongtrue\gdef\@spreadlong{#1}% + \enlargethispage{#1}% + \fi} +% check specs and enable one or both of these commands +\def\leaflong#1{\enlargethispage{#1}} +%%%%% +\def\trimmarks{% + \vbox to 0pt{% + \vskip-25pt\parindent0pt + \draftnote\offinterlineskip}% + \ifdraft + \vbox to 0pt{\hsize\trimwidth\offinterlineskip + \parindent0pt\leftskip0pt\rightskip0pt + \fboxsep0pt\fboxrule\draftrule + \fbox{\vbox{\vskip\trimheight\hskip\trimwidth}}}% +% + \vbox to 0pt{\hsize\trimwidth\offinterlineskip + \parindent0pt\leftskip0pt\rightskip0pt + \vbox to \trimheight{\offinterlineskip\parindent0pt + \hbox to \trimwidth{\vbox to 2pc{\vskip-3.5pc\hbox{\vrule height2pc width\trimrule}}\raisebox{2pc}{\hbox{\hskip-3.5pc\vrule width2pc height\trimrule}}\hfill + \raisebox{2pc}{\vrule width2pc height\trimrule\hskip-3.75pc} + \vbox to 2pc{\vskip-3.5pc\hbox{\vrule height2pc width\trimrule}}% + }\vfill + \hbox to \trimwidth{\hbox{\hskip-3.5pc\vrule height\trimrule width2pc}\vbox to 3pc{\vspace*{4.5pc}\hbox{\hskip1.5pc\vrule width\trimrule height2pc}}\hfill + \vbox to 3.5pc{\vskip5pc\hbox{\vrule height2pc width\trimrule}}\rlap{\hskip1.5pc\vrule width2pc height\trimrule}}}}% +% + \else + \vbox to 0pt{\hsize\trimwidth\offinterlineskip + \parindent0pt\leftskip0pt\rightskip0pt + \vbox to \trimheight{\offinterlineskip\parindent0pt + \hbox to \trimwidth{\vbox to 2pc{\vskip-3.5pc\hbox{\vrule height2pc width\trimrule}}\raisebox{2pc}{\hbox{\hskip-3.5pc\vrule width2pc height\trimrule}}\hfill + \raisebox{2pc}{\vrule width2pc height\trimrule\hskip-3.75pc} + \vbox to 2pc{\vskip-3.5pc\hbox{\vrule height2pc width\trimrule}}% + }\vfill + \hbox to \trimwidth{\hbox{\hskip-3.5pc\vrule height\trimrule width2pc}\vbox to 3pc{\vspace*{4.5pc}\hbox{\hskip1.5pc\vrule width\trimrule height2pc}}\hfill + \vbox to 3.5pc{\vskip5pc\hbox{\vrule height2pc width\trimrule}}\rlap{\hskip1.5pc\vrule width2pc height\trimrule}}}} +\fi +\insidedraftrules} +% +\def\insidedraftrules{\overfullrule0pt\leftskip0pt\rightskip0pt\vbox to 0pt{% + \offinterlineskip\parindent0pt + \vskip \topmargin + \tempdimen\normaltextheight + \advance\tempdimen\headheight + \advance\tempdimen\headsep + \moveright\@themargin + \vbox{\vbox to 0pt{\vskip\headheight\vskip\headsep\vskip.2pt + \vrule height\draftrule width\textwidth + } + \hbox{\fboxsep0pt\fboxrule\draftrule + \fbox{\vbox to \tempdimen + {\hsize\textwidth\hskip\textwidth}}}}}}% +% + +%% +%% +\usepackage{rotating} +%% +\ifprinter + \def\draftnote{} + \def\Qauthor{} +\else +\def\draftnote{\vbox to 0pt{\vskip-12pt + \hbox{\ \footnotesize}}%\TeXversion + \hbox{\ \footnotesize ZU064-05-FPR\qquad\jobname\qquad\today\qquad\currenttime\qquad %Char Count= \@TotalChars + \@questionmark\hfil}}% + \def\Qauthor#1{\marginpar{{\raggedright\footnotesize\bf #1\endgraf}}} +\fi +%% +\newdimen\figheight +\newdimen\figwidth +% +\def\ArtDir{art/}% +\input epsf.sty +% +\newbox\figtempbox +\def\ArtPiece#1{\epsfbox{\ArtDir#1}}% +% +\def\figurebox#1#2{% + \@ifnextchar[{\@figurebox{#1}{#2}}{\@figurebox{#1}{#2}[]}} +% +\def\@figurebox#1#2[#3]{% + \gdef\@thirdarg{#3}% + \ifx\@thirdarg\empty + \global\figheight=#1 + \global\figwidth=#2 + \else + \setbox\figtempbox=\hbox{\epsfbox{\ArtDir\@thirdarg}}% + \global\figwidth=\wd\figtempbox + \global\figheight=\ht\figtempbox + \fi + \centerline{\figbox} + \vskip7pt}% +% +\def\figbox{% + \ifx\@thirdarg\empty + \vbox{\vskip.3pt\hsize\figwidth + \hrule\hbox to\figwidth{\vrule\hfill\vbox to\figheight{% + \hsize\figwidth\vfill}\vrule}\hrule}% + \else + \vbox{\hsize\figwidth + \hbox to\figwidth{\vbox to\figheight{\hsize\figwidth\box\figtempbox}}}% + \fi} +% +% +% +\newdimen\tabledim +\newskip\tableleftskip +\newskip\tablerightskip +\newskip\tabnoteleftskip +\newskip\tabnoterightskip +\newdimen\tablewidth +% + +% +\def\tbl#1#2{% + \setbox\tempbox\hbox{\tablefont#2}% + \tabledim\hsize + \advance\tabledim-\wd\tempbox + \ifdim\tabledim>0pt + \divide\tabledim2 + \else + \global\tabledim0pt + \fi + \global\tableleftskip\tabledim + \global\tablerightskip\tabledim plus.5fill + \global\tabnoteleftskip\tabledim + \global\tabnoterightskip\tabledim + \caption{\tablefont #1}% + {\centerline{\box\tempbox}}}% +% +\let\bulletlist\itemize +\let\endbulletlist\enditemize +\let\arabiclist\enumerate +\let\endarabiclist\endenumerate +\let\ulist\unnumlist +\let\endulist\endunnumlist +\def\bibauthor#1{{#1}} +\def\x{@{\extracolsep{\fill}}} +\def\tablefont{\fontsize{9}{11}\selectfont}%\leftskip\tableleftskip\rightskip\tablerightskip\mathversion{normal}}% use plus 1fill if needed +\def\tablecaptionfont{\fontsize{10}{12}\selectfont\itshape\leftskip\tableleftskip\rightskip\tablerightskip}%\itshape +\def\tablecaptionnumfont{\reset@font\fontsize{10}{12}\selectfont}% +\def\TCHfont{\fontsize{9}{13}\selectfont}% +\def\TSCHfont{}% +\def\tabnotefont{\fontsize{9}{11}\selectfont\leftskip\tabnoteleftskip\rightskip\tabnoterightskip}% use plus 1fill if needed +\def\toprule{\\[-5pt]\Hline\\[-9pt]\Hline\\[-7.1pt]} +\def\colrule{\\[-7.8pt]\HHline\\[-7pt]} +\def\Colrule{\\[-8.6pt]\HHline\\[-5.2pt]} +\def\botrule{\\[-8.3pt]\Hline\\[-9pt]\Hline} +\def\crule#1{\\[-10.9pt]#1\\[-21.4pt]} +% +\def\Hline{% + \noalign{\ifnum0=`}\fi\hrule \@height .5pt \futurelet%\@height \arrayrulewidth + \@tempa\@xhline} +% +\def\HHline{% + \noalign{\ifnum0=`}\fi\hrule \@height .5pt \futurelet%\@height \arrayrulewidth + \@tempa\@xhline} +% +% +% +\def\pubDate#1{(#1)} +% +\newenvironment{ack}{\par\addvspace{\baselineskip}}{\par} +% +\def\@Afterheading{% + \global\@nobreaktrue + \everypar{% + \if@nobreak + \global\@nobreakfalse + \clubpenalty \@M + \if@afterindent \else + {\setbox\z@\lastbox}% + \fi + \else + \clubpenalty \@clubpenalty + \everypar{}% + \fi}} +% +\def\getBIBNUM#1{% + \expandafter\getstring#1\@} +% +\def\getstring #1#2#3#4\@{\gdef\@@getstr{#1#2#3}} +% +\let\summary\abstract +\let\endsummary\endabstract +\let\makechaptertitle\relax +% +\@namedef{equation*}{$$} +\@namedef{endequation*}{$$} +% +\gdef\zero@{0} +\gdef\REF{ref} +\gdef\removedash#1-#2-#3#4#5#6#7#8#9{% +\gdef\tempa{#2}% +\gdef\tempb{#3}% +\ifx\tempa\REF% +\else% +\ifx\tempb\N% +\expandafter\removezeros#7#8#9% +\else% +\fi% +\fi% +\gdef\tempa{}\gdef\tempb{}} +% +\gdef\N{n} +% +\gdef\removezeros#1#2#3{% +\gdef\tempd{#1}% +\gdef\tempe{#2}% +\gdef\tempf{#3}% +\ifnum\tempd=\zero@% + \ifnum\tempe=\zero@% + $^\tempf$% + \else% + $^{\tempe\tempf}$% + \fi% +\else% + $^{\tempd\tempe\tempf}$% +\fi +\gdef\tempd{}\gdef\tempe{}\gdef\tempf{}} +\newcount\colcount +\newcount\firstcol +\newcount\lastcol +\def\getCOLNUM#1#2{ +\global\colcount\expandafter\getnumber#2 +\global\advance\colcount-\expandafter\getnumber#1 +\global\advance\colcount1 +\global\firstcol\expandafter\getnumber#1 +\global\lastcol\expandafter\getnumber#2} +% +%\def\getnumber col#1{#1} +\def\getnumber #1{#1} +% +\gdef\removexref#1-#2-#3#4#5#6#7#8{% +\thechapter.\expandafter\removexzeros#6#7#8} +% +\gdef\removehash#1#2{#2} +\gdef\removexzeros#1#2#3{% +\gdef\tempd{#1}% +\gdef\tempe{#2}% +\gdef\tempf{#3}% +\ifnum\tempd=\zero@% + \ifnum\tempe=\zero@% +{\tempf}% + \else% +{\tempe\tempf}% + \fi% +\else% +{\tempd\tempe\tempf}% +\fi +\gdef\tempd{}\gdef\tempe{}\gdef\tempf{}} +% +\newif\ifframed +\newif\ifnotablenum +% +\renewcommand{\textellipsis}{% + .\kern\fontdimen3\font + .\kern\fontdimen3\font + .\kern\fontdimen3\font} +% +% +\let\thenotes\Notes +\let\endthenotes\endNotes +\let\endnote\Enote +\def\listhead#1{} +\let\parahead\prhead +% +\let\@chaptertitle\@chaptitle +% +\def\Pound{\hbox{\char'243}}% +% +\newbox\tempbox +% +\def\pubyear#1{\gdef\@pubyear{#1}}%\pubyear{2002} +\def\cpyyear#1{\gdef\@cpyyear{#1}}%\pubyear{2002} +\cpyyear{} +%\def\volume#1{\gdef\@volume{#1}}%\volume{xxx} +\def\issue#1{\gdef\@issue{#1}}%\volume{xxx} +\issue{} +\def\doi#1{\gdef\@doi{#1}}%\doi{10.1017$/$S002211200100622X} +% +\let\chapter\title +% +\def\indexfont{\fontsize{9}{10}\selectfont} +% +\def\alphabet#1{{\bf#1}\par\vskip.5\baselineskip} + +% +\def\indexheadfont{\fontsize{18.5}{20.5}\selectfont\bfseries\centering} +\newcommand\indexname{Author index} +\newenvironment{theindex}[2][\relax]{\thispagestyle{empty}\authormark{\indexname}%\global\indextrue%% + \ifx#2\relax\else\gdef\indexname{#2}\fi% + \ifx#1\relax\else\gdef\indexhead{#1}\fi% + \maketitle\indexfont% + \parindent\z@ + \let\item\@idxitem +}{% + \par%\global\indexfalse +} +\newcommand\@idxitem {\par\hangindent9pt} +\newcommand\subitem {\par\hangindent2em\hspace*{1em}} +\newcommand\subsubitem{\par\hangindent2em\hspace*{2em}} +\newcommand\indexspace{\par \vskip\baselineskip} +% +\newenvironment{indexpara}{\setbox\tempbox\hbox\bgroup}{\egroup} +\def\au#1{{\indexfont\scshape#1}} +\def\ttl#1{{\indexfont#1}} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\newcommand\email[1]{\par{\normalfont\rmfamily +% \itshape\textup{(}e-mail: \textup{\texttt{#1})}}\par} + +\edef\r@{\ifprodtf mtr\else cmr\fi} +%\edef\s@{\ifprodtf mtss\else cmr\fi} + +\let\real@font@warning\@font@warning +\DeclareMathVersion{program} +\let\@font@warning\@gobble +\SetSymbolFont{letters}{program}{OT1}{\r@}{m}{sl} +\let\@font@warning\real@font@warning +\SetMathAlphabet{\mathnormal}{program}{OT1}{\r@}{m}{sl} + + +\newcommand{\programmath}{\mathversion{program}} +\newcommand{\unprogrammath}{\mathversion{normal}} +\newcommand{\figrule}{\begin{center}\hrule\end{center}} + +\DeclareRobustCommand\dplus{\mathbin{+\!\!+}} +\DeclareRobustCommand\dequals{\mathbin{==}} +\DeclareRobustCommand\dcolon{\mathbin{::}} +\DeclareRobustCommand\dcolonequals{\mathbin{::=}} + +\pagestyle{headings} +\pagenumbering{arabic} +\frenchspacing +\flushbottom + +\def\parahead#1{} + +\ifprinter +\voffset-18.4mm +\hoffset-25.4mm +\else +\voffset2.3pc +\hoffset-1pc +\fi +%% +\ifcompmod +\else + \usepackage{mathptmx,bm} + \DeclareMathVersion{bold} + \usepackage{amsfonts} +\fi +%% +\endinput + +% end of file jfp.cls \ No newline at end of file diff --git a/jfp-paper/latexrun b/jfp-paper/latexrun new file mode 100755 index 0000000000000000000000000000000000000000..b669d9fbbc0ff0b15a3dea0e2d21fe873ab1a9bf --- /dev/null +++ b/jfp-paper/latexrun @@ -0,0 +1,1936 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2013, 2014 Austin Clements + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +import os +import errno +import argparse +import shlex +import json +import subprocess +import re +import collections +import hashlib +import shutil +import curses +import filecmp +import io +import traceback +import time + +try: + import fcntl +except ImportError: + # Non-UNIX platform + fcntl = None + +def debug(string, *args): + if debug.enabled: + print(string.format(*args), file=sys.stderr) +debug.enabled = False + +def debug_exc(): + if debug.enabled: + traceback.print_exc() + +def main(): + # Parse command-line + arg_parser = argparse.ArgumentParser( + description='''A 21st century LaTeX wrapper, + %(prog)s runs latex (and bibtex) the right number of times so you + don't have to, + strips the log spew to make errors visible, + and plays well with standard build tools.''') + arg_parser.add_argument( + '-o', metavar='FILE', dest='output', default=None, + help='Output file name (default: derived from input file)') + arg_parser.add_argument( + '--latex-cmd', metavar='CMD', default='pdflatex', + help='Latex command (default: %(default)s)') + arg_parser.add_argument( + '--latex-args', metavar='ARGS', type=arg_parser_shlex, + help='Additional command-line arguments for latex.' + ' This will be parsed and split using POSIX shell rules.') + arg_parser.add_argument( + '--bibtex-cmd', metavar='CMD', default='bibtex', + help='Bibtex command (default: %(default)s)') + arg_parser.add_argument( + '--bibtex-args', metavar='ARGS', type=arg_parser_shlex, + help='Additional command-line arguments for bibtex') + arg_parser.add_argument( + '--max-iterations', metavar='N', type=int, default=10, + help='Max number of times to run latex before giving up' + ' (default: %(default)s)') + arg_parser.add_argument( + '-W', metavar='(no-)CLASS', + action=ArgParserWarnAction, dest='nowarns', default=set(['underfull']), + help='Enable/disable warning from CLASS, which can be any package name, ' + 'LaTeX warning class (e.g., font), bad box type ' + '(underfull, overfull, loose, tight), or "all"') + arg_parser.add_argument( + '-O', metavar='DIR', dest='obj_dir', default='latex.out', + help='Directory for intermediate files and control database ' + '(default: %(default)s)') + arg_parser.add_argument( + '--color', choices=('auto', 'always', 'never'), default='auto', + help='When to colorize messages') + arg_parser.add_argument( + '--verbose-cmds', action='store_true', default=False, + help='Print commands as they are executed') + arg_parser.add_argument( + '--debug', action='store_true', + help='Enable detailed debug output') + actions = arg_parser.add_argument_group('actions') + actions.add_argument( + '--clean-all', action='store_true', help='Delete output files') + actions.add_argument( + 'file', nargs='?', help='.tex file to compile') + args = arg_parser.parse_args() + if not any([args.clean_all, args.file]): + arg_parser.error('at least one action is required') + args.latex_args = args.latex_args or [] + args.bibtex_args = args.bibtex_args or [] + + verbose_cmd.enabled = args.verbose_cmds + debug.enabled = args.debug + + # A note about encodings: POSIX encoding is a mess; TeX encoding + # is a disaster. Our goal is to make things no worse, so we want + # byte-accurate round-tripping of TeX messages. Since TeX + # messages are *basically* text, we use strings and + # surrogateescape'ing for both input and output. I'm not fond of + # setting surrogateescape globally, but it's far easier than + # dealing with every place we pass TeX output through. + # Conveniently, JSON can round-trip surrogateescape'd strings, so + # our control database doesn't need special handling. + sys.stdout = io.TextIOWrapper( + sys.stdout.buffer, encoding=sys.stdout.encoding, + errors='surrogateescape', line_buffering=sys.stdout.line_buffering) + sys.stderr = io.TextIOWrapper( + sys.stderr.buffer, encoding=sys.stderr.encoding, + errors='surrogateescape', line_buffering=sys.stderr.line_buffering) + + Message.setup_color(args.color) + + # Open control database. + dbpath = os.path.join(args.obj_dir, '.latexrun.db') + if not os.path.exists(dbpath) and os.path.exists('.latexrun.db'): + # The control database used to live in the source directory. + # Support this for backwards compatibility. + dbpath = '.latexrun.db' + try: + db = DB(dbpath) + except (ValueError, OSError) as e: + print('error opening {}: {}'.format(e.filename if hasattr(e, 'filename') + else dbpath, e), + file=sys.stderr) + debug_exc() + sys.exit(1) + + # Clean + if args.clean_all: + try: + db.do_clean(args.obj_dir) + except OSError as e: + print(e, file=sys.stderr) + debug_exc() + sys.exit(1) + + # Build + if not args.file: + return + task_commit = None + try: + task_latex = LaTeX(db, args.file, args.latex_cmd, args.latex_args, + args.obj_dir, args.nowarns) + task_commit = LaTeXCommit(db, task_latex, args.output) + task_bibtex = BibTeX(db, task_latex, args.bibtex_cmd, args.bibtex_args, + args.nowarns, args.obj_dir) + tasks = [task_latex, task_commit, task_bibtex] + stable = run_tasks(tasks, args.max_iterations) + + # Print final task output and gather exit status + status = 0 + for task in tasks: + status = max(task.report(), status) + + if not stable: + print('error: files are still changing after {} iterations; giving up' + .format(args.max_iterations), file=sys.stderr) + status = max(status, 1) + except TaskError as e: + print(str(e), file=sys.stderr) + debug_exc() + status = 1 + + # Report final status, if interesting + fstatus = 'There were errors' if task_commit is None else task_commit.status + if fstatus: + output = args.output + if output is None: + if task_latex.get_outname() is not None: + output = os.path.basename(task_latex.get_outname()) + else: + output = 'output' + if Message._color: + terminfo.send('bold', ('setaf', 1)) + print('{}; {} not updated'.format(fstatus, output)) + if Message._color: + terminfo.send('sgr0') + sys.exit(status) + +def arg_parser_shlex(string): + """Argument parser for shell token lists.""" + try: + return shlex.split(string) + except ValueError as e: + raise argparse.ArgumentTypeError(str(e)) from None + +class ArgParserWarnAction(argparse.Action): + def __call__(self, parser, namespace, value, option_string=None): + nowarn = getattr(namespace, self.dest) + if value == 'all': + nowarn.clear() + elif value.startswith('no-'): + nowarn.add(value[3:]) + else: + nowarn.discard(value) + setattr(namespace, self.dest, nowarn) + +def verbose_cmd(args, cwd=None, env=None): + if verbose_cmd.enabled: + cmd = ' '.join(map(shlex.quote, args)) + if cwd is not None: + cmd = '(cd {} && {})'.format(shlex.quote(cwd), cmd) + if env is not None: + for k, v in env.items(): + if os.environ.get(k) != v: + cmd = '{}={} {}'.format(k, shlex.quote(v), cmd) + print(cmd, file=sys.stderr) +verbose_cmd.enabled = False + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + +class DB: + """A latexrun control database.""" + + _VERSION = 'latexrun-db-v2' + + def __init__(self, filename): + self.__filename = filename + + # Make sure database directory exists + if os.path.dirname(self.__filename): + os.makedirs(os.path.dirname(self.__filename), exist_ok=True) + + # Lock the database if possible. We don't release this lock + # until the process exits. + lockpath = self.__filename + '.lock' + if fcntl is not None: + lockfd = os.open(lockpath, os.O_CREAT|os.O_WRONLY|os.O_CLOEXEC, 0o666) + # Note that this is actually an fcntl lock, not a lockf + # lock. Don't be fooled. + fcntl.lockf(lockfd, fcntl.LOCK_EX, 1) + + try: + fp = open(filename, 'r') + except FileNotFoundError: + debug('creating new database') + self.__val = {'version': DB._VERSION} + else: + debug('loading database') + self.__val = json.load(fp) + if 'version' not in self.__val: + raise ValueError('file exists, but does not appear to be a latexrun database'.format(filename)) + if self.__val['version'] != DB._VERSION: + raise ValueError('unknown database version {!r}' + .format(self.__val['version'])) + + def commit(self): + debug('committing database') + # Atomically commit database + tmp_filename = self.__filename + '.tmp' + with open(tmp_filename, 'w') as fp: + json.dump(self.__val, fp, indent=2, separators=(',', ': ')) + fp.flush() + os.fsync(fp.fileno()) + os.rename(tmp_filename, self.__filename) + + def get_summary(self, task_id): + """Return the recorded summary for the given task or None.""" + return self.__val.get('tasks', {}).get(task_id) + + def set_summary(self, task_id, summary): + """Set the summary for the given task.""" + self.__val.setdefault('tasks', {})[task_id] = summary + + def add_clean(self, filename): + """Add an output file to be cleaned. + + Unlike the output files recorded in the task summaries, + cleanable files strictly accumulate until a clean is + performed. + """ + self.__val.setdefault('clean', {})[filename] = hash_cache.get(filename) + + def do_clean(self, obj_dir=None): + """Remove output files and delete database. + + If obj_dir is not None and it is empty after all files are + removed, it will also be removed. + """ + + for f, want_hash in self.__val.get('clean', {}).items(): + have_hash = hash_cache.get(f) + if have_hash is not None: + if want_hash == have_hash: + debug('unlinking {}', f) + hash_cache.invalidate(f) + os.unlink(f) + else: + print('warning: {} has changed; not removing'.format(f), + file=sys.stderr) + self.__val = {'version': DB._VERSION} + try: + os.unlink(self.__filename) + except FileNotFoundError: + pass + if obj_dir is not None: + try: + os.rmdir(obj_dir) + except OSError: + pass + +class HashCache: + """Cache of file hashes. + + As latexrun reaches fixed-point, it hashes the same files over and + over, many of which never change. Since hashing is somewhat + expensive, we keep a simple cache of these hashes. + """ + + def __init__(self): + self.__cache = {} + + def get(self, filename): + """Return the hash of filename, or * if it was clobbered.""" + try: + with open(filename, 'rb') as fp: + st = os.fstat(fp.fileno()) + key = (st.st_dev, st.st_ino) + if key in self.__cache: + return self.__cache[key] + + debug('hashing {}', filename) + h = hashlib.sha256() + while True: + block = fp.read(256*1024) + if not len(block): + break + h.update(block) + self.__cache[key] = h.hexdigest() + return self.__cache[key] + except (FileNotFoundError, IsADirectoryError): + return None + + def clobber(self, filename): + """If filename's hash is not known, record an invalid hash. + + This can be used when filename was overwritten before we were + necessarily able to obtain its hash. filename must exist. + """ + st = os.stat(filename) + key = (st.st_dev, st.st_ino) + if key not in self.__cache: + self.__cache[key] = '*' + + def invalidate(self, filename): + try: + st = os.stat(filename) + except OSError as e: + # Pessimistically wipe the whole cache + debug('wiping hash cache ({})', e) + self.__cache.clear() + else: + key = (st.st_dev, st.st_ino) + if key in self.__cache: + del self.__cache[key] +hash_cache = HashCache() + +class _Terminfo: + def __init__(self): + self.__tty = os.isatty(sys.stdout.fileno()) + if self.__tty: + curses.setupterm() + self.__ti = {} + + def __ensure(self, cap): + if cap not in self.__ti: + if not self.__tty: + string = None + else: + string = curses.tigetstr(cap) + if string is None or b'$<' in string: + # Don't have this capability or it has a pause + string = None + self.__ti[cap] = string + return self.__ti[cap] + + def has(self, *caps): + return all(self.__ensure(cap) is not None for cap in caps) + + def send(self, *caps): + # Flush TextIOWrapper to the binary IO buffer + sys.stdout.flush() + for cap in caps: + # We should use curses.putp here, but it's broken in + # Python3 because it writes directly to C's buffered + # stdout and there's no way to flush that. + if isinstance(cap, tuple): + s = curses.tparm(self.__ensure(cap[0]), *cap[1:]) + else: + s = self.__ensure(cap) + sys.stdout.buffer.write(s) +terminfo = _Terminfo() + +class Progress: + _enabled = None + + def __init__(self, prefix): + self.__prefix = prefix + if Progress._enabled is None: + Progress._enabled = (not debug.enabled) and \ + terminfo.has('cr', 'el', 'rmam', 'smam') + + def __enter__(self): + self.last = '' + self.update('') + return self + + def __exit__(self, typ, value, traceback): + if Progress._enabled: + # Beginning of line and clear + terminfo.send('cr', 'el') + sys.stdout.flush() + + def update(self, msg): + if not Progress._enabled: + return + out = '[' + self.__prefix + ']' + if msg: + out += ' ' + msg + if out != self.last: + # Beginning of line, clear line, disable wrap + terminfo.send('cr', 'el', 'rmam') + sys.stdout.write(out) + # Enable wrap + terminfo.send('smam') + self.last = out + sys.stdout.flush() + +class Message(collections.namedtuple( + 'Message', 'typ filename lineno msg')): + def emit(self): + if self.filename: + if self.filename.startswith('./'): + finfo = self.filename[2:] + else: + finfo = self.filename + else: + finfo = '<no file>' + if self.lineno is not None: + finfo += ':' + str(self.lineno) + finfo += ': ' + if self._color: + terminfo.send('bold') + sys.stdout.write(finfo) + + if self.typ != 'info': + if self._color: + terminfo.send(('setaf', 5 if self.typ == 'warning' else 1)) + sys.stdout.write(self.typ + ': ') + if self._color: + terminfo.send('sgr0') + sys.stdout.write(self.msg + '\n') + + @classmethod + def setup_color(cls, state): + if state == 'never': + cls._color = False + elif state == 'always': + cls._color = True + elif state == 'auto': + cls._color = terminfo.has('setaf', 'bold', 'sgr0') + else: + raise ValueError('Illegal color state {:r}'.format(state)) + + +################################################################## +# Task framework +# + +terminate_task_loop = False +start_time = time.time() + +def run_tasks(tasks, max_iterations): + """Execute tasks in round-robin order until all are stable. + + This will also exit if terminate_task_loop is true. Tasks may use + this to terminate after a fatal error (even if that fatal error + doesn't necessarily indicate stability; as long as re-running the + task will never eliminate the fatal error). + + Return True if fixed-point is reached or terminate_task_loop is + set within max_iterations iterations. + """ + + global terminate_task_loop + terminate_task_loop = False + + nstable = 0 + for iteration in range(max_iterations): + for task in tasks: + if task.stable(): + nstable += 1 + if nstable == len(tasks): + debug('fixed-point reached') + return True + else: + task.run() + nstable = 0 + if terminate_task_loop: + debug('terminate_task_loop set') + return True + debug('fixed-point not reached') + return False + +class TaskError(Exception): + pass + +class Task: + """A deterministic computation whose inputs and outputs can be captured.""" + + def __init__(self, db, task_id): + self.__db = db + self.__task_id = task_id + + def __debug(self, string, *args): + if debug.enabled: + debug('task {}: {}', self.__task_id, string.format(*args)) + + def stable(self): + """Return True if running this task will not affect system state. + + Functionally, let f be the task, and s be the system state. + Then s' = f(s). If it must be that s' == s (that is, f has + reached a fixed point), then this function must return True. + """ + last_summary = self.__db.get_summary(self.__task_id) + if last_summary is None: + # Task has never run, so running it will modify system + # state + changed = 'never run' + else: + # If any of the inputs have changed since the last run of + # this task, the result may change, so re-run the task. + # Also, it's possible something else changed an output + # file, in which case we also want to re-run the task, so + # check the outputs, too. + changed = self.__summary_changed(last_summary) + + if changed: + self.__debug('unstable (changed: {})', changed) + return False + else: + self.__debug('stable') + return True + + def __summary_changed(self, summary): + """Test if any inputs changed from summary. + + Returns a string describing the changed input, or None. + """ + for dep in summary['deps']: + fn, args, val = dep + method = getattr(self, '_input_' + fn, None) + if method is None: + return 'unknown dependency method {}'.format(fn) + if method == self._input_unstable or method(*args) != val: + return '{}{}'.format(fn, tuple(args)) + return None + + def _input(self, name, *args): + """Register an input for this run. + + This calls self._input_<name>(*args) to get the value of this + input. This function should run quickly and return some + projection of system state that affects the result of this + computation. + + Both args and the return value must be JSON serializable. + """ + method = getattr(self, '_input_' + name) + val = method(*args) + if [name, args, val] not in self.__deps: + self.__deps.append([name, args, val]) + return val + + def run(self): + # Before we run the task, pre-hash any files that were output + # files in the last run. These may be input by this run and + # then clobbered, at which point it will be too late to get an + # input hash. Ideally we would only hash files that were + # *both* input and output files, but latex doesn't tell us + # about input files that didn't exist, so if we start from a + # clean slate, we often require an extra run because we don't + # know a file is input/output until after the second run. + last_summary = self.__db.get_summary(self.__task_id) + if last_summary is not None: + for io_filename in last_summary['output_files']: + self.__debug('pre-hashing {}', io_filename) + hash_cache.get(io_filename) + + # Run the task + self.__debug('running') + self.__deps = [] + result = self._execute() + + # Clear cached output file hashes + for filename in result.output_filenames: + hash_cache.invalidate(filename) + + # If the output files change, then the computation needs to be + # re-run, so record them as inputs + for filename in result.output_filenames: + self._input('file', filename) + + # Update task summary in database + self.__db.set_summary(self.__task_id, + self.__make_summary(self.__deps, result)) + del self.__deps + + # Add output files to be cleaned + for f in result.output_filenames: + self.__db.add_clean(f) + + try: + self.__db.commit() + except OSError as e: + raise TaskError('error committing control database {}: {}'.format( + getattr(e, 'filename', '<unknown path>'), e)) from e + + def __make_summary(self, deps, run_result): + """Construct a new task summary.""" + return { + 'deps': deps, + 'output_files': {f: hash_cache.get(f) + for f in run_result.output_filenames}, + 'extra': run_result.extra, + } + + def _execute(self): + """Abstract: Execute this task. + + Subclasses should implement this method to execute this task. + This method must return a RunResult giving the inputs that + were used by the task and the outputs it produced. + """ + raise NotImplementedError('Task._execute is abstract') + + def _get_result_extra(self): + """Return the 'extra' result from the previous run, or None.""" + summary = self.__db.get_summary(self.__task_id) + if summary is None: + return None + return summary['extra'] + + def report(self): + """Report the task's results to stdout and return exit status. + + This may be called when the task has never executed. + Subclasses should override this. The default implementation + reports nothing and returns 0. + """ + return 0 + + # Standard input functions + + def _input_env(self, var): + return os.environ.get(var) + + def _input_file(self, path): + return hash_cache.get(path) + + def _input_unstable(self): + """Mark this run as unstable, regardless of other inputs.""" + return None + + def _input_unknown_input(self): + """An unknown input that may change after latexrun exits. + + This conservatively marks some unknown input that definitely + won't change while latexrun is running, but may change before + the user next runs latexrun. This allows the task to + stabilize during this invocation, but will cause the task to + re-run on the next invocation. + """ + return start_time + +class RunResult(collections.namedtuple( + 'RunResult', 'output_filenames extra')): + """The result of a single task execution. + + This captures all files written by the task, and task-specific + results that need to be persisted between runs (for example, to + enable reporting of a task's results). + """ + pass + +################################################################## +# LaTeX task +# + +def normalize_input_path(path): + # Resolve the directory of the input path, but leave the file + # component alone because it affects TeX's behavior. + head, tail = os.path.split(path) + npath = os.path.join(os.path.realpath(head), tail) + return os.path.relpath(path) + +class LaTeX(Task): + def __init__(self, db, tex_filename, cmd, cmd_args, obj_dir, nowarns): + super().__init__(db, 'latex::' + normalize_input_path(tex_filename)) + self.__tex_filename = tex_filename + self.__cmd = cmd + self.__cmd_args = cmd_args + self.__obj_dir = obj_dir + self.__nowarns = nowarns + + self.__pass = 0 + + def _input_args(self): + # If filename starts with a character the tex command-line + # treats specially, then tweak it so it doesn't. + filename = self.__tex_filename + if filename.startswith(('-', '&', '\\')): + filename = './' + filename + # XXX Put these at the beginning in case the provided + # arguments are malformed. Might want to do a best-effort + # check for incompatible user-provided arguments (note: + # arguments can be given with one or two dashes and those with + # values can use an equals or a space). + return [self.__cmd] + self.__cmd_args + \ + ['-interaction', 'nonstopmode', '-recorder', + '-output-directory', self.__obj_dir, filename] + + def _execute(self): + # Run latex + self.__pass += 1 + args = self._input('args') + debug('running {}', args) + try: + os.makedirs(self.__obj_dir, exist_ok=True) + except OSError as e: + raise TaskError('failed to create %s: ' % self.__obj_dir + str(e)) \ + from e + try: + verbose_cmd(args) + p = subprocess.Popen(args, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout, has_errors, missing_includes = self.__feed_terminal(p.stdout) + status = p.wait() + except OSError as e: + raise TaskError('failed to execute latex task: ' + str(e)) from e + + # Register environment variable inputs + for env_var in ['TEXMFOUTPUT', 'TEXINPUTS', 'TEXFORMATS', 'TEXPOOL', + 'TFMFONTS', 'PATH']: + self._input('env', env_var) + + jobname, outname = self.__parse_jobname(stdout) + inputs, outputs = self.__parse_recorder(jobname) + + # LaTeX overwrites its own inputs. Mark its output files as + # clobbered before we hash its input files. + for path in outputs: + # In some abort cases (e.g., >=100 errors), LaTeX claims + # output files that don't actually exist. + if os.path.exists(path): + hash_cache.clobber(path) + # Depend on input files. Task.run pre-hashed outputs from the + # previous run, so if this isn't the first run and as long as + # the set of outputs didn't change, we'll be able to get the + # input hashes, even if they were clobbered. + for path in inputs: + self._input('file', path) + + if missing_includes: + # Missing \includes are tricky. Ideally we'd depend on + # the absence of some file, but in fact we'd have to + # depend on the failure of a whole kpathsea lookup. + # Rather than try to be clever, just mark this as an + # unknown input so we'll run at least once on the next + # invocation. + self._input('unknown_input') + + if not self.__create_outdirs(stdout) and has_errors: + # LaTeX reported unrecoverable errors (other than output + # directory errors, which we just fixed). We could + # continue to stabilize the document, which may change + # some of the other problems reported (but not the + # unrecoverable errors), or we can just abort now and get + # back to the user quickly with the major errors. We opt + # for the latter. + global terminate_task_loop + terminate_task_loop = True + # This error could depend on something we failed to track. + # It would be really confusing if we continued to report + # the error after the user fixed it, so be conservative + # and force a re-run next time. + self._input('unknown_input') + + return RunResult(outputs, + {'jobname': jobname, 'outname': outname, + 'status': status}) + + def __feed_terminal(self, stdout): + prefix = 'latex' + if self.__pass > 1: + prefix += ' ({})'.format(self.__pass) + with Progress(prefix) as progress: + buf = [] + filt = LaTeXFilter() + while True: + # Use os.read to read only what's available on the pipe, + # without waiting to fill a buffer + data = os.read(stdout.fileno(), 4096) + if not data: + break + # See "A note about encoding" above + data = data.decode('ascii', errors='surrogateescape') + buf.append(data) + filt.feed(data) + file_stack = filt.get_file_stack() + if file_stack: + tos = file_stack[-1] + if tos.startswith('./'): + tos = tos[2:] + progress.update('>' * len(file_stack) + ' ' + tos) + else: + progress.update('') + + # Were there unrecoverable errors? + has_errors = any(msg.typ == 'error' for msg in filt.get_messages()) + + return ''.join(buf), has_errors, filt.has_missing_includes() + + def __parse_jobname(self, stdout): + """Extract the job name and output name from latex's output. + + We get these from latex because they depend on complicated + file name parsing rules, are affected by arguments like + -output-directory, and may be just "texput" if things fail + really early. The output name may be None if there were no + pages of output. + """ + jobname = outname = None + for m in re.finditer(r'^Transcript written on "?(.*)\.log"?\.$', stdout, + re.MULTILINE | re.DOTALL): + jobname = m.group(1).replace('\n', '') + if jobname is None: + print(stdout, file=sys.stderr) + raise TaskError('failed to extract job name from latex log') + for m in re.finditer(r'^Output written on "?(.*\.[^ ."]+)"? \([0-9]+ page', + stdout, re.MULTILINE | re.DOTALL): + outname = m.group(1).replace('\n', '') + if outname is None and not \ + re.search(r'^No pages of output\.$|^! Emergency stop\.$' + r'|^! ==> Fatal error occurred, no output PDF file produced!$', + stdout, re.MULTILINE): + print(stdout, file=sys.stderr) + raise TaskError('failed to extract output name from latex log') + + # LuaTeX (0.76.0) doesn't include the output directory in the + # logged transcript or output file name. + if os.path.basename(jobname) == jobname and \ + os.path.exists(os.path.join(self.__obj_dir, jobname + '.log')): + jobname = os.path.join(self.__obj_dir, jobname) + if outname is not None: + outname = os.path.join(self.__obj_dir, outname) + + return jobname, outname + + def __parse_recorder(self, jobname): + """Parse file recorder output.""" + # XXX If latex fails because a file isn't found, that doesn't + # go into the .fls file, but creating that file will affect + # the computation, so it should be included as an input. + # Though it's generally true that files can be added earlier + # in search paths and will affect the output without us knowing. + # + # XXX This is a serious problem for bibtex, since the first + # run won't depend on the .bbl file! But maybe the .aux file + # will always cause a re-run, at which point the .bbl will + # exist? + filename = jobname + '.fls' + try: + recorder = open(filename) + except OSError as e: + raise TaskError('failed to open file recorder output: ' + str(e)) \ + from e + pwd, inputs, outputs = '', set(), set() + for linenum, line in enumerate(recorder): + parts = line.rstrip('\n').split(' ', 1) + if parts[0] == 'PWD': + pwd = parts[1] + elif parts[0] in ('INPUT', 'OUTPUT'): + if parts[1].startswith('/'): + path = parts[1] + else: + # Try to make "nice" paths, especially for clean + path = os.path.relpath(os.path.join(pwd, parts[1])) + if parts[0] == 'INPUT': + inputs.add(path) + else: + outputs.add(path) + else: + raise TaskError('syntax error on line {} of {}' + .format(linenum, filename)) + # Ironically, latex omits the .fls file itself + outputs.add(filename) + return inputs, outputs + + def __create_outdirs(self, stdout): + # In some cases, such as \include'ing a file from a + # subdirectory, TeX will attempt to create files in + # subdirectories of the output directory that don't exist. + # Detect this, create the output directory, and re-run. + m = re.search('^! I can\'t write on file `(.*)\'\\.$', stdout, re.M) + if m and m.group(1).find('/') > 0 and '../' not in m.group(1): + debug('considering creating output sub-directory for {}'. + format(m.group(1))) + subdir = os.path.dirname(m.group(1)) + newdir = os.path.join(self.__obj_dir, subdir) + if os.path.isdir(subdir) and not os.path.isdir(newdir): + debug('creating output subdirectory {}'.format(newdir)) + try: + mkdir_p(newdir) + except OSError as e: + raise TaskError('failed to create output subdirectory: ' + + str(e)) from e + self._input('unstable') + return True + + def report(self): + extra = self._get_result_extra() + if extra is None: + return 0 + + # Parse the log + logfile = open(extra['jobname'] + '.log', 'rt', errors='surrogateescape') + for msg in self.__clean_messages( + LaTeXFilter(self.__nowarns).feed( + logfile.read(), True).get_messages()): + msg.emit() + + # Return LaTeX's exit status + return extra['status'] + + def __clean_messages(self, msgs): + """Make some standard log messages more user-friendly.""" + have_undefined_reference = False + for msg in msgs: + if msg.msg == '==> Fatal error occurred, no output PDF file produced!': + msg = msg._replace(typ='info', + msg='Fatal error (no output file produced)') + if msg.msg.startswith('[LaTeX] '): + # Strip unnecessary package name + msg = msg._replace(msg=msg.msg.split(' ', 1)[1]) + if re.match(r'Reference .* undefined', msg.msg): + have_undefined_reference = True + if have_undefined_reference and \ + re.match(r'There were undefined references', msg.msg): + # LaTeX prints this at the end so the user knows it's + # worthwhile looking back at the log. Since latexrun + # makes the earlier messages obvious, this is + # redundant. + continue + yield msg + + def get_tex_filename(self): + return self.__tex_filename + + def get_jobname(self): + extra = self._get_result_extra() + if extra is None: + return None + return extra['jobname'] + + def get_outname(self): + extra = self._get_result_extra() + if extra is None: + return None + return extra['outname'] + + def get_status(self): + extra = self._get_result_extra() + if extra is None: + return None + return extra['status'] + +class LaTeXCommit(Task): + def __init__(self, db, latex_task, output_path): + super().__init__(db, 'latex_commit::' + + normalize_input_path(latex_task.get_tex_filename())) + self.__latex_task = latex_task + self.__output_path = output_path + self.status = 'There were errors' + + def _input_latex(self): + return self.__latex_task.get_status(), self.__latex_task.get_outname() + + def _execute(self): + self.status = 'There were errors' + + # If latex succeeded with output, atomically commit the output + status, outname = self._input('latex') + if status != 0 or outname is None: + debug('not committing (status {}, outname {})', status, outname) + if outname is None: + self.status = 'No pages of output' + return RunResult([], None) + + commit = self.__output_path or os.path.basename(outname) + if os.path.abspath(commit) == os.path.abspath(outname): + debug('skipping commit (outname is commit name)') + self.status = None + return RunResult([], None) + + try: + if os.path.exists(commit) and filecmp.cmp(outname, commit): + debug('skipping commit ({} and {} are identical)', + outname, commit) + # To avoid confusion, touch the output file + open(outname, 'r+b').close() + else: + debug('commiting {} to {}', outname, commit) + shutil.copy(outname, outname + '~') + os.rename(outname + '~', commit) + except OSError as e: + raise TaskError('error committing latex output: {}'.format(e)) from e + self._input('file', outname) + self.status = None + return RunResult([commit], None) + +class LaTeXFilter: + TRACE = False # Set to enable detailed parse tracing + + def __init__(self, nowarns=[]): + self.__data = '' + self.__restart_pos = 0 + self.__restart_file_stack = [] + self.__restart_messages_len = 0 + self.__messages = [] + self.__first_file = None + self.__fatal_error = False + self.__missing_includes = False + self.__pageno = 1 + self.__restart_pageno = 1 + + self.__suppress = {cls: 0 for cls in nowarns} + + def feed(self, data, eof=False): + """Feed LaTeX log data to the parser. + + The log data can be from LaTeX's standard output, or from the + log file. If there will be no more data, set eof to True. + """ + + self.__data += data + self.__data_complete = eof + + # Reset to last known-good restart point + self.__pos = self.__restart_pos + self.__file_stack = self.__restart_file_stack.copy() + self.__messages = self.__messages[:self.__restart_messages_len] + self.__lstart = self.__lend = -1 + self.__pageno = self.__restart_pageno + + # Parse forward + while self.__pos < len(self.__data): + self.__noise() + + # Handle suppressed warnings + if eof: + msgs = ['%d %s warning%s' % (count, cls, "s" if count > 1 else "") + for cls, count in self.__suppress.items() if count] + if msgs: + self.__message('info', None, + '%s not shown (use -Wall to show them)' % + ', '.join(msgs), filename=self.__first_file) + + if eof and len(self.__file_stack) and not self.__fatal_error: + # Fatal errors generally cause TeX to "succumb" without + # closing the file stack, so don't complain in that case. + self.__message('warning', None, + "unbalanced `(' in log; file names may be wrong") + return self + + def get_messages(self): + """Return a list of warning and error Messages.""" + return self.__messages + + def get_file_stack(self): + """Return the file stack for the data that has been parsed. + + This results a list from outermost file to innermost file. + The list may be empty. + """ + + return self.__file_stack + + def has_missing_includes(self): + """Return True if the log reported missing \\include files.""" + return self.__missing_includes + + def __save_restart_point(self): + """Save the current state as a known-good restart point. + + On the next call to feed, the parser will reset to this point. + """ + self.__restart_pos = self.__pos + self.__restart_file_stack = self.__file_stack.copy() + self.__restart_messages_len = len(self.__messages) + self.__restart_pageno = self.__pageno + + def __message(self, typ, lineno, msg, cls=None, filename=None): + if cls is not None and cls in self.__suppress: + self.__suppress[cls] += 1 + return + filename = filename or (self.__file_stack[-1] if self.__file_stack + else self.__first_file) + self.__messages.append(Message(typ, filename, lineno, msg)) + + def __ensure_line(self): + """Update lstart and lend.""" + if self.__lstart <= self.__pos < self.__lend: + return + self.__lstart = self.__data.rfind('\n', 0, self.__pos) + 1 + self.__lend = self.__data.find('\n', self.__pos) + 1 + if self.__lend == 0: + self.__lend = len(self.__data) + + @property + def __col(self): + """The 0-based column number of __pos.""" + self.__ensure_line() + return self.__pos - self.__lstart + + @property + def __avail(self): + return self.__pos < len(self.__data) + + def __lookingat(self, needle): + return self.__data.startswith(needle, self.__pos) + + def __lookingatre(self, regexp, flags=0): + return re.compile(regexp, flags=flags).match(self.__data, self.__pos) + + def __skip_line(self): + self.__ensure_line() + self.__pos = self.__lend + + def __consume_line(self, unwrap=False): + self.__ensure_line() + data = self.__data[self.__pos:self.__lend] + self.__pos = self.__lend + if unwrap: + # TeX helpfully wraps all terminal output at 79 columns + # (max_print_line). If requested, unwrap it. There's + # simply no way to do this perfectly, since there could be + # a line that happens to be 79 columns. + # + # We check for >=80 because a bug in LuaTeX causes it to + # wrap at 80 columns instead of 79 (LuaTeX #900). + while self.__lend - self.__lstart >= 80: + if self.TRACE: print('<{}> wrapping'.format(self.__pos)) + self.__ensure_line() + data = data[:-1] + self.__data[self.__pos:self.__lend] + self.__pos = self.__lend + return data + + # Parser productions + + def __noise(self): + # Most of TeX's output is line noise that combines error + # messages, warnings, file names, user errors and warnings, + # and echos of token lists and other input. This attempts to + # tease these apart, paying particular attention to all of the + # places where TeX echos input so that parens in the input do + # not confuse the file name scanner. There are three + # functions in TeX that echo input: show_token_list (used by + # runaway and show_context, which is used by print_err), + # short_display (used by overfull/etc h/vbox), and show_print + # (used in issue_message and the same places as + # show_token_list). + lookingat, lookingatre = self.__lookingat, self.__lookingatre + if self.__col == 0: + # The following messages are always preceded by a newline + if lookingat('! '): + return self.__errmessage() + if lookingat('!pdfTeX error: '): + return self.__pdftex_fail() + if lookingat('Runaway '): + return self.__runaway() + if lookingatre(r'(Overfull|Underfull|Loose|Tight) \\[hv]box \('): + return self.__bad_box() + if lookingatre('(Package |Class |LaTeX |pdfTeX )?(\w+ )?warning: ', re.I): + return self.__generic_warning() + if lookingatre('No file .*\\.tex\\.$', re.M): + # This happens with \includes of missing files. For + # whatever reason, LaTeX doesn't consider this even + # worth a warning, but I do! + self.__message('warning', None, + self.__simplify_message( + self.__consume_line(unwrap=True).strip())) + self.__missing_includes = True + return + # Other things that are common and irrelevant + if lookingatre(r'(Package|Class|LaTeX) (\w+ )?info: ', re.I): + return self.__generic_info() + if lookingatre(r'(Document Class|File|Package): '): + # Output from "\ProvidesX" + return self.__consume_line(unwrap=True) + if lookingatre(r'\\\w+=\\[a-z]+\d+\n'): + # Output from "\new{count,dimen,skip,...}" + return self.__consume_line(unwrap=True) + + # print(self.__data[self.__lstart:self.__lend].rstrip()) + # self.__pos = self.__lend + # return + + # Now that we've substantially reduced the spew and hopefully + # eliminated all input echoing, we're left with the file name + # stack, page outs, and random other messages from both TeX + # and various packages. We'll assume at this point that all + # parentheses belong to the file name stack or, if they're in + # random other messages, they're at least balanced and nothing + # interesting happens between them. For page outs, ship_out + # prints a space if not at the beginning of a line, then a + # "[", then the page number being shipped out (this is + # usually, but not always, followed by "]"). + m = re.compile(r'[(){}\n]|(?<=[\n ])\[\d+', re.M).\ + search(self.__data, self.__pos) + if m is None: + self.__pos = len(self.__data) + return + self.__pos = m.start() + 1 + ch = self.__data[m.start()] + if ch == '\n': + # Save this as a known-good restart point for incremental + # parsing, since we definitely didn't match any of the + # known message types above. + self.__save_restart_point() + elif ch == '[': + # This is printed at the end of a page, so we're beginning + # page n+1. + self.__pageno = int(self.__lookingatre(r'\d+').group(0)) + 1 + elif ((self.__data.startswith('`', m.start() - 1) or + self.__data.startswith('`\\', m.start() - 2)) and + self.__data.startswith('\'', m.start() + 1)): + # (, ), {, and } sometimes appear in TeX's error + # descriptions, but they're always in `'s (and sometimes + # backslashed) + return + elif ch == '(': + # XXX Check that the stack doesn't drop to empty and then re-grow + first = self.__first_file is None and self.__col == 1 + filename = self.__filename() + self.__file_stack.append(filename) + if first: + self.__first_file = filename + if self.TRACE: + print('<{}>{}enter {}'.format( + m.start(), ' '*len(self.__file_stack), filename)) + elif ch == ')': + if len(self.__file_stack): + if self.TRACE: + print('<{}>{}exit {}'.format( + m.start(), ' '*len(self.__file_stack), + self.__file_stack[-1])) + self.__file_stack.pop() + else: + self.__message('warning', None, + "extra `)' in log; file names may be wrong ") + elif ch == '{': + # TeX uses this for various things we want to ignore, like + # file names and print_mark. Consume up to the '}' + epos = self.__data.find('}', self.__pos) + if epos != -1: + self.__pos = epos + 1 + else: + self.__message('warning', None, + "unbalanced `{' in log; file names may be wrong") + elif ch == '}': + self.__message('warning', None, + "extra `}' in log; file names may be wrong") + + def __filename(self): + initcol = self.__col + first = True + name = '' + # File names may wrap, but if they do, TeX will always print a + # newline before the open paren + while first or (initcol == 1 and self.__lookingat('\n') + and self.__col >= 79): + if not first: + self.__pos += 1 + m = self.__lookingatre(r'[^(){} \n]*') + name += m.group() + self.__pos = m.end() + first = False + return name + + def __simplify_message(self, msg): + msg = re.sub(r'^(?:Package |Class |LaTeX |pdfTeX )?([^ ]+) (?:Error|Warning): ', + r'[\1] ', msg, flags=re.I) + msg = re.sub(r'\.$', '', msg) + msg = re.sub(r'has occurred (while \\output is active)', r'\1', msg) + return msg + + def __errmessage(self): + # Procedure print_err (including \errmessage, itself used by + # LaTeX's \GenericError and all of its callers), as well as + # fatal_error. Prints "\n! " followed by error text + # ("Emergency stop" in the case of fatal_error). print_err is + # always followed by a call to error, which prints a period, + # and a newline... + msg = self.__consume_line(unwrap=True)[1:].strip() + is_fatal_error = (msg == 'Emergency stop.') + msg = self.__simplify_message(msg) + # ... and then calls show_context, which prints the input + # stack as pairs of lines giving the context. These context + # lines are truncated so they never wrap. Each pair of lines + # will start with either "<something> " if the context is a + # token list, "<*> " for terminal input (or command line), + # "<read ...>" for stream reads, something like "\macroname + # #1->" for macros (though everything after \macroname is + # subject to being elided as "..."), or "l.[0-9]+ " if it's a + # file. This is followed by the errant input with a line + # break where the error occurred. + lineno = None + found_context = False + stack = [] + while self.__avail: + m1 = self.__lookingatre(r'<([a-z ]+|\*|read [^ >]*)> |\\.*(->|...)') + m2 = self.__lookingatre('l\.[0-9]+ ') + if m1: + found_context = True + pre = self.__consume_line().rstrip('\n') + stack.append(pre) + elif m2: + found_context = True + pre = self.__consume_line().rstrip('\n') + info, rest = pre.split(' ', 1) + lineno = int(info[2:]) + stack.append(rest) + elif found_context: + # Done with context + break + if found_context: + # Consume the second context line + post = self.__consume_line().rstrip('\n') + # Clean up goofy trailing ^^M TeX sometimes includes + post = re.sub(r'\^\^M$', '', post) + if post[:len(pre)].isspace() and not post.isspace(): + stack.append(len(stack[-1])) + stack[-2] += post[len(pre):] + else: + # If we haven't found the context, skip the line. + self.__skip_line() + stack_msg = '' + for i, trace in enumerate(stack): + stack_msg += ('\n ' + (' ' * trace) + '^' + if isinstance(trace, int) else + '\n at ' + trace.rstrip() if i == 0 else + '\n from ' + trace.rstrip()) + + if is_fatal_error: + # fatal_error always prints one additional line of message + info = self.__consume_line().strip() + if info.startswith('*** '): + info = info[4:] + msg += ': ' + info.lstrip('(').rstrip(')') + + self.__message('error', lineno, msg + stack_msg) + self.__fatal_error = True + + def __pdftex_fail(self): + # Procedure pdftex_fail. Prints "\n!pdfTeX error: ", the + # message, and a newline. Unlike print_err, there's never + # context. + msg = self.__consume_line(unwrap=True)[1:].strip() + msg = self.__simplify_message(msg) + self.__message('error', None, msg) + + def __runaway(self): + # Procedure runaway. Prints "\nRunaway ...\n" possibly + # followed by token list (user text). Always followed by a + # call to print_err, so skip lines until we see the print_err. + self.__skip_line() # Skip "Runaway ...\n" + if not self.__lookingat('! ') and self.__avail: + # Skip token list, which is limited to one line + self.__skip_line() + + def __bad_box(self): + # Function hpack and vpack. hpack prints a warning, a + # newline, then a short_display of the offending text. + # Unfortunately, there's nothing indicating the end of the + # offending text, but it should be on one (possible wrapped) + # line. vpack prints a warning and then, *unless output is + # active*, a newline. The missing newline is probably a bug, + # but it sure makes our lives harder. + origpos = self.__pos + msg = self.__consume_line() + m = re.search(r' in (?:paragraph|alignment) at lines ([0-9]+)--([0-9]+)', msg) or \ + re.search(r' detected at line ([0-9]+)', msg) + if m: + # Sometimes TeX prints crazy line ranges like "at lines + # 8500--250". The lower number seems roughly sane, so use + # that. I'm not sure what causes this, but it may be + # related to shipout routines messing up line registers. + lineno = min(int(m.group(1)), int(m.groups()[-1])) + msg = msg[:m.start()] + else: + m = re.search(r' while \\output is active', msg) + if m: + lineno = None + msg = msg[:m.end()] + else: + self.__message('warning', None, + 'malformed bad box message in log') + return + # Back up to the end of the known message text + self.__pos = origpos + m.end() + if self.__lookingat('\n'): + # We have a newline, so consume it and look for the + # offending text. + self.__pos += 1 + # If there is offending text, it will start with a font + # name, which will start with a \. + if 'hbox' in msg and self.__lookingat('\\'): + self.__consume_line(unwrap=True) + msg = self.__simplify_message(msg) + ' (page {})'.format(self.__pageno) + cls = msg.split(None, 1)[0].lower() + self.__message('warning', lineno, msg, cls=cls) + + def __generic_warning(self): + # Warnings produced by LaTeX's \GenericWarning (which is + # called by \{Package,Class}Warning and \@latex@warning), + # warnings produced by pdftex_warn, and other random warnings. + msg, cls = self.__generic_info() + # Most warnings include an input line emitted by \on@line + m = re.search(' on input line ([0-9]+)', msg) + if m: + lineno = int(m.group(1)) + msg = msg[:m.start()] + else: + lineno = None + msg = self.__simplify_message(msg) + self.__message('warning', lineno, msg, cls=cls) + + def __generic_info(self): + # Messages produced by LaTeX's \Generic{Error,Warning,Info} + # and things that look like them + msg = self.__consume_line(unwrap=True).strip() + # Package and class messages are continued with lines + # containing '(package name) ' + pkg_name = msg.split(' ', 2)[1] + prefix = '(' + pkg_name + ') ' + while self.__lookingat(prefix): + # Collect extra lines. It's important that we keep these + # because they may contain context information like line + # numbers. + extra = self.__consume_line(unwrap=True) + msg += ' ' + extra[len(prefix):].strip() + return msg, pkg_name.lower() + +################################################################## +# BibTeX task +# + +class BibTeX(Task): + def __init__(self, db, latex_task, cmd, cmd_args, nowarns, obj_dir): + super().__init__(db, 'bibtex::' + normalize_input_path( + latex_task.get_tex_filename())) + self.__latex_task = latex_task + self.__cmd = cmd + self.__cmd_args = cmd_args + self.__obj_dir = obj_dir + + def stable(self): + # If bibtex doesn't have its inputs, then it's stable because + # it has no effect on system state. + jobname = self.__latex_task.get_jobname() + if jobname is None: + # We don't know where the .aux file is until latex has run + return True + if not os.path.exists(jobname + '.aux'): + # Input isn't ready, so bibtex will simply fail without + # affecting system state. Hence, this task is trivially + # stable. + return True + if not self.__find_bib_cmds(os.path.dirname(jobname), jobname + '.aux'): + # The tex file doesn't refer to any bibliographic data, so + # don't run bibtex. + return True + + return super().stable() + + def __find_bib_cmds(self, basedir, auxname, stack=()): + debug('scanning for bib commands in {}'.format(auxname)) + if auxname in stack: + raise TaskError('.aux file loop') + stack = stack + (auxname,) + + try: + aux_data = open(auxname, errors='surrogateescape').read() + except FileNotFoundError: + # The aux file may not exist if latex aborted + return False + if re.search(r'^\\bibstyle\{', aux_data, flags=re.M) or \ + re.search(r'^\\bibdata\{', aux_data, flags=re.M): + return True + + if re.search(r'^\\abx@aux@cite\{', aux_data, flags=re.M): + # biber citation + return True + + # Recurse into included aux files (see aux_input_command), in + # case \bibliography appears in an \included file. + for m in re.finditer(r'^\\@input\{([^}]*)\}', aux_data, flags=re.M): + if self.__find_bib_cmds(basedir, os.path.join(basedir, m.group(1)), + stack): + return True + + return False + + def _input_args(self): + if self.__is_biber(): + aux_name = os.path.basename(self.__latex_task.get_jobname()) + else: + aux_name = os.path.basename(self.__latex_task.get_jobname()) + '.aux' + return [self.__cmd] + self.__cmd_args + [aux_name] + + def _input_cwd(self): + return os.path.dirname(self.__latex_task.get_jobname()) + + def _input_auxfile(self, auxname): + # We don't consider the .aux files regular inputs. + # Instead, we extract just the bit that BibTeX cares about + # and depend on that. See get_aux_command_and_process in + # bibtex.web. + debug('hashing filtered aux file {}', auxname) + try: + with open(auxname, 'rb') as aux: + h = hashlib.sha256() + for line in aux: + if line.startswith((b'\\citation{', b'\\bibdata{', + b'\\bibstyle{', b'\\@input{', + b'\\abx@aux@cite{')): + h.update(line) + return h.hexdigest() + except FileNotFoundError: + debug('{} does not exist', auxname) + return None + + def __path_join(self, first, rest): + if rest is None: + # Append ':' to keep the default search path + return first + ':' + return first + ':' + rest + + def __is_biber(self): + return "biber" in self.__cmd + + def _execute(self): + # This gets complicated when \include is involved. \include + # switches to a different aux file and records its path in the + # main aux file. However, BibTeX does not consider this path + # to be relative to the location of the main aux file, so we + # have to run BibTeX *in the output directory* for it to + # follow these includes (there's no way to tell BibTeX other + # locations to search). Unfortunately, this means BibTeX will + # no longer be able to find local bib or bst files, but so we + # tell it where to look by setting BIBINPUTS and BSTINPUTS + # (luckily we can control this search). We have to pass this + # same environment down to Kpathsea when we resolve the paths + # in BibTeX's log. + args, cwd = self._input('args'), self._input('cwd') + debug('running {} in {}', args, cwd) + + env = os.environ.copy() + env['BIBINPUTS'] = self.__path_join(os.getcwd(), env.get('BIBINPUTS')) + env['BSTINPUTS'] = self.__path_join(os.getcwd(), env.get('BSTINPUTS')) + + try: + verbose_cmd(args, cwd, env) + p = subprocess.Popen(args, cwd=cwd, env=env, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = self.__feed_terminal(p.stdout) + status = p.wait() + except OSError as e: + raise TaskError('failed to execute bibtex task: ' + str(e)) from e + + inputs, auxnames, outbase = self.__parse_inputs(stdout, cwd, env) + if not inputs and not auxnames: + # BibTeX failed catastrophically. + print(stdout, file=sys.stderr) + raise TaskError('failed to execute bibtex task') + + # Register environment variable inputs + for env_var in ['TEXMFOUTPUT', 'BSTINPUTS', 'BIBINPUTS', 'PATH']: + self._input('env', env_var) + + # Register file inputs + for path in auxnames: + self._input('auxfile', path) + for path in inputs: + self._input('file', path) + + if self.__is_biber(): + outbase = os.path.join(cwd, outbase) + outputs = [outbase + '.bbl', outbase + '.blg'] + return RunResult(outputs, {'outbase': outbase, 'status': status, + 'inputs': inputs}) + + def __feed_terminal(self, stdout): + with Progress('bibtex') as progress: + buf, linebuf = [], '' + while True: + data = os.read(stdout.fileno(), 4096) + if not data: + break + # See "A note about encoding" above + data = data.decode('ascii', errors='surrogateescape') + buf.append(data) + linebuf += data + while '\n' in linebuf: + line, _, linebuf = linebuf.partition('\n') + if line.startswith('Database file'): + progress.update(line.split(': ', 1)[1]) + return ''.join(buf) + + def __parse_inputs(self, log, cwd, env): + # BibTeX conveniently logs every file that it opens, and its + # log is actually sensible (see calls to a_open_in in + # bibtex.web.) The only trick is that these file names are + # pre-kpathsea lookup and may be relative to the directory we + # ran BibTeX in. + # + # Because BibTeX actually depends on very little in the .aux + # file (and it's likely other things will change in the .aux + # file), we don't count the whole .aux file as an input, but + # instead depend only on the lines that matter to BibTeX. + kpathsea = Kpathsea('bibtex') + inputs = [] + auxnames = [] + outbase = None + for line in log.splitlines(): + m = re.match('(?:The top-level auxiliary file:' + '|A level-[0-9]+ auxiliary file:) (.*)', line) + if m: + auxnames.append(os.path.join(cwd, m.group(1))) + continue + m = re.match('(?:(The style file:)|(Database file #[0-9]+:)) (.*)', + line) + if m: + filename = m.group(3) + if m.group(1): + filename = kpathsea.find_file(filename, 'bst', cwd, env) + elif m.group(2): + filename = kpathsea.find_file(filename, 'bib', cwd, env) + + # If this path is relative to the source directory, + # clean it up for error reporting and portability of + # the dependency DB + if filename.startswith('/'): + relname = os.path.relpath(filename) + if '../' not in relname: + filename = relname + + inputs.append(filename) + + # biber output + m = re.search("Found BibTeX data source '(.*?)'", + line) + if m: + filename = m.group(1) + inputs.append(filename) + + m = re.search("Logfile is '(.*?)'", line) + if m: + outbase = m.group(1)[:-4] + + if outbase is None: + outbase = auxnames[0][:-4] + + return inputs, auxnames, outbase + + def report(self): + extra = self._get_result_extra() + if extra is None: + return 0 + + # Parse and pretty-print the log + log = open(extra['outbase'] + '.blg', 'rt').read() + inputs = extra['inputs'] + for msg in BibTeXFilter(log, inputs).get_messages(): + msg.emit() + + # BibTeX exits with 1 if there are warnings, 2 if there are + # errors, and 3 if there are fatal errors (sysdep.h). + # Translate to a normal UNIX exit status. + if extra['status'] >= 2: + return 1 + return 0 + +class BibTeXFilter: + def __init__(self, data, inputs): + self.__inputs = inputs + self.__key_locs = None + + self.__messages = [] + + prev_line = '' + for line in data.splitlines(): + msg = self.__process_line(prev_line, line) + if msg is not None: + self.__messages.append(Message(*msg)) + prev_line = line + + def get_messages(self): + """Return a list of warning and error Messages.""" + # BibTeX reports most errors in no particular order. Sort by + # file and line. + return sorted(self.__messages, + key=lambda msg: (msg.filename or '', msg.lineno or 0)) + + def __process_line(self, prev_line, line): + m = None + def match(regexp): + nonlocal m + m = re.match(regexp, line) + return m + + # BibTeX has many error paths, but luckily the set is closed, + # so we can find all of them. This first case is the + # workhorse format. + # + # AUX errors: aux_err/aux_err_return/aux_err_print + # + # BST errors: bst_ln_num_print/bst_err/ + # bst_err_print_and_look_for_blank_line_return/ + # bst_warn_print/bst_warn/ + # skip_token/skip_token_print/ + # bst_ext_warn/bst_ext_warn_print/ + # bst_ex_warn/bst_ex_warn_print/ + # bst_mild_ex_warn/bst_mild_ex_warn_print/ + # bst_string_size_exceeded + # + # BIB errors: bib_ln_num_print/ + # bib_err_print/bib_err/ + # bib_warn_print/bib_warn/ + # bib_one_of_two_expected_err/macro_name_warning/ + if match('(.*?)---?line ([0-9]+) of file (.*)'): + # Sometimes the real error is printed on the previous line + if m.group(1) == 'while executing': + # bst_ex_warn. The real message is on the previous line + text = prev_line + else: + text = m.group(1) or prev_line + typ, msg = self.__canonicalize(text) + return (typ, m.group(3), int(m.group(2)), msg) + + # overflow/print_overflow + if match('Sorry---you\'ve exceeded BibTeX\'s (.*)'): + return ('error', None, None, 'capacity exceeded: ' + m.group(1)) + # confusion/print_confusion + if match('(.*)---this can\'t happen$'): + return ('error', None, None, 'internal error: ' + m.group(1)) + # aux_end_err + if match('I found (no .*)---while reading file (.*)'): + return ('error', m.group(2), None, m.group(1)) + # bad_cross_reference_print/ + # nonexistent_cross_reference_error/ + # @<Complain about a nested cross reference@> + # + # This is split across two lines. Match the second. + if match('^refers to entry "'): + typ, msg = self.__canonicalize(prev_line + ' ' + line) + msg = re.sub('^a (bad cross reference)', '\\1', msg) + # Try to give this key a location + filename = lineno = None + m2 = re.search(r'--entry "[^"]"', prev_line) + if m2: + filename, lineno = self.__find_key(m2.group(1)) + return (typ, filename, lineno, msg) + # print_missing_entry + if match('Warning--I didn\'t find a database entry for (".*")'): + return ('warning', None, None, + 'no database entry for ' + m.group(1)) + # x_warning + if match('Warning--(.*)'): + # Most formats give warnings about "something in <key>". + # Try to match it up. + filename = lineno = None + for m2 in reversed(list(re.finditer(r' in ([^, \t\n]+)\b', line))): + if m2: + filename, lineno = self.__find_key(m2.group(1)) + if filename: + break + return ('warning', filename, lineno, m.group(1)) + # @<Clean up and leave@> + if match('Aborted at line ([0-9]+) of file (.*)'): + return ('info', m.group(2), int(m.group(1)), 'aborted') + + # biber type errors + if match('^.*> WARN - (.*)$'): + print ('warning', None, None, m.group(1)) + m2 = re.match("(.*) in file '(.*?)', skipping ...", m.group(1)) + if m2: + return ('warning', m2.group(2), "0", m2.group(1)) + return ('warning', None, None, m.group(1)) + + if match('^.*> ERROR - (.*)$'): + m2 = re.match("BibTeX subsystem: (.*?), line (\d+), (.*)$", m.group(1)) + if m2: + return ('error', m2.group(1), m2.group(2), m2.group(3)) + return ('error', None, None, m.group(1)) + + + def __canonicalize(self, msg): + if msg.startswith('Warning'): + msg = re.sub('^Warning-*', '', msg) + typ = 'warning' + else: + typ = 'error' + msg = re.sub('^I(\'m| was)? ', '', msg) + msg = msg[:1].lower() + msg[1:] + return typ, msg + + def __find_key(self, key): + if self.__key_locs is None: + p = BibTeXKeyParser() + self.__key_locs = {} + for filename in self.__inputs: + data = open(filename, 'rt', errors='surrogateescape').read() + for pkey, lineno in p.parse(data): + self.__key_locs.setdefault(pkey, (filename, lineno)) + return self.__key_locs.get(key, (None, None)) + +class BibTeXKeyParser: + """Just enough of a BibTeX parser to find keys.""" + + def parse(self, data): + IDENT_RE = '(?![0-9])([^\x00-\x20\x80-\xff \t"#%\'(),={}]+)' + self.__pos, self.__data = 0, data + # Find the next entry + while self.__consume('[^@]*@[ \t\n]*'): + # What type of entry? + if not self.__consume(IDENT_RE + '[ \t\n]*'): + continue + typ = self.__m.group(1) + if typ == 'comment': + continue + start = self.__pos + if not self.__consume('([{(])[ \t\n]*'): + continue + closing, key_re = {'{' : ('}', '([^, \t\n}]*)'), + '(' : (')', '([^, \t\n]*)')}[self.__m.group(1)] + if typ not in ('preamble', 'string'): + # Regular entry; get key + if self.__consume(key_re): + yield self.__m.group(1), self.__lineno() + # Consume body of entry + self.__pos = start + self.__balanced(closing) + + def __consume(self, regexp): + self.__m = re.compile(regexp).match(self.__data, self.__pos) + if self.__m: + self.__pos = self.__m.end() + return self.__m + + def __lineno(self): + return self.__data.count('\n', 0, self.__pos) + 1 + + def __balanced(self, closing): + self.__pos += 1 + level = 0 + skip = re.compile('[{}' + closing + ']') + while True: + m = skip.search(self.__data, self.__pos) + if not m: + break + self.__pos = m.end() + ch = m.group(0) + if level == 0 and ch == closing: + break + elif ch == '{': + level += 1 + elif ch == '}': + level -= 1 + +class Kpathsea: + def __init__(self, program_name): + self.__progname = program_name + + def find_file(self, name, format, cwd=None, env=None): + """Return the resolved path of 'name' or None.""" + + args = ['kpsewhich', '-progname', self.__progname, '-format', format, + name] + try: + verbose_cmd(args, cwd, env) + path = subprocess.check_output( + args, cwd=cwd, env=env, universal_newlines=True).strip() + except subprocess.CalledProcessError as e: + if e.returncode != 1: + raise + return None + if cwd is None: + return path + return os.path.join(cwd, path) + +if __name__ == "__main__": + main() diff --git a/jfp-paper/mathptmx.sty b/jfp-paper/mathptmx.sty new file mode 100644 index 0000000000000000000000000000000000000000..85b08b4bfb3b530e0b4c9e04fbda5d8a1c69c142 --- /dev/null +++ b/jfp-paper/mathptmx.sty @@ -0,0 +1,42 @@ +\def\filedate{1998/06/30} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{mathptmx}[\filedate\space + Times + math package from fontinst] +\def\rmdefault{ptm} +\DeclareSymbolFont{operators} {OT1}{ztmcm}{m}{n} +\DeclareSymbolFont{letters} {OML}{ztmcm}{m}{it} +\DeclareSymbolFont{symbols} {OMS}{ztmcm}{m}{n} +\DeclareSymbolFont{largesymbols}{OMX}{ztmcm}{m}{n} +\DeclareSymbolFont{bold} {OT1}{ptm}{bx}{n} +\DeclareSymbolFont{italic} {OT1}{ptm}{m}{it} +\@ifundefined{mathbf}{}{\DeclareMathAlphabet{\mathbf}{OT1}{ptm}{bx}{n}} +\@ifundefined{mathit}{}{\DeclareMathAlphabet{\mathit}{OT1}{ptm}{m}{it}} +\DeclareMathSymbol{\omicron}{0}{operators}{`\o} +\thinmuskip=2mu +\medmuskip=2.5mu plus 1mu minus 1mu +\thickmuskip=4mu plus 1.5mu minus 1mu + \let\@tempa\version@elt + \def\version@elt#1{% + \ifx\mv@bold#1\else\noexpand\version@elt\noexpand#1\fi} + \edef\version@list{\version@list} + \let\version@elt\@tempa + \let\mv@bold\@undefined +\def\boldmath{% + \PackageWarning{there is no bold Symbol font}% + \global\let\boldmath=\relax +} +\DeclareMathSizes{5}{5}{5}{5} +\DeclareMathSizes{6}{6}{5}{5} +\DeclareMathSizes{7}{7}{5}{5} +\DeclareMathSizes{8}{8}{6}{5} +\DeclareMathSizes{9}{9}{7}{5} +\DeclareMathSizes{10}{10}{7.4}{6} +\DeclareMathSizes{10.95}{10.95}{8}{6} +\DeclareMathSizes{12}{12}{9}{7} +\DeclareMathSizes{14.4}{14.4}{10.95}{8} +\DeclareMathSizes{17.28}{17.28}{12}{10} +\DeclareMathSizes{20.74}{20.74}{14.4}{12} +\DeclareMathSizes{24.88}{24.88}{17.28}{14.4} +\endinput +%% +%% End of file `mathptmx.sty'. \ No newline at end of file