summaryrefslogtreecommitdiff
path: root/macros/latex/contrib
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-08-20 03:01:54 +0000
committerNorbert Preining <norbert@preining.info>2021-08-20 03:01:54 +0000
commitda0e202bdd0dc2f52f28ae0d96dc96969826890b (patch)
tree589f0ecfc7c29d3eef6c67e5a4d023aee511af74 /macros/latex/contrib
parent0c52816f121429fd9e4277d4dc8895f92c2bdb52 (diff)
CTAN sync 202108200301
Diffstat (limited to 'macros/latex/contrib')
-rw-r--r--macros/latex/contrib/animate/ChangeLog3
-rw-r--r--macros/latex/contrib/animate/animate.pdfbin3869206 -> 3878981 bytes
-rw-r--r--macros/latex/contrib/animate/animate.sty10
-rw-r--r--macros/latex/contrib/animate/animate.tex24
-rw-r--r--macros/latex/contrib/easybook/easybook.dtx18
-rw-r--r--macros/latex/contrib/easybook/easybook.pdfbin590797 -> 590649 bytes
-rw-r--r--macros/latex/contrib/easybook/easybook.tex12
-rw-r--r--macros/latex/contrib/gamebooklib/Makefile20
-rw-r--r--macros/latex/contrib/gamebooklib/README41
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib.dtx998
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib.ins53
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib.pdfbin0 -> 265430 bytes
-rwxr-xr-xmacros/latex/contrib/gamebooklib/gamebooklib_countpagesperseed.sh62
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib_test.pdfbin0 -> 117057 bytes
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib_test.tex109
-rw-r--r--macros/latex/contrib/lambdax/lambdax.bib26
-rw-r--r--macros/latex/contrib/lambdax/lambdax.dtx19
-rw-r--r--macros/latex/contrib/lambdax/lambdax.pdfbin0 -> 555406 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc-cn.pdfbin319814 -> 319918 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc-en.pdfbin199160 -> 199267 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc-fr.pdfbin200071 -> 200190 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc.dtx6
-rw-r--r--macros/latex/contrib/projlib/ProjLib.dtx22
23 files changed, 1371 insertions, 52 deletions
diff --git a/macros/latex/contrib/animate/ChangeLog b/macros/latex/contrib/animate/ChangeLog
index df96396f01..c7f679fd55 100644
--- a/macros/latex/contrib/animate/ChangeLog
+++ b/macros/latex/contrib/animate/ChangeLog
@@ -1,3 +1,6 @@
+2021-08-19
+ * fix: wrong orientation of button faces on landscape pages (dvips)
+
2021-06-11
* fix: `undefined references' warning, when placing animation in a \phantom
diff --git a/macros/latex/contrib/animate/animate.pdf b/macros/latex/contrib/animate/animate.pdf
index 1cb9d5a557..5a8488adc2 100644
--- a/macros/latex/contrib/animate/animate.pdf
+++ b/macros/latex/contrib/animate/animate.pdf
Binary files differ
diff --git a/macros/latex/contrib/animate/animate.sty b/macros/latex/contrib/animate/animate.sty
index a492a7677d..ed9681e490 100644
--- a/macros/latex/contrib/animate/animate.sty
+++ b/macros/latex/contrib/animate/animate.sty
@@ -13,7 +13,7 @@
\NeedsTeXFormat{LaTeX2e}[2020-10-01]
-\def\@anim@version{2021/06/11}
+\def\@anim@version{2021/08/19}
\ProvidesPackage{animate}
[\@anim@version\space PDF & SVG animations from files and inline graphics]
@@ -793,10 +793,10 @@
\edef\@anim@arg{#1}%
\ifx\@anim@EndLeft\@anim@arg%
\@anim@xbutton{EndLeft}{%
- [-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
+ [-1 0 0 1 15 0] concat
\@anim@btnend}{#2}%
\fi%
\ifx\@anim@EndRight\@anim@arg%
@@ -815,10 +815,10 @@
\fi%
\ifx\@anim@PauseLeft\@anim@arg%
\@anim@xbutton{PauseLeft}{%
- [-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
+ [-1 0 0 1 15 0] concat
\@anim@btnpause}{#2}%
\fi%
\ifx\@anim@PauseRight\@anim@arg%
@@ -830,10 +830,10 @@
\fi%
\ifx\@anim@PlayLeft\@anim@arg%
\@anim@xbutton{PlayLeft}{%
- [-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
+ [-1 0 0 1 15 0] concat
\@anim@btnplay}{#2}%
\fi%
\ifx\@anim@PlayRight\@anim@arg%
@@ -877,10 +877,10 @@
\fi%
\ifx\@anim@StepLeft\@anim@arg%
\@anim@xbutton{StepLeft}{%
- [-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
+ [-1 0 0 1 15 0] concat
\@anim@btnstep}{#2}%
\fi%
\ifx\@anim@StepRight\@anim@arg%
diff --git a/macros/latex/contrib/animate/animate.tex b/macros/latex/contrib/animate/animate.tex
index 4721acff54..a5fb68d90f 100644
--- a/macros/latex/contrib/animate/animate.tex
+++ b/macros/latex/contrib/animate/animate.tex
@@ -5,14 +5,16 @@
% http://mirrors.ctan.org/macros/latex/base/lppl.txt
% for the details of that license.
%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\listfiles
-
-\RequirePackage{pdfmanagement-testphase}
-\DeclareDocumentMetadata{
-% uncompress
+%%% force dvi %%%
+\ifdefined\outputmode\outputmode=0\fi
+\ifdefined\pdfoutput\pdfoutput=0\fi
+%%%%%%% pdfmanagement-testphase %%%%%%
+\RequirePackage{pdfmanagement-testphase} % load the package
+\DeclareDocumentMetadata % activates the PDF management interface
+{
+ %uncompress,
}
-
+%%%%%% /pdfmanagement-testphase %%%%%%
\documentclass[a4paper]{article}
\frenchspacing
\usepackage[buttonbg=0.9]{animate}
@@ -35,7 +37,7 @@
\usepackage{parskip}
\usepackage{tabls}
\usepackage{multirow}
-\usepackage[bookmarksnumbered,linktocpage]{hyperref}
+\usepackage{hyperref}
\usepackage[ocgcolorlinks]{ocgx2}
\usepackage{amsmath}
\usepackage{fancyvrb}
@@ -65,7 +67,8 @@
pdfsubject={Documentation},
pdfauthor={Alexander Grahn},
pdfkeywords={\keywords},
- allcolors=blue
+ allcolors=blue,
+ bookmarksnumbered,linktocpage
}
\def\XeLaTeX{X\kern-.1667em\lower.5ex\hbox{\reflectbox{E}}\kern-.125em\LaTeX}
@@ -1477,12 +1480,11 @@ I would like to thank François Lafont who discovered quite a few bugs and made
\bibitem{chupin} Chupin, M.: \emph{Syracuse MetaPost/Animations.} URL: \href{http://melusine.eu.org/syracuse/metapost/animations/chupin/?idsec=scara}{\texttt{http://melusine.eu.org/}} \href{http://melusine.eu.org/syracuse/metapost/animations/chupin/?idsec=scara}{\texttt{syracuse/metapost/animations/chupin/?idsec=scara}}
\bibitem{dvisvgm} \emph{dvisvgm: A fast DVI to SVG converter} URL: \url{http://dvisvgm.de}
\bibitem{gilg05} Gilg, J.: PDF-Animationen. In: \emph{Die \TeX nische Kom\"odie}, Issue 4, 2005, pp.~30--37
-%%\bibitem{hol} Holeček, J.: \emph{Animations in a pdf\TeX-generated PDF}. URL: \url{http://www.fi.muni.cz/~xholecek/tex/pdfanim.xhtml}
\bibitem{hol} Holeček, J.; Sojka, P.: Animations in pdf\TeX-generated PDF. In: \emph{\TeX, XML, and Digital Typography}, Springer, 2004, pp.~179--191. doi:10.1007/978-3-540-27773-6\textunderscore14
\bibitem{luque12} Luque, M.: \emph{PSTricks : applications.} URL: \url{http://pstricks.blogspot.com}
\bibitem{media4svg} \emph{The media4svg Package}. URL: \url{http://www.ctan.org/pkg/media4svg}
\bibitem{media9} \emph{The media9 Package}. URL: \url{http://www.ctan.org/pkg/media9}
-\bibitem{texsx} \emph{Beamer: animate package and overlay}. URL: \href{https://tex.stackexchange.com/a/385209}{\texttt{https://tex.stackexchange.com}}\\\href{https://tex.stackexchange.com/a/385209}{\texttt{/a/385209}}
+\bibitem{texsx} \emph{Beamer: animate package and overlay}. URL: \href{https://tex.stackexchange.com/a/385209}{\texttt{https://tex.stackexchange.com}}\\ \href{https://tex.stackexchange.com/a/385209}{\texttt{/a/385209}}
\end{thebibliography}
\end{document}
diff --git a/macros/latex/contrib/easybook/easybook.dtx b/macros/latex/contrib/easybook/easybook.dtx
index 778d47e92a..23cdec1049 100644
--- a/macros/latex/contrib/easybook/easybook.dtx
+++ b/macros/latex/contrib/easybook/easybook.dtx
@@ -15,7 +15,7 @@
%<*class>
\NeedsTeXFormat{LaTeX2e}[2020/10/01]
\RequirePackage{l3keys2e}
-\ProvidesExplClass{easybook}{2021/08/16}{1.29}
+\ProvidesExplClass{easybook}{2021/08/18}{1.29c}
{Typeset Chinese theses or books}
\bool_set_false:N \l__eb_compile_draft_bool
@@ -63,7 +63,7 @@
}
\ProcessKeysOptions{easybook}
-\PassOptionsToPackage{CJKmath,quiet}{xeCJK}
+\PassOptionsToPackage{no-math,quiet,CJKmath}{xeCJK}
\eb_put_ctexbook:n { \g__eb_options_clist }
\LoadClass[UTF8]{ctexbook}
@@ -297,7 +297,7 @@
%<*package>
\NeedsTeXFormat{LaTeX2e}[2020/10/01]
\RequirePackage{l3keys2e,etoolbox}
-\ProvidesExplPackage{easybase}{2021/08/16}{1.29}
+\ProvidesExplPackage{easybase}{2021/08/18}{1.29c}
{Typeset Chinese theses or books}
\cs_generate_variant:Nn \dim_add:Nn { NV,Nv }
@@ -1337,7 +1337,7 @@
\newcounter{bichapter}
\newcounter{bisection}[bichapter]
\newcounter{bisubsection}[bisection]
-\cs_set_protected:Npn \eb_current_label:n #1
+\cs_new_protected:Npn \eb_current_label:n #1
{
\tl_set:Nx \@currentlabel
{
@@ -1376,7 +1376,7 @@
{\tl_gset:Nn \eb@before@addbitoc@hook {#2}}
{\tl_gput_right:Nn \eb@before@addbitoc@hook {#2}}
}
-\cs_set_protected:Npn \CTEX@addbitocline #1#2
+\cs_new_protected:Npn \CTEX@addbitocline #1#2
{
\group_begin:
\def\CTEX@prechapter{\CTEX@prebichapter}
@@ -1589,7 +1589,7 @@
\cs_set_eq:NN \imki@indexlevel \use_none:n
\setkeys{imkiindex}{noclearpage}
\IfValueT{#3}{\keys_set:nn { eb/listoc } {#3}}
- \tl_set:Nn \imki@indexheaders
+ \cs_set_protected:Npn \imki@indexheaders
{
\eb_title_number_intoc_spec:nn {#2} {#1}
\cs_set_eq:NN \thispagestyle \use_none:n
@@ -1677,7 +1677,7 @@
\cs_new_protected:Npn \eb_put_newtxmath:n #1
{ \PassOptionsToPackage{#1}{newtxmath} }
-\AfterPreamble
+\eb_at_end_preamble:n
{
\str_case:VnT \l__eb_subfont_math_choice_tl
{
@@ -2131,7 +2131,7 @@
\group_begin:
\tl_set_eq:NN \eb@toc@title \bibname
\IfValueT{##3}{ \keys_set:nn { eb/listoc } {##3} }
- \cs_set:Npn \bibsection
+ \cs_set_protected:Npn \bibsection
{
\eb_title_number_intoc_spec:nn {##2} {##1}
\bool_if:NT \l__eb_toc_multi_column_bool
@@ -2394,7 +2394,7 @@
}
%</package>
%<*tcolorbox>
-\ProvidesExplFile{eb-tcolorbox.cfg}{2021/08/16}{1.29}
+\ProvidesExplFile{eb-tcolorbox.cfg}{2021/08/18}{1.29c}
{Customization of tcolorbox for easybook}
\tl_gset:Nn \eb@tc@line@skip { 0.5\baselineskip }
diff --git a/macros/latex/contrib/easybook/easybook.pdf b/macros/latex/contrib/easybook/easybook.pdf
index 59fc52c31d..281479c7dd 100644
--- a/macros/latex/contrib/easybook/easybook.pdf
+++ b/macros/latex/contrib/easybook/easybook.pdf
Binary files differ
diff --git a/macros/latex/contrib/easybook/easybook.tex b/macros/latex/contrib/easybook/easybook.tex
index 8485acc478..eba882bc04 100644
--- a/macros/latex/contrib/easybook/easybook.tex
+++ b/macros/latex/contrib/easybook/easybook.tex
@@ -12,8 +12,8 @@
name = easybook,
color-scheme = blue,
title = EASYBOOK 使用手册,
- version = v1.29,
- date = 2021/08/16,
+ version = v1.29c,
+ date = 2021/08/18,
authors = 瞿毅,
info = 排版简体中文学位论文和书籍,
email = quee123@foxmail.com,
@@ -316,7 +316,7 @@
\label{sec:interface options}
\begin{commands}
\command*{ctexset}[\marg{键值列表}]
- \cls*{easybook} 扩展了 C\TeX 宏集 \hologo{LaTeX3} 风格键值的通用控制命令 \cs*{ctexset},接口选项同样可用它设置, 原有的 \meta{键值列表} 仍然可用。本文档类目前有九个模块用于实现常规的排版功能,如下表所示,它们既是统一接口 \cs*{ctexset} 的路径,也是相关模块的接口命令名:
+ \cls*{easybook} 扩展了 C\TeX 宏集 \hologo{LaTeX3} 风格键值的通用控制命令 \cs*{ctexset},接口选项同样可用它设置, 原有的 \meta{键值列表} 仍然可用。本文档类目前有 9 个模块用于实现常规的排版功能,如下表所示,它们既是统一接口 \cs*{ctexset} 的路径,也是相关模块的接口命令名:
\begin{center}
\begin{tabular}{*{5}{c}}
\toprule
@@ -547,7 +547,7 @@
\subsubsection{新建定理样式}
\begin{commands}
\command{declaretheorem}[\oarg{键值列表1}\marg{定理环境}\oarg{键值列表2}]
- 声明新的定理环境命令,\cs{newtheorem} 命令与它等效。可选参数的 \meta{键值列表1} 与 \meta{键值列表2} 等效,用法与它们的同名命令一致。键值列表中常用的选项如下:
+ 声明新的定理环境命令,\cs{newtheorem} 命令与它等效。可选参数的 \meta{键值列表1} 与 \meta{键值列表2} 等效,用法与原来的同名命令一致。键值列表中常用的选项如下:
\begin{options}
\keyval*-{name}{定理名}
定理名的默认值是首字母大写的环境名称(英文标题)。
@@ -559,7 +559,7 @@
选项的值为使用 \cs{declaretheoremstyle} 命令新定义的定理样式。
\end{options}
\command{DeclareTheorem}[\marg{环境名}\oarg{英文标题}\marg{中文标题}\darg{盒子风格}\oarg{键值列表}]
- 定理声明命令 \cs{DeclareTheorem} 更加便捷,同样定义一个新的定理环境,与 \cs{declaretheorem} 命令的键值列表支持相同的选项,但它们的区别有:
+ 定理声明命令 \cs{DeclareTheorem} 更加便捷,同样定义一个新的定理环境,\meta{键值列表} 中支持的选项与 \cs{declaretheorem} 命令相同,但它们的区别有:
\begin{itemize}
\item 中英文模式下标题不同,英文标题为可选项,默认为首字母大写的 \meta{环境名}。
\item 自动定义交叉引用的格式,引用标签前缀为定理名。
@@ -567,7 +567,7 @@
\item 新建定理环境默认使用的 \meta{定理样式} 为 \code{easy-theorem},而不是 \pkg*{thmtools} 默认样式。
\end{itemize}
\command{declaretheoremstyle}[\oarg{键值列表1}\marg{定理样式}\oarg{键值列表2}]
- 声明新的定理样式命令,键值列表支持上述 \module*{thmset} 模块中以及 \cs{declaretheorem} 的所有选项。可选参数的 \meta{键值列表1} 与 \meta{键值列表2} 等效,用法与它们的同名命令一致。
+ 声明新的定理样式命令,键值列表支持上述 \module*{thmset} 模块中以及 \cs{declaretheorem} 的所有选项。可选参数的 \meta{键值列表1} 与 \meta{键值列表2} 等效,用法与原来的同名命令一致。
下面简单列举几个定理命令的用法,例如使用预置样式新建一个定理环境猜想:
\begin{ctexexam}
diff --git a/macros/latex/contrib/gamebooklib/Makefile b/macros/latex/contrib/gamebooklib/Makefile
new file mode 100644
index 0000000000..eae8922072
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/Makefile
@@ -0,0 +1,20 @@
+default: gamebooklib_test.pdf gamebooklib.pdf tidy
+
+gamebooklib_test.pdf : gamebooklib_test.tex gamebooklib.sty
+ pdflatex \\nonstopmode\\input gamebooklib_test.tex && \
+ pdflatex \\nonstopmode\\input gamebooklib_test.tex
+
+gamebooklib.sty : gamebooklib.dtx gamebooklib.ins
+ rm -f gamebooklib.sty && latex gamebooklib.ins
+
+gamebooklib.pdf : gamebooklib.sty gamebooklib.dtx
+ pdflatex \\nonstopmode\\input gamebooklib.dtx && \
+ makeindex -s gglo.ist -o gamebooklib.gls gamebooklib.glo && \
+ makeindex -s gind.ist -o gamebooklib.ind gamebooklib.idx && \
+ pdflatex \\nonstopmode\\input gamebooklib.dtx
+
+tidy:
+ rm -f *.log *.ind *.idx *.glo *.gls *.aux *.ilg
+
+clean: tidy
+ rm -f *~ *.sty
diff --git a/macros/latex/contrib/gamebooklib/README b/macros/latex/contrib/gamebooklib/README
new file mode 100644
index 0000000000..01ac270ee2
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/README
@@ -0,0 +1,41 @@
+Copyright (C) 2021 by Robert J Lee
+
+This file 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 2005/12/01 or later.
+
+
+The gamebooklib package, provides a convenient set of macros to assist
+the author choosing to develop a gamebook. In particular, it aims to
+solve 2 non-trivial issues:
+
+1) Writing a set of entries in order, then shuffling them in the
+output routine, preserving reference links, and
+
+2) Allowing LaTeX to output footnotes at the end of an entry, in the
+case where another entry falls below the footnote mark on the page.
+
+
+This package uses the standard TeX .dtx+.ins install mechanism,
+although a UNIX Makefile is provided for convenience to generate all
+files.
+
+The file "gamebooklib_test.tex" provides a simple demonstration of
+this library.
+
+The file "gamebooklib_countpagesperseed.sh" is a utility script using
+bash, perl and pdflatex that will report on the number of pages for
+your document, when entries are shuffled with different pseudorandom
+seeds. This is useful if you have large objects such as graphics and
+want to minimise needless white space. Further instructions are
+provided in the header of that file.
+
+It is suggested that the gamebooklib_countpagesperseed.sh utility
+should be placed on the system path for ease of use, or into any
+utility scripts directory. \ No newline at end of file
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib.dtx b/macros/latex/contrib/gamebooklib/gamebooklib.dtx
new file mode 100644
index 0000000000..eed4fc64c6
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/gamebooklib.dtx
@@ -0,0 +1,998 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2021 by Robert J Lee
+%
+% This file 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 2005/12/01 or later.
+%
+% \fi
+%
+% \iffalse
+% <package>\NeedsTeXFormat{LaTeX2e}[2005/12/01]
+% <package>\ProvidesPackage{gamebooklib}
+% <package> [2021/08/10 v1.0 gamebooklib typesetting]
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{makeidx}
+\usepackage[seed=1234]{lcg}
+\usepackage{gamebooklib}
+\usepackage{indentfirst}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\makeindex
+\begin{document}
+ \DocInput{gamebooklib.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \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 \~}
+%
+% \CheckSum{507}
+%
+% \changes{v1.0}{2021/08/10}{Initial Release}
+%
+% \GetFileInfo{gamebooklib.sty}
+%
+% \DoNotIndex{\let, \edef, \xdef, \relax, \newcommand}
+% \DoNotIndex{\csname, \endcsname, \@M, \@MM, \@gobble}
+% \DoNotIndex{\@ifnextchar, \@tmp, \@undefined, \\}
+% \DoNotIndex{\arabic, \begin, \begingroup, \botmark, \break}
+% \DoNotIndex{\@tmp, \@tmp@, \mytmp@, \tmp@, \tmp@@}
+% \DoNotIndex{\centerline, \cs, \def, \detokenize, \else}
+% \DoNotIndex{\endgroup, \equal, \expandafter, \fi}
+% \DoNotIndex{\gdef, \global, \head, \hspace, \Huge, \if}
+% \DoNotIndex{\ifcsname, \ifhmode, \ifnum, \ifthenelse, \ifvmode}
+% \DoNotIndex{\interlinepenalty, \interlinefootnotepenalty}
+% \DoNotIndex{\large, \leftskip, \mark, \NeedsTeXFormat}
+% \DoNotIndex{\newcounter, \newenvironment, \newtoks, \noexpand}
+% \DoNotIndex{\noindexnt, \nopagebreak, \not, \PackageInfo, \pagebreak}
+% \DoNotIndex{\par, \PassOptionsToClass, \penalty, \ProcessOptions}
+% \DoNotIndex{\protected@xdef, \ProvidesPackage, \rand, \requirecommand}
+% \DoNotIndex{\RequirePackage, \rightskip, \rule, \setbox}
+% \DoNotIndex{\setcounter, \stepcounter, \textbf, \typeout, \value}
+% \DoNotIndex{\vbox, \unvbox, \vfill, \vspace, \vsize}
+% \DoNotIndex{\WarningFilter, \whiledo, \Collect@Body, \CurrentOption}
+% \DoNotIndex{\DeclareOption, \g@addto@macro, \the, \noindent}
+% \DoNotIndex{\interfootnotelinepenalty, \marginpar, \myidx}
+% \DoNotIndex{\addtocounter, \refstepcounter, \label}
+% \DoNotIndex{\iffalse, \iftrue, \outputpenalty, \renewcommand}
+% \DoNotIndex{\noshuffle, \verbose, \endpage, \footnote}
+%
+% \title{The Gamebooklib Package\thanks{This document corresponds to \textsf{Gamebooklib}~\fileversion, dated \filedate.}}
+% \author{Robert J Lee \\ latex@rjlee.homelinux.org}
+%
+% \maketitle
+%
+% \begin{abstract}
+%
+% This package provides macros and environments to allow the user to
+% typeset a series of cross-referenced, numbered ``entries'',
+% shuffled into random order
+%
+% \end{abstract}
+%
+% \section{Introduction}
+%
+% This package was written to allow the typesetting of gamebooks.
+%
+% A gamebook is a book divided into ``entries'' (which may be a single
+% paragraph or longer), each with a sequentially numbered value. At
+% the end of each entry, a link to one or more other numbered
+% entries is given; the reader selects one and they follow through
+% the story in this order. gamebooks traditionally start at the
+% entry numbered~``1'' and some gamebooks have multiple endings,
+% with the final section representing a success or victory for the
+% reader.
+%
+% In particular, this package handles two technical challenges which
+% are tricky to solve with \LaTeX\ directly: writing the ``entries''
+% in order but presenting them in a randomised order; and presenting
+% footnotes at the end of each ``entry'', numbered in the order in
+% which they appear, not the order in which they are written.
+%
+% Aside from shuffling the paragraphs and fixing the handling of
+% footnotes, this package provides little help for the actual
+% typesetting of gamebook entries. For this, please consider using
+% Andr\'e Miede's |gamebook| package, available on
+% CTAN\footnote{\texttt{https://www.ctan.org/pkg/gamebook}}. That
+% package is orthogonal to this one; both may be used together.
+%
+% \section*{Terminology}
+%
+% For the purposes of this document, the term \textit{entry} means a
+% numbered section of text. This term helps describe the
+% common format of a gamebook, while avoiding confusion with the terms
+% \textit{paragraph} and a \textit{section}, both of which
+% already have a clear definition.
+%
+% The term \textit{gamebook} means a book consisting of numbered
+% sections, typically presented in a non-linear order with a
+% tree or graph of possible reading options.
+%
+% \section*{Usage}
+%
+% To load the class, use |\usepackage[|\textit{options}|]{gamebook}|
+%
+% The class options are described below; |[footnotes]| is normally a
+% good choice, although there are some limitations.
+%
+% The user simply writes entries like this inside the document:
+% \begin{verbatim}
+% \begin{gentry}{codea}
+% This is the first entry
+%
+% Turn to \turnto{codeb}
+% \end{gentry}
+%
+% \begin{gentry}[123]{codeb}[title]
+% This is the second and final entry.\par
+% To play again, turn to \turnto{codea}
+% \end{gentry}
+%
+% % Output:
+% \thegentries
+% \end{verbatim}
+%
+% Here, two entries are defined, and then output.
+%
+% The first entry is given a label of |gentry:codea|, and the
+% \cs{turnto\{codea\}} in the second entry generates a link back to
+% that label.
+%
+% As |entry| is a common term likely to conflict with other
+% environments, the environment to declare an entry has been named
+% |gentry| (gamebook entry) instead.
+%
+% Sometimes it is convenient, when writing an entry, to give it a fixed
+% index in the text. The first optional argument in the second entry
+% --- |[123]| --- fixes the entry at that position during
+% shuffling. This is implemented by iterating over each entry and
+% swapping it with that index. Duplicates are not currently checked
+% for, but they would not be lost; if two entries are defined with the
+% same fixed index, one will end up somewhere else in the text.
+%
+% The first and last entries are automatically fixed without
+% needing to specify the optional number.
+%
+% Specifying the optional number as a value greater than or equal to
+% the number of entries, or less than~2, is not recommended. (Yes,
+% this example used |123|, which is beyond the number of entries. This
+% was done to show the syntax).
+%
+% The second optional argument is a title to be displayed alongside
+% the numerical value.
+%
+% Finally, the command \cs{thegentries} will output all entries defined so
+% far, handling shuffling and footnotes.
+%
+% \DescribeMacro{\gentryheader}\marg{counterIdx}\marg{fixedIdx}\marg{code}\marg{title}
+%
+% Users may also want to redefine \cs{gentryheader} to change how the
+% entries are displayed. The initial version is quite basic and
+% intended for debugging; users should use \cs{renewcommand} to change
+% it to something more pleasant.
+%
+% Here's one suggestion, using packages from CTAN. It works well if you have either a
+% title, or at least 2 lines of text before the first paragraph break
+% inside the |gentry|.
+%
+%
+% It also requires near the start of the document:
+% \begin{verbatim}
+% \usepackage{lettrine}
+% \usepackage{etoolbox}
+% \usepackage{color}
+% \end{verbatim}
+% And this anywhere before \cs{thegentries}:
+% \begin{verbatim}
+% \renewcommand{\LettrineFontHook}{%
+% \color[gray]{0.5}\fontfamily{ppl}\fontseries{bx}}
+% \renewcommand{\gentryheader}[4]{
+% \lettrine[lines=3,lhang=0.2,loversize=0.2]{\raisebox{0.1em}{#1}}%
+% {\textbf{\Large\textbf{\raisebox{0.3em}{~#4}
+% }}}%
+% \ifstrempty{#1}{}{\linebreak\mbox{}~}}
+% \end{verbatim}
+% On the last line, \cs{mbox} stops the \cs{parindent} space being
+% ignored; the $\sim$ brings it back up to the expected spacing.
+%
+% \section*{Package options}
+%
+% These options can be specified as a comma-separated list to the
+% \cs{usepackage} line.
+%
+% \begin{macro}{footnote}
+% \changes{v1.0}{2021/08/10}{Footnote option}
+% The |footnote| option causes \LaTeX\ to output footnotes at the end
+% of each entry, or the end of each page, whichever comes first after
+% the footnote mark.
+%
+% There are some limitations, described below.
+%
+% Support for other packages that affect footnotes is limited. If
+% using |hyperref|, it is recommended to pass |[hyperfootnotes=false]|
+% to avoid broken links.
+% \end{macro}
+%
+% \begin{macro}{noshuffle}
+% \changes{v1.0}{2021/08/10}{Noshuffle option}
+% In general, it's easier to write gamebooks in a more linear fashion,
+% in which related entries are kept together. But this is much less
+% fun to play, as it's too easy for the reader to simply read the
+% adjacent eentries to decide what to do.
+% For this reason, this package shuffles the output entries by
+% default. The first and last entries are never shuffled.
+%
+% Sometimes, perhaps for proofreading, you may not want the entries
+% to be shuffled. In this case, you can use the |noshuffle| option.
+% \end{macro}
+%
+% \begin{macro}{verbose}
+% \changes{v1.0}{2021/08/10}{Verbose option}
+% This macro causes the package to output information messages about
+% what it's doing to the log file. This is not generally too useful, but it does
+% include a mapping of the original paragraph indexes to their sorted
+% positons, which may be useful to keep for handling proofreading
+% corrections.
+% \end{macro}
+%
+% \begin{macro}{endpage}
+% \changes{v1.0}{2021/08/10}{Endpage option}
+% Puts the last entry on a page on its own. This typically produces a
+% better ``winning'' feel for reaching the last entry, but it can also
+% produce documents with ugly spacing, so it's recommended to try it
+% each way and see which works better for your text.
+% \end{macro}
+%
+%
+% \section*{Footnotes}
+%
+% When typesetting a gamebook with footnotes, it is confusing if they
+% migrate to the bottom of each page, as the footnote becomes visually
+% detached from the entry to which it relates. Some effort has been taken to
+% ensure that footnotes can be typeset at the bottom of the page on which
+% the mark appears, or the bottom of each entry, whichever comes
+% first.
+%
+% However, this implementation has some limitations:
+%
+% \begin{itemize}
+% \item Footnotes are not expanded until they are typeset.
+% \item As a consequence, attaching one footnote to another with the
+% use of \cs{footnotemark} within a \cs{footnote} argument will not
+% advance the counter in time, so \cs{footnotetext} may not behave as
+% you expect unless it is also set inside the first footnote's text.
+% \item Footnotes at the end of the page will not be broken across
+% pages. Putting sufficient text into footnotes will cause the page
+% to overflow.
+% \item Where the footnote \textbf{mark} appears at the very end of a page,
+% the footnote \textbf{text} may be set at the top of the subsequent
+% page. \TeX\ is asked not to break the page there, but this influence
+% is limited. It may be possible for the author to avoid this, eg by
+% adding a rubber length to the interline spacing (it may be easier to
+% simply choose a different seed value for the |lcg| package to
+% reshuffle).
+% \item If you have a lot of rubber space in the text, or
+% variably-sized items, \LaTeX\ may expand the footnote at the end of
+% the entry before it works out where to put the page break. In this
+% case, the footnote will appear on the wrong page. The macro
+% \cs{noentryfoot} is provided to allow the author to fix this case.
+% \item Support for other footnotes packages may be limited and the
+% behaviour of packages like |footnote|, |endnotes|, |footmisx|,
+% |fnote|, |dblfnote| \textit{etc} may be affected.
+% \item If using the |hyperref| package, it is recommended to pass the
+% option |hyperfootnotes=false| to that package, as the footnote links
+% will be incorrect.
+% \item The package uses \TeX\ \cs{mark}s to indicate which footnotes
+% should appear on each page. Because \TeX\ supports only one set of
+% marks, this would break any other package or usage of \cs{mark}
+% while a gamebook was being output.
+% \item Because \cs{mark} does not escape a floating environment, such
+% as |minipage|, it is likely that this footnote implementation will
+% not work as expected if the gamebook or \cs{footnote} is set in a |minipage| or
+% similar.
+% \item Each footnote is evaluated in a group. Just conceivably, this
+% might affect the behaviour of some macros that affect the document
+% beyond the footnote.
+% \item We rely on some non-``public'' macros, such as \cs{@mpfn} and
+% \cs{@footnotetext} defined by \LaTeX\ standard document
+% classes. Other document classes may override these, which would
+% override this package's footnotes too.
+% \end{itemize}
+%
+% For this reason, the improved footnote handling is only enabled if
+% you pass the |footnote| option, and only while the environment is
+% active.
+%
+% \section*{Implementation}
+%\StopEventually{\PrintChanges \pagebreak[4] \PrintIndex}
+%
+% \begin{macrocode}
+\ProvidesPackage{gamebooklib}[2021/08/10 Gamebook by R Lee latex@rjlee.homelinux.org]
+% \end{macrocode}
+% We need \LaTeXe, for the extra token registers.
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}[1994/06/01]
+% \end{macrocode}
+% \begin{macro}{verbose}
+% The package option |verbose| enables detailed logging.
+% Logging is via the macro \cs{gamebook@info}, which throws away detail messages
+% unless the |verbose| option is given.
+% \begin{macrocode}
+\newcommand{\gamebook@info}[1]{}%
+\DeclareOption{verbose}{%
+ \renewcommand{\gamebook@info}[1]{\PackageInfo{gamebooklib}{#1}}%
+ \gamebook@info{Gamebook Library package is logging}}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{endpage}
+% The |endpage| option puts the last entry on its own page. This can
+% work better when the last entryraph is about a page long, and also
+% the final ``winning'' entry of the gamebook.
+% \begin{macrocode}
+\newcommand\gamebook@beforelast{}
+\DeclareOption{endpage}{%
+ \renewcommand\gamebook@beforelast{\eject}%
+}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{footnote}
+% The |footnote| option enables our footnote processing, to throw out
+% footnotes at the end of each |gentry| so that they don't appear to be
+% against subsequent entries for that page.
+%
+% This is genearlly recommended, unless you have a reason to turn it
+% off (such as a conflicting package). It's disabled by default
+% because it could cause unexpected errors.
+% \begin{macrocode}
+\def\if@gamebook@footnotes{\iffalse}
+\DeclareOption{footnote}{%
+ \gdef\if@gamebook@footnotes{\iftrue}%
+ \gamebook@info{Gamebook Library footnotes per gamebook entry}%
+}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{noshuffle}
+% \begin{macrocode}
+\def\if@gamebook@shuffle{\iftrue}
+\DeclareOption{noshuffle}{%
+ \gdef\if@gamebook@shuffle{\iffalse}%
+ \gamebook@info{Gamebook Library entries output in order}%
+}%
+% \end{macrocode}
+% \end{macro}
+%
+% All unknown options are passed to |lcg|, as it's our only dependency with options.
+% It's suggested that users specify a value for ``seed'' for stable
+% builds, by adding the following before including this package:
+%
+% |\usepackage[seed=123]{lcg}|
+% \begin{macrocode}
+\DeclareOption*{%
+ \typeout{Current option: \CurrentOption}%
+ \PassOptionsToClass{\CurrentOption}{lcg}%
+}%
+\ProcessOptions\relax%
+% \end{macrocode}
+% We need to capture environment contents
+% \begin{macrocode}
+\RequirePackage{environ}%
+% \end{macrocode}
+% |Macroswap|: used to swap the commands that evaluate the macros
+% \begin{macrocode}
+\RequirePackage{macroswap}%
+% \end{macrocode}
+% |Ifthen| makes branching and loops a little easier
+% \begin{macrocode}
+\RequirePackage{ifthen}
+% \end{macrocode}
+% |LCG|: random numbers for the shuffle
+% \begin{macrocode}
+\RequirePackage{lcg}%
+% \end{macrocode}
+% |Silence| is used to suppress a warning from~|lcg| that gamebook is
+% \textbf{not} wasting counter registers. |debrief| ensures that the
+% user is at least told than warnings were suppressed.
+%
+% To see the warnings, put the following line before
+% |\usepackage{gamebook}|:
+%
+% |\usepackage[debrief,showwarnings]{silence}|:
+% \begin{macrocode}
+\RequirePackage[debrief]{silence}%
+% \end{macrocode}
+%
+% Let's count the entries we're reading in so we can build up token
+% registers.
+% \begin{macrocode}
+\newcounter{gentryctr}%
+\setcounter{gentryctr}{0}%
+% \end{macrocode}
+%
+% \begin{environment}{gentry}\oarg{fixedIdx}\marg{code}\oarg{title}
+% First, we need to parse the optional arguments.
+%
+% When we say \cs{begin}\{gentry\}, \LaTeX\ does some stuff ending in \cs{gentry}
+% so we redefine \cs{gentry} to take an optional argument and delegate to \cs{@gentry}
+% \begin{macrocode}
+\newcommand{\gentry}[1][]{\@gentry{#1}}%
+% \end{macrocode}
+% \cs{gentry} just makes the first argument mandatory.
+%
+% \cs{@gentry} defines \cs{gentryidx} and \cs{gentrycode}, which can be used in
+% the body of the \cs{gentry} environment to supply the unsorted index
+% number and the current entry's unique code.
+%
+% NB: If you define two entries with the same code, \LaTeX\ will print
+% out a "multiply defined" label warning.
+% \begin{macrocode}
+\newenvironment{@gentry}[2]{%
+ \def\gentryidx{#1}%
+ \def\gentrycode{#2}%
+ \@@gentry%
+}{\ignorespacesandallpars%
+}%
+% \end{macrocode}
+% \cs{@@gentry} then reads in the optional title argument, storing it in the \cs{gentrytitle}
+% macro to supply the unsorted index number and the current entry's code respectively.
+% \begin{macrocode}
+\newcommand{\@@gentry}[1][]{%
+ \def\gentrytitle{#1}%
+ \stepcounter{gentryctr}%
+% \end{macrocode}
+% For fixed entries, define a macro to hold the requested index
+% \begin{macrocode}
+ \ifthenelse{\equal{\gentryidx}{}}{}{%
+ \expandafter\xdef\csname fixedat\arabic{gentryctr}%
+ \endcsname{\gentryidx}%
+ }%
+ \expandafter\global\expandafter\newtoks\expandafter{%
+ \csname paratok\arabic{gentryctr}\endcsname}{ }%
+ \Collect@Body\gentry@store%
+% \end{macrocode}
+% This was supposed to discard any blank lines at the end of the
+% |gentry| environment, but it still left odd spacing in the
+% output somehow, and sometimes produced weird error messages about
+% |\inaccessible| and |\head|. Removed for now.
+% \begin{macrocode}
+% \ignorespacesandallpars%
+}
+% \end{macrocode}
+% Store the collected environment contents for \cs{thegentries} to output:
+% This uses the token register \cs{gentry$N$}, where $N$ is the
+% unsorted index of this entry.
+% Later, we'll change the values of the $N$ bit of \cs{gentry$N$}
+% macros when we shuffle (the underlying token registers stay the same).
+%
+% This relies on \cs{refstepcounter}\marg{gentryctr} before expanded
+% before this macro. The label |gentry:\gentrycode| is thus set to the
+% current index of the final output entry.
+% \begin{macrocode}
+\newcommand{\gentry@store}[1]{%
+ \edef\head{\noexpand\begingroup\noexpand\gentryheader%
+ {\arabic{gentryctr}}{\gentryidx}{\gentrycode}{\gentrytitle}%
+ \noexpand\label{gentry:\gentrycode}%
+ }%
+ \global\expandafter\csname paratok\arabic{gentryctr}\endcsname=%
+% \end{macrocode}
+% Output the header, the environment token list, flush any footnotes (if applicable) then the inter-gentry footer.
+% \begin{macrocode}
+ \expandafter{\head #1%
+ \outputfootnotes@endgentry%
+ \gentryfooter\endgroup}%
+}%
+% \end{macrocode}
+% \end{environment}
+%
+% \DescribeMacro{\gentry@footnotespergentry}
+% This macro is executed inside the |gentry| group and sets up the
+% commands to be run to allow footnotes. It is only expanded if
+% \cs{if@gamebook@footnotes} is true, \textit{ie} the |footnotes|
+% option is given.
+% \begin{macrocode}
+\newcommand{\gentry@footnotespergentry}{}
+% \end{macrocode}
+%
+% \DescribeMacro{\thegentries}
+%
+% This macro shuffles the entries as required, then expands to them in
+% the correct order.
+% \begin{macrocode}
+\newcommand{\thegentries}{%
+% \end{macrocode}
+% This command is in a group so that the output routine resets.
+%
+% The expansion of \cs{gentry@footnotespergentry} only happens if the
+% |footnote| option was given; it sets up the output routine while the
+% gamebook is running.
+% \begin{macrocode}
+\begingroup%
+ \if@gamebook@footnotes\gentry@footnotespergentry\fi%
+% \end{macrocode}
+% To begin, let's record the number of entries. This may come in
+% useful. Note that you can use this macro in the |gentry| environment,
+% because that's not been expanded yet.
+% \begin{macrocode}
+ \xdef\gentrycount{\arabic{gentryctr}}%
+% \end{macrocode}
+%
+% The next thing is to perform some surgery on LCG.
+% This cuts out an \textbf{annoying} warning, hopefully more reliably
+% than replacing the definition of \cs{p@stkeysr@nd}.
+% The warning is simply that this package doesn't waste another
+% counter every time it changes the random limits (which happens a lot
+% during Knuth shuffle):
+% \begin{macrocode}
+ \WarningFilter{lcg}{Using an already existing counter rand}%
+% \end{macrocode}
+%
+% \subsection*{The output routine and end-of-page footnotes}
+% The idea is to keep footnotes always on the same page as their mark where possible.
+%
+% \LaTeX\ does lots of fun things with the output routine, which we
+% want to keep. So grab a copy of whatever the code is currently doing:
+%
+% Here I'm using the \cs{edef} trick to expand \cs{the}\cs{output} into a token register, because using a macro
+% causes a weird error about an ``|{|'' after ``\cs{the}''.
+% \begin{macrocode}
+\newtoks\gentry@oldoutput{}%
+\edef\mytmp@{\noexpand\gentry@oldoutput={\the\output}}\mytmp@%
+% \end{macrocode}
+% For the footnotes, if we reach the end of a page without outputting
+% them, we need to flush them.
+%
+% \cs{output} is the output routine. It takes the page built up in
+% \cs{box255}, annotates it with headers, footers etc, then ships it
+% out. For our purposes, we only need to append the footnotes to the
+% bottom of \cs{box255}.
+% \begin{macrocode}
+\if@gamebook@footnotes\output={%
+% \end{macrocode}
+% The \cs{outputpenalty} tells us why the output routine was called; generally, it's invoked whenever
+% a new floatable environment is generated, or when a page is full. Anything less than -1000 means that
+% the page was filled, so we should add any footnotes only in this case.
+% \begin{macrocode}
+ \ifnum\outputpenalty<-\@M\else%
+ \edef\tmp@{footnotetoks\botmark}
+ \expandafter\ifcsname footnotetoks\botmark\endcsname%
+ \global\setbox255=\vbox to \vsize{%
+ \unvbox255\vfill\outputfootnotes@endpage}%
+ \fi%
+ \fi%
+ \the\gentry@oldoutput
+}\fi%
+% \end{macrocode}
+%
+% \subsection*{The shuffling algorithm}
+%
+% \TeX\ has well beyond 255 token registers these days, so don't
+% bother to check that limit.
+%
+% The LCG package provides a suitable pseudo-random number generator.
+% What we want is a repeatable series of numbers.
+%
+%\begin{enumerate}
+% \item Work out how many entries there are~($N$). Provided \cs{thegentries} is
+% called at the end, this is just the value of |gentryctr|
+% \item Declare a set of token registers named \cs{paratoks}$n$, where $n$ is
+% each integer 1\dots$N$ inclusive. These will hold the contents of the entry.
+% \item Declare a set of macros named \cs{paraidx}$n$, where $n$ is
+% each integer 1\dots$N$ inclusive, initialised to $n$. These will hold the number of the entry.
+% \item Shuffle elements $\{2:N-1\}$, in that array. For $i=2$ through $N-2$
+% \begin{enumerate}
+% \item Let $R$ be a random number between $i$ and $N-1$ inclusive
+% \item If $R\ne i$ then swap macros \cs{gentrytoks}$R$ and \cs{gentrytoks}$i$
+% \item If $R\ne i$ then swap macros \cs{paraIdx}$R$ and \cs{gentryidx}$i$
+% \end{enumerate}
+% \item For $i=1:n$, output token reg $i$
+%\end{enumerate}
+%
+% Define macros \cs{csname}~|paraIdx|$N'$\cs{endcsname} containing the arabic
+% original page number to be put out on the $N'$th output ``page''
+% \begin{macrocode}
+ \xdef\gentrycount{\arabic{gentryctr}}%
+% \end{macrocode}
+% we can reuse |gentryctr|; we've finished this set of paras and
+% kept the total count.
+% \begin{macrocode}
+ \setcounter{gentryctr}{0}%
+% \end{macrocode}
+% If there are fewer than 3 entries, don't try and shuffle.
+% \begin{macrocode}
+ \ifthenelse{\gentrycount<3}{}{%SHUFFLE START
+ \whiledo{\not{\value{gentryctr}>\gentrycount}}{%
+ \edef\myidx{\arabic{gentryctr}}%
+ \expandafter\xdef\csname paraIdx\myidx\endcsname{\myidx}%
+ \stepcounter{gentryctr}%
+ }%
+% \end{macrocode}
+% Don't renumber para~1 or \cs{gentrycount}; Knuth-shuffle the rest
+% NB: we stop at \cs{gentrycount}$-2$, because \cs{gentrycount}$-1$ would only shuffle
+% with itself.
+% \begin{macrocode}
+ \if@gamebook@shuffle
+ \setcounter{gentryctr}{2}%
+ \setcounter{rand}{\gentrycount}%
+ \addtocounter{rand}{-1}\edef%
+ \stoppoint{\arabic{rand}}%
+ \chgrand[last=\stoppoint]%
+ \whiledo{\value{gentryctr}<\stoppoint}{%
+% \end{macrocode}
+% If this is to be swapped with a fixed position, skip it
+% \begin{macrocode}
+ \edef\myidx{\arabic{gentryctr}}%
+ \expandafter\ifcsname fixedat\myidx\endcsname%
+ \gamebook@info{Not shuffling \myidx; fixed pos}%
+ \stepcounter{gentryctr}%
+ \else%
+ \gamebook@info{Shuffling \myidx}%
+ \stepcounter{gentryctr}%
+ \edef\nextidx{\arabic{gentryctr}}%
+% \end{macrocode}
+% If we've hit an entry with fixed position, we may as well skip it
+% \begin{macrocode}
+ \expandafter\ifcsname fixedto\arabic{rand}\endcsname\else%
+ \chgrand[first=\nextidx]%
+ \rand%
+ \gamebook@info{Shuffling \myidx to \arabic{rand}}%
+ \macroswap{paraIdx\myidx}{paraIdx\arabic{rand}}%
+ \fi%
+ \fi%
+ }%
+% \end{macrocode}
+% Now move fixed entries into their final place:
+% \begin{macrocode}
+ \setcounter{gentryctr}{2}%
+ \whiledo{\value{gentryctr}<\stoppoint}{%
+ \edef\myidx{\arabic{gentryctr}}%
+ \expandafter\ifcsname fixedat\myidx\endcsname%
+ \expandafter\edef\expandafter\mydest\expandafter%
+ {\expandafter\csname fixedat\myidx\endcsname}%
+ \gamebook@info{MOVING FIXED GAMEBOOK ENTRY INTO PLACE: \myidx -> \mydest}%
+ \macroswap{paraIdx\myidx}%
+ {paraIdx\expandafter\csname fixedat\myidx\endcsname}%
+ \fi%
+ \stepcounter{gentryctr}%
+ }}\fi%SHUFFLE END
+ \gamebook@info{Shuffled! Gentry order:}%
+ \setcounter{gentryctr}{1}%
+ \whiledo{\not{\value{gentryctr}>\gentrycount}}{%
+ \edef\myidx{\arabic{gentryctr}}%
+ \gamebook@info{\myidx -> \csname paraIdx\myidx\endcsname}%
+ \stepcounter{gentryctr}%
+ }%
+% \end{macrocode}
+%
+% We can reuse the same counter again to output
+% \begin{macrocode}
+ \setcounter{gentryctr}{0}%
+ \gamebook@info{Outputting \gentrycount\ gamebook entries}%
+ \whiledo{\value{gentryctr}<\gentrycount}{%
+% \end{macrocode}
+% Use refstepcounter in the loop to allow \cs{label} to work as expected.
+% \begin{macrocode}
+ \refstepcounter{gentryctr}%
+% \end{macrocode}
+% Keep last entry on its own page
+% \begin{macrocode}
+ \ifthenelse{\value{gentryctr}=\gentrycount}{%
+ \gamebook@beforelast%
+ }{}%
+ \edef\myidx{\arabic{gentryctr}}%
+ \xdef\youridx{\csname paraIdx\myidx\endcsname}%
+ \gamebook@info{Output gentry \myidx\ of \gentrycount,%
+ original idx \youridx}%
+% \end{macrocode}
+% Output the stored entry body, stripping any extraneous space:
+% \begin{macrocode}
+ \the\csname paratok\youridx\endcsname%
+ }%
+% \end{macrocode}
+% Finally, we clear the registers and reset the counter in case we want to start again
+% \begin{macrocode}
+ \gamebook@info{All gamebook entries added to main vertical list}%
+ \setcounter{gentryctr}{1}%
+ \whiledo{\not{\value{gentryctr}>\gentrycount}}{%
+ \edef\myidx{\arabic{gentryctr}}%
+ \expandafter\global\expandafter\let%
+ \csname paratok\myidx\endcsname\@undefined%
+ \expandafter\ifcsname fixedat\myidx\endcsname%
+ \expandafter\global\expandafter\let%
+ \csname fixedat\myidx\endcsname\@undefined%
+ \fi%
+ \stepcounter{gentryctr}%
+ }%
+ \setcounter{gentryctr}{0}%
+ \eject
+ \endgroup%
+}%
+% \end{macrocode}
+% The final \cs{eject} ensures that the output routine has flushed as
+% many pages as it can, before the output routine is reset again.
+%
+% \DescribeMacro{\gentryheader}\marg{counterIdx}\marg{fixedIdx}\marg{code}\marg{title}
+%
+% This macro is called before outputting the header. Its
+% job is to format whatever header information the user wants to see
+% on each entry; generally, this will be the page number.
+%
+% It takes 4 parameters:
+%\begin{enumerate}
+%\item The \textit{unshuffled} index value (to help an author find an
+% entry in the original text)
+%\item The \textit{fixed} index value, if any; otherwise an empty argument
+%\item The user-entered unique code for this entry
+%\item The user-supplied title, if any; otherwise an empty argument
+%\end{enumerate}
+%
+% The value of the output index can be obtained with |\arabic{gentryctr}|
+% \begin{macrocode}
+\newcommand{\gentryheader}[4]{%
+ \noindent\textbf{\Huge\arabic{gentryctr}\large\ #4}%
+ \nopagebreak%
+ \vspace{0.3em}%
+ \nopagebreak%
+ \par%
+ \marginpar{#3}%
+}%
+% \end{macrocode}
+%
+% \DescribeMacro{\gentryfooter}
+% This takes no arguments and is simply expanded after the entry is typeset. The default adds some vertical
+% space and a simple separator.
+%
+% \begin{macrocode}
+\newcommand{\gentryfooter}{%
+ \par\vspace{2em}\centerline{---}\vspace{2em plus 1in}\par%
+}%
+% \end{macrocode}
+%
+% \DescribeMacro{\ignorespacesandallpars@}
+% This is a technique described on StackExchange:
+%
+% {\small https://tex.stackexchange.com/questions/179016/\\ignore-spaces-and-pars-after-an-environment\#179034}
+%
+% This is used to ensure that extra space at the start and end of the |gentry|
+% environment is ignored.
+%
+% \begin{macrocode}
+\def\ignorespacesandallpars@{%
+ \@ifnextchar\par%
+ {\expandafter\ignorespacesandallpars\@gobble}%
+ {}%
+}%
+% \end{macrocode}
+%
+% \DescribeMacro{\@footnotetext}\marg{token register}
+% Token registers to hold each footnote.
+%
+% Each footnote is held in its own token register, so that we can control
+% which footnotes appear on each page.
+%
+% \LaTeX\ would normally use saveboxes to store footnotes, but I
+% prefer to hold off on expanding them until we know which page
+% they're to be expanded on, which saves some difficulties (and
+% perhaps creates others).
+%
+% To start with, modify \LaTeX's \cs{@makefnmark} to output a mark for
+% the footnote, holding its index. This tells the output routine which
+% footnotes to include at the end of the page. The
+% \cs{in@out} macro is only defined when outputting footnotes, so
+% suppresses this mark when we don't need it.
+% \begin{macrocode}
+\g@addto@macro{\@makefnmark}{%
+ \ifcsname in@out\endcsname\else%
+ \mark{\arabic{\@mpfn}}%
+ \fi%
+}%
+% \end{macrocode}
+%
+% The \cs{footnotetext@save} is a convenience that takes the the
+% footnote counter value in the first argument, the token register as
+% a second argument, and the token list (footnote text) as the third.
+% \begin{macrocode}
+\g@addto@macro{\gentry@footnotespergentry}{%
+\newcommand{\@footnotetext@save}[3]{%
+ \global\newtoks#2{}%
+ \global#2={\noindent\@footnotemark{}#3}%
+}}%
+% \end{macrocode}
+% \cs{@footnotetext@save} unpacks the arguments for
+% \cs{@footnotetext@save@}. This one uses the value of the \cs{@mpfn}
+% counter to unpack the footnote counter, the token register (full csname) as
+% the first argument, and the token list (footnote text) as the second.
+% \begin{macrocode}
+\g@addto@macro{\gentry@footnotespergentry}{%
+\newcommand{\@footnotetext@save@}[2]{%
+ \edef\@tmp@{\expandafter\arabic{\@mpfn}}%
+ \expandafter\@footnotetext@save\expandafter{\@tmp@}{#1}{#2}%
+}}%
+% \end{macrocode}
+% Footnotes are built in a group, so that \cs{in@out} can be defined
+% locally to indicate that footnotes are being built (which stops
+% spurious \cs{mark}s).
+% \begin{macrocode}
+\g@addto@macro{\gentry@footnotespergentry}{%
+\renewcommand{\@footnotetext}[1]{%
+ \begingroup%
+ \def\in@out{}% flag that we're building footnotes
+ \edef\@tmp{\expandafter\csname footnotetoks\arabic{\@mpfn}\endcsname}%
+ \expandafter\@footnotetext@save@\expandafter{\@tmp}{%
+ % This fixes up the use of \cs{footnotemark} within footnotes:
+ #1}%
+ \endgroup%
+}}%
+% \end{macrocode}
+%
+% \DescribeMacro{\outputfootnotes}\marg{maxIdx}
+%
+% Command to output the footnotes, which are just in \cs{footnotetoks$N$}
+% for now.
+%
+% An end user can call this at any point in the text to set out the footnotes.
+%
+% This macro takes one argument, being the maximum index of footnotes to output, inclusive.
+% Footnotes after this index will be excluded. If not provided, the
+% value provided by the counter \cs{@mfpn}, which in the default
+% \LaTeX\ counter, will be used.
+% \begin{macrocode}
+\newcounter{fncounter}%
+\newcommand{\outputfootnotes}[1]{%
+ \begingroup%
+ \def\in@out{}% flag that footnotes are outputting; suppresses marks
+ \setcounter{fncounter}{1}
+% \end{macrocode}
+% Called in vertical mode, and don't want to throw a page break.
+%
+% I'm not sure how \LaTeX\ renders the footnote rule exactly, so I'm just using my own.
+% \begin{macrocode}
+ \def\footnote@rule{%
+% \end{macrocode}
+% The next line comess from the TUGboat suggestions, and protect against various user changes
+% \begin{macrocode}
+ \leftskip=0pt\rightskip=0pt\interlinepenalty=1000%
+ \penalty-1000%
+ \vspace{1pt plus 2pt minus 0.5pt}%
+ \hspace{-0.5in}\rule{1.5in}{0.4pt}\\%
+ }%
+% \end{macrocode}
+% Invoke the output routine. This attempts to stop the output routine
+% being invoked while we're adding the footnote rule, which could
+% cause a blank footnote to appear.
+%
+% Instead, it means some footnotes could appear on the subsequent
+% page. To guard against this, footnotes are set into a \cs{vbox}
+% to prevent page breaking.
+%
+% The macro \cs{footnote@rule} is output before each footnote. The
+% first time, it outputs a divider rule; subsequently, it just throws
+% a new paragraph to keep footnotes on separate lines.
+%
+% The next line comess from the TUGboat suggestions, and protect against various user changes
+% \begin{macrocode}
+ \outputpenalty=-\@MM\break%
+ \vbox{%
+ \whiledo{\not{\value{fncounter}>#1}}{%
+% \end{macrocode}
+% We are now looping over all possible entry numbers, in
+% order. Some will already have been output, but we check them all
+% anyway (it doesn't take much time).
+%
+% First, we check if the macro exists. If it does, it must contain the
+% value of the token register.
+%
+% Next, we make sure that the token register has contents.
+%
+% \begin{macrocode}
+ \expandafter\ifcsname footnotetoks\arabic{fncounter}\endcsname%
+ \edef\tmp@@{\csname footnotetoks\arabic{fncounter}\endcsname}%
+% \end{macrocode}
+% This \cs{detokenize} black magic tests if a token reg is actually
+% empty:
+%
+% https://tex.stackexchange.com/questions/263733/\\whats-the-best-practice-way-to-test-whether-parameter-is-empty
+% \begin{macrocode}
+ \expandafter\if\expandafter\relax\expandafter%
+ \detokenize\expandafter{\the\tmp@@}\relax\else%
+ \footnote@rule\gdef\footnote@rule{\ifvmode\else\par\fi}%
+ \interlinepenalty\interfootnotelinepenalty%
+% \end{macrocode}
+% Actually output the footnotes.
+%
+% Having output the footnote, clear the token register (to save
+% memory), then use \cs{let} to clear the definition of the
+% macro. This ensures that we don't try to output the same footnote
+% twice (at page end and entry end).
+% \begin{macrocode}
+ \expandafter\the\tmp@@%
+ \global\expandafter\tmp@@={}%
+ \expandafter\let\tmp@@\@undefined%
+ \fi\fi%
+ \stepcounter{fncounter}%
+ }%
+ }%
+ \endgroup%
+}%
+% \end{macrocode}
+% \LaTeX\ works by building up a little more than a page, then calling the output routine.
+% The output routine then decides where to put the page end from the built-up material.
+% If there is a footnote mark, it could come after the page end, so we can't rely on the
+% fact that there's footnote register to determine if we should output footnotes or not.
+% The edge case is: if the footnote mark is held back for the next page, the footnote text
+% would appear on the footer of the page where being built when the mark was expanded, which
+% is the page before the footnote.
+%
+% One fix for this is to have each footnote mark in the main body of
+% the text output a \cs{mark} containing the footnote's counter value,
+% and output the footnotes only to \cs{botmark}, which is the last
+% \cs{mark} actually typeset on the page.
+%
+% (see https://www.tug.org/TUGboat/Articles/tb11-4/tb30salomon.pdf,
+% page 598, to read around footnotes).
+%
+% \DescribeMacro{\outputfootnotes@endgentry}
+% This macro is called at the end of each |gentry|. It switches into
+% vertical mode (as ending |gentry| doesn't throw a \cs{break} or line
+% end by itself), then we output all footnotes so far (by reading the
+% footnote counter \cs{@mpfn}, as this is ``sequential'').
+% \begin{macrocode}
+\newcommand{\outputfootnotes@endgentry}{%
+ \if@gamebook@footnotes%
+ \nopagebreak\ifhmode\\\fi% get into vertical mode
+ \nopagebreak\outputfootnotes{\arabic{\@mpfn}}%
+ \fi%
+}%
+% \end{macrocode}
+% \DescribeMacro{\noentryfoot}
+% This method simply suppresses footnotes at the end of the entry
+% within the current group. This forces footnotes within the current
+% group to be printed at the bottom of the page.
+%
+% This is useful in the case where \LaTeX\ expands the footnote at the
+% end of the entry, then decides to put the page split between the
+% footnote mark and the text.
+% \begin{macrocode}
+\newcommand{\noentryfoot}{\def\outputfootnotes@endgentry{}}
+% \end{macrocode}
+% \DescribeMacro{\outputfootnotes@endpage}
+% This is called by the output routine at the end of each page. If
+% \cs{botmark} has a value, then we can output all footnotes up to
+% that index.
+% \begin{macrocode}
+\g@addto@macro{\gentry@footnotespergentry}{
+\newcommand{\outputfootnotes@endpage}{%
+ \expandafter\if\expandafter\relax\expandafter%
+ \detokenize\expandafter{\botmark}\relax\else%
+ \outputfootnotes{\botmark}%
+ \fi%
+}}%
+% \end{macrocode}
+% \Finale
+\endinput
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib.ins b/macros/latex/contrib/gamebooklib/gamebooklib.ins
new file mode 100644
index 0000000000..843a747bbd
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/gamebooklib.ins
@@ -0,0 +1,53 @@
+%%
+%% Copyright (C) 2021 by Robert J Lee
+%%
+%% This file 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 2005/12/01 or later.
+%
+\input docstrip.tex
+\keepsilent
+\usedir{tex/latex/gamebooklib}
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2021 by Robert J Lee
+
+This file 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 2005/12/01 or later.
+
+\endpreamble
+
+\generate{\file{gamebooklib.sty}{\from{gamebooklib.dtx}{package}}}
+
+\obeyspaces
+
+\Msg{****************************************************}
+\Msg{* *}
+\Msg{* To finish the installation you have to move the *}
+\Msg{* following file into a directory searched by TeX: *}
+\Msg{* *}
+\Msg{* gamebooklib.sty *}
+\Msg{* *}
+\Msg{* To produce the documentation run the file *}
+\Msg{* gamebooklib.dtx through LaTeX. *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{****************************************************}
+
+\endbatchfile
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib.pdf b/macros/latex/contrib/gamebooklib/gamebooklib.pdf
new file mode 100644
index 0000000000..991b237de3
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/gamebooklib.pdf
Binary files differ
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib_countpagesperseed.sh b/macros/latex/contrib/gamebooklib/gamebooklib_countpagesperseed.sh
new file mode 100755
index 0000000000..926e7d152e
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/gamebooklib_countpagesperseed.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# Copyright (C) 2021 by Robert J Lee
+#
+# This file 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 2005/12/01 or later.
+#
+# A utility script to find the best seed number for a particular gamebook
+#
+# Prerequisites: bash, tee, tail, egrep, pdflatex, perl with Sort::Naturally
+#
+# To install Sort::Naturally, you can simply type "cpan install Sort::Naturally"
+# assuming Perl is installed.
+#
+# First keep a backup of your .tex file, just in case.
+#
+# Next, ensure that you have a line containing "seed=<numerals>,"
+# (including the comma) in your .tex file.
+#
+# The first occurence will be replaced with a sequence of numbers in turn,
+# the PDF regenerated, and the number of output pages with each number reported
+# on, first by seed number, then by reversed number of pages (smallest last).
+# It's then up to you to choose the seed number appropriate for your work.
+#
+# Use this script with caution as it will edit your source file.
+#
+# The script may be placed on the system path or copied to the working directory.
+
+file=${1}
+
+if [[ -z $file ]]; then
+ echo "Usage: $0 <file>.tex"
+ exit 1
+fi
+
+egrep -q "seed=[0-9]+," $file || (
+ echo "$1 Does not contain \\usepackage[seed=123,quiet]{lcg}"
+ exit 2
+);
+
+pdf="pdflatex -interaction=nonstopmode $file"
+
+cp $file $file~ || exit 3
+
+# FOR seed in (1..1000)
+for seed in $(perl -e 'for (1..1000){print "$_\n"}'); do
+ # edit $file and replace any seed values
+ perl -i -pe "s/seed=[0-9]*,/seed=$seed,/" $file
+ # Run it through LaTeX, stripping out the line of output containing the number of pages, and then
+ # add the seed value
+ echo $($pdf 2>&1 | grep 'pages' | tail -n 1 | perl -pe "chomp") "; seed=$seed";
+done | \
+ # report on the output as we get it, and report on the sorted pages at the end.
+ # (sort numerically by first numeral on lines with identical prefix)
+ perl -MSort::Naturally -pe \
+ '{push @lines, $_}; END{print "SORTED:"; print reverse nsort(@lines)}'
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf b/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf
new file mode 100644
index 0000000000..ceac9a9eb7
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf
Binary files differ
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib_test.tex b/macros/latex/contrib/gamebooklib/gamebooklib_test.tex
new file mode 100644
index 0000000000..4d661dce63
--- /dev/null
+++ b/macros/latex/contrib/gamebooklib/gamebooklib_test.tex
@@ -0,0 +1,109 @@
+%%
+%% This is file `gamebooklib_test.tex',
+%%
+%% Copyright (C) 2021 by Robert J Lee
+%%
+%% This file 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 2005/12/01 or later.
+%%
+\documentclass{report}
+\usepackage[seed=123]{lcg}
+\usepackage[verbose,footnote]{gamebooklib}
+\usepackage{lipsum}
+\begin{document}
+
+\newcommand{\turnto}[1]{\ref{gentry:#1}\par}
+
+\section*{Example of Use}
+
+This document was used for testing during development of gamebooklib.
+Please see the \texttt{gamebooklib\_test.tex} file alongside the PDF
+to see how the package behaves.
+
+
+\begin{gentry}{codea}
+ This is the first gentry!
+
+ It actually contains two gentryraphs.
+
+Turn to \turnto{codeb}
+\end{gentry}
+
+\begin{gentry}{codea}
+ This one is a duplicate! This creates a `'multiple defined'' labels Warning!
+\end{gentry}
+
+\begin{gentry}{codeb}
+ This is the second gentry.
+
+ Turn to \turnto{codec}
+
+Turn to \turnto{coded}
+\end{gentry}
+
+\begin{gentry}{codec}[You lose!]
+ This is the third gentry.
+
+ You can't escape from here.
+\end{gentry}
+
+\begin{gentry}[123]{coded}[You win!]
+ This is the second and final gentryraph.
+
+ To play again, turn to \turnto{codea}
+
+ (Note that this is the wrong number due to the duplicate label)
+\end{gentry}
+
+\section*{Here is the result:}
+
+\thegentries
+\eject
+
+For my next trick, here are some longer and multi-page examples.
+
+Note the location of the footnotes in these entries.
+
+\begin{gentry}{restart}\noentryfoot
+ This is the first gentryraph again.
+ \lipsum[1]\footnote{First footnote, forced to page end}
+\end{gentry}
+
+\begin{gentry}{restart2}
+ \lipsum[2-7]\footnote{This is just Lorum Ipsum\footnote{Nonsense
+ pseudo-latin, with roughly English letter distribution, commonly
+ used to compare fonts\footnotemark.\footnotetext{Here, it's just nonsense.}}}
+\end{gentry}
+
+\newcounter{foo}
+\newcounter{bar}
+\setcounter{foo}{3}
+\setcounter{bar}{3}
+\newcommand{\gentrytst}[2]{
+ \begin{gentry}{restart#1}
+ \lipsum[#1]\footnote{This was gentry #1}
+ \lipsum[#1-#2]\footnote{This was also gentry #1}
+ \end{gentry}
+}
+\whiledo{\not{\value{foo}>10}}{
+ \stepcounter{foo}
+ \stepcounter{bar}
+ \stepcounter{bar}
+ \edef\idx{\arabic{foo}}
+ \edef\idxx{\arabic{bar}}
+ \expandafter\gentrytst\expandafter{\idx}{\idxx}
+}
+
+\section*{Here is the result:}
+
+\thegentries
+\vfill
+
+\end{document}
diff --git a/macros/latex/contrib/lambdax/lambdax.bib b/macros/latex/contrib/lambdax/lambdax.bib
new file mode 100644
index 0000000000..62b85c380a
--- /dev/null
+++ b/macros/latex/contrib/lambdax/lambdax.bib
@@ -0,0 +1,26 @@
+@misc{erw-ccool,
+ author = {Rogard, Erwann},
+ title = {The \pkg{ccool} package for \LaTeX},
+ note = {\url{https://github.com/rogard/ccool/blob/master/ccool.pdf}},
+ year = {2020}}
+@misc{erw-keyparse,
+ author = {Rogard, Erwann},
+ title = {The \pkg{keyparse} package for \LaTeX},
+ note = {\url{https://github.com/rogard/keyparse/blob/master/keyparse.pdf}},
+ year = {2021}}
+@manual{xparse,
+ title = {The \pkg{xparse} package},
+ author = {The \LaTeX3 Project Team},
+ year = {2019},
+ note = {\url{https://ctan.math.illinois.edu/macros/latex/contrib/l3packages/xparse.pdf}},
+ annote = {} }
+@misc{a-188053,
+ author = {@{}sean-allred},
+ title = {``How to create lambda expressions?''},
+ year = {2014},
+ note = {\url{https://tex.stackexchange.com/a/188053/112708}}}
+@misc{q-610349,
+ author = {@{}Erwann},
+ title = {``Troubleshooting \PrintIndex \PrintChanges''},
+ year = {2021},
+ note = {\url{https://tex.stackexchange.com/questions/610349/troubleshooting-printindex-printchanges}}}
diff --git a/macros/latex/contrib/lambdax/lambdax.dtx b/macros/latex/contrib/lambdax/lambdax.dtx
index 77e6a91115..36661218b8 100644
--- a/macros/latex/contrib/lambdax/lambdax.dtx
+++ b/macros/latex/contrib/lambdax/lambdax.dtx
@@ -69,11 +69,11 @@ lambdax.sty, and lambdax.pdf.
%</internal>
%<package> \NeedsTeXFormat{LaTeX2e}[2021-06-01]
%<package> \RequirePackage{expl3, xparse, xtemplate, l3keys2e}[2021-06-01]
-%<package> \RequirePackage{lex}[2021-08-03]
+%<package> \RequirePackage{keyparse}[2021-08-18]
%<package> \ProvidesExplPackage
%<package> {lambdax} % Package name
-%<package> {2021-08-03} % Release date
-%<package> {1.0} % Release version
+%<package> {2021-08-18} % Release date
+%<package> {1.1} % Release version
%<package> {lambdax --- Lambda expression } % Description
%<*driver>
\documentclass[show-notes]{l3doc}%^^A full
@@ -96,10 +96,10 @@ lambdax.sty, and lambdax.pdf.
title = {The \pkg{ccool} package for \LaTeX},
note = {\url{https://github.com/rogard/ccool/blob/master/ccool.pdf}},
year = {2020}}
-@misc{erw-lex,
+@misc{erw-keyparse,
author = {Rogard, Erwann},
- title = {The \pkg{lex} package for \LaTeX},
- note = {\url{https://github.com/rogard/lex/blob/master/lex.pdf}},
+ title = {The \pkg{keyparse} package for \LaTeX},
+ note = {\url{https://github.com/rogard/keyparse/blob/master/keyparse.pdf}},
year = {2021}}
@manual{xparse,
title = {The \pkg{xparse} package},
@@ -194,7 +194,7 @@ lambdax.sty, and lambdax.pdf.
% \end{syntax}
% \end{function}
% \begin{descr}
-% \item[Limitation] That of \pkg{lex}\cite{erw-lex}'s \texttt{argspec} collection.
+% \item[Limitation] That of \pkg{keyparse}\cite{erw-keyparse}'s \texttt{argspec} collection.
% \item[Argspec] Examples of \meta{bool-arg-type}\cite{xparse} and \meta{bool-arg} are |s| and |*|, respectively.
% \item[Semantics] That of \cs{lambdax:nn} and recurse if applicable.
% \end{descr}
@@ -227,6 +227,9 @@ lambdax.sty, and lambdax.pdf.
% \changes{Version 1.0}
% {2020/08/03}
% {Initial version}
+% \changes{Version 1.1}
+% {2020/08/18}
+% {Dependency lex.sty renamed keyparse.sty}
% \clearpage
% \StopEventually{
% \PrintChanges
@@ -338,7 +341,7 @@ lambdax.sty, and lambdax.pdf.
% \begin{macrocode}
\cs_new:Nn\@@_placeholder:n{#### #1}
\cs_generate_variant:Nn\@@_placeholder:n{o,e}
-\cs_new:Nn\@@_argspec:n{\lex_eval:nn{argspec}{#1}}
+\cs_new:Nn\@@_argspec:n{\keyparse_eval:nn{argspec}{#1}}
\cs_new:Nn\@@_argspec_count:n{\tl_count:e{\@@_argspec:n{#1}}}
\cs_new:Nn\@@_chain_position:n{\int_eval:e{\@@_argspec_count:n{#1}+1}}
\cs_new:Nn\@@_chain_placeholder:n
diff --git a/macros/latex/contrib/lambdax/lambdax.pdf b/macros/latex/contrib/lambdax/lambdax.pdf
new file mode 100644
index 0000000000..05c8c95f0f
--- /dev/null
+++ b/macros/latex/contrib/lambdax/lambdax.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf b/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf
index db10c276d5..dbadeb94d7 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf
+++ b/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc-en.pdf b/macros/latex/contrib/projlib/ProjLib-doc-en.pdf
index 67f16164a8..f41e7621f7 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc-en.pdf
+++ b/macros/latex/contrib/projlib/ProjLib-doc-en.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf b/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf
index 18ae26be58..868b604e6a 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf
+++ b/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc.dtx b/macros/latex/contrib/projlib/ProjLib-doc.dtx
index ac30792c0f..c5d10d507c 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc.dtx
+++ b/macros/latex/contrib/projlib/ProjLib-doc.dtx
@@ -107,7 +107,7 @@
%<*ProjLib-doc-cn>
\title{\ProjLib{} 工具集\\[.3\baselineskip]\normalsize 使用指南}
\author{许锦文}
-\thanks{对应版本.~~\texttt{\ProjLib{}~2021/08/17}}
+\thanks{对应版本.~~\texttt{\ProjLib{}~2021/08/19}}
\email{\href{mailto:ProjLib@outlook.com}{ProjLib@outlook.com}}
\date{2021年8月,北京}
%</ProjLib-doc-cn>
@@ -115,7 +115,7 @@
%<*ProjLib-doc-en>
\title{\ProjLib{}~\,Toolkit\\[.3\baselineskip]\normalsize User Manual}
\author{Jinwen XU}
-\thanks{Corresponding to: \texttt{\ProjLib{}~2021/08/17}}
+\thanks{Corresponding to: \texttt{\ProjLib{}~2021/08/19}}
\email{\href{mailto:ProjLib@outlook.com}{ProjLib@outlook.com}}
\date{August 2021, Beijing}
%</ProjLib-doc-en>
@@ -123,7 +123,7 @@
%<*ProjLib-doc-fr>
\title{La boîte à outils~\,\ProjLib{}\\[.3\baselineskip]\normalsize Manuel d'utilisation}
\author{Jinwen XU}
-\thanks{Correspondant à : \texttt{\ProjLib{}~2021/08/17}}
+\thanks{Correspondant à : \texttt{\ProjLib{}~2021/08/19}}
\email{\href{mailto:ProjLib@outlook.com}{ProjLib@outlook.com}}
\date{Août 2021, à Pékin}
%</ProjLib-doc-fr>
diff --git a/macros/latex/contrib/projlib/ProjLib.dtx b/macros/latex/contrib/projlib/ProjLib.dtx
index 7199d00910..fd3b252e1f 100644
--- a/macros/latex/contrib/projlib/ProjLib.dtx
+++ b/macros/latex/contrib/projlib/ProjLib.dtx
@@ -18,47 +18,47 @@
%
%<*ProjLib>
\ProvidesPackage{ProjLib}
- [2021/08/17 The collective interface of ProjLib toolkit]
+ [2021/08/19 The collective interface of ProjLib toolkit]
%</ProjLib>
%
%<*PJLauthor>
\ProvidesPackage{PJLauthor}
- [2021/08/17 Enhanced author information block]
+ [2021/08/19 Enhanced author information block]
%</PJLauthor>
%
%<*PJLdate>
\ProvidesPackage{PJLdate}
- [2021/08/17 Convert yyyy-mm-dd to normal datetime format]
+ [2021/08/19 Convert yyyy-mm-dd to normal datetime format]
%</PJLdate>
%
%<*PJLdraft>
\ProvidesPackage{PJLdraft}
- [2021/08/17 Some useful macros for the draft stage]
+ [2021/08/19 Some useful macros for the draft stage]
%</PJLdraft>
%
%<*PJLlang>
\ProvidesPackage{PJLlang}
- [2021/08/17 Multi-language configuration]
+ [2021/08/19 Multi-language configuration]
%</PJLlang>
%
%<*PJLlogo>
\ProvidesPackage{PJLlogo}
- [2021/08/17 The ProjLib logo]
+ [2021/08/19 The ProjLib logo]
%</PJLlogo>
%
%<*PJLmath>
\ProvidesPackage{PJLmath}
- [2021/08/17 Useful math macros and shortcuts]
+ [2021/08/19 Useful math macros and shortcuts]
%</PJLmath>
%
%<*PJLpaper>
\ProvidesPackage{PJLpaper}
- [2021/08/17 Paper style configuration]
+ [2021/08/19 Paper style configuration]
%</PJLpaper>
%
%<*PJLthm>
\ProvidesPackage{PJLthm}
- [2021/08/17 Theorem setup and configuration]
+ [2021/08/19 Theorem setup and configuration]
%</PJLthm>
%
%# 下面两行引入宏包的代码是所有文件共用的。
@@ -1415,7 +1415,7 @@
\expandafter\IfEndWith\expandafter{\PJLthm@temp}{*}{%
\expandafter\StrGobbleRight\expandafter{\PJLthm@temp}{1}[\PJLthm@temp]%
}{}%
- \IfSubStr{#3}{=}{% key-value mode
+ \IfSubStr{\detokenize{#3}}{=}{% key-value mode
\IfValueTF{#1}{%
\CreateTheoremSetKeys{\PJLthm@temp}{#1={#3}}%
}{%
@@ -2101,6 +2101,8 @@
\fi
\CreateTheorem*{remark*}
\CreateTheorem*{observation*}
+
+\theoremstyle{definition}
\fi
%# 按照 thmnum 决定公式如何编号