summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-10-12 03:04:15 +0000
committerNorbert Preining <norbert@preining.info>2023-10-12 03:04:15 +0000
commit1598205ade1602e324b7fd8e5410d1389eae7416 (patch)
tree65f81ef88c5a968e7141ffab7b210b7bf051a867
parent366cf31a771ded1f10860be3212058d48020398d (diff)
CTAN sync 202310120304
-rw-r--r--FILES.byname430
-rw-r--r--FILES.byname.gzbin2551761 -> 2552604 bytes
-rw-r--r--FILES.last07days378
-rw-r--r--biblio/ctan-bibdata/ctan.bib79
-rw-r--r--biblio/ctan-bibdata/ctan.pdfbin3713325 -> 3716783 bytes
-rw-r--r--macros/generic/advice/INSTALL.md69
-rw-r--r--macros/generic/advice/LICENCE416
-rw-r--r--macros/generic/advice/Makefile8
-rw-r--r--macros/generic/advice/README.md8
-rw-r--r--macros/generic/advice/advice.edtx1095
-rw-r--r--macros/generic/advice/advice.ins33
-rw-r--r--macros/generic/collargs/INSTALL.md68
-rw-r--r--macros/generic/collargs/LICENCE416
-rw-r--r--macros/generic/collargs/Makefile8
-rw-r--r--macros/generic/collargs/README.md8
-rw-r--r--macros/generic/collargs/collargs.edtx2938
-rw-r--r--macros/generic/collargs/collargs.ins33
-rw-r--r--macros/generic/etoolbox-generic/LICENCE416
-rw-r--r--macros/generic/etoolbox-generic/README.md8
-rw-r--r--macros/generic/etoolbox-generic/etoolbox-generic.tex80
-rw-r--r--macros/generic/memoize/INSTALL.md216
-rw-r--r--macros/generic/memoize/LICENCE416
-rw-r--r--macros/generic/memoize/Makefile139
-rw-r--r--macros/generic/memoize/README.md11
-rw-r--r--macros/generic/memoize/doc/memoize-clean.1.md62
-rw-r--r--macros/generic/memoize/doc/memoize-code.pdfbin0 -> 621070 bytes
-rw-r--r--macros/generic/memoize/doc/memoize-code.sty276
-rw-r--r--macros/generic/memoize/doc/memoize-code.tex120
-rw-r--r--macros/generic/memoize/doc/memoize-doc-common.sty173
-rw-r--r--macros/generic/memoize/doc/memoize-doc.sty711
-rw-r--r--macros/generic/memoize/doc/memoize-extract.1.md94
-rw-r--r--macros/generic/memoize/doc/memoize.mst1
-rw-r--r--macros/generic/memoize/doc/memoize.pdfbin0 -> 2164795 bytes
-rw-r--r--macros/generic/memoize/doc/memoize.tex9094
-rw-r--r--macros/generic/memoize/doc/yadoc.sty491
-rwxr-xr-xmacros/generic/memoize/memoize-clean.pl163
-rwxr-xr-xmacros/generic/memoize/memoize-clean.py159
-rwxr-xr-xmacros/generic/memoize/memoize-extract.pl205
-rwxr-xr-xmacros/generic/memoize/memoize-extract.py183
-rw-r--r--macros/generic/memoize/memoize.edtx3597
-rw-r--r--macros/generic/memoize/memoize.ins39
-rw-r--r--support/easydtx/LICENCE674
-rw-r--r--support/easydtx/README.md10
-rw-r--r--support/easydtx/easydoctex-mode.el149
-rw-r--r--support/easydtx/edtx2dtx.154
-rwxr-xr-xsupport/easydtx/edtx2dtx.pl99
-rw-r--r--support/texshop/README.txt2
-rw-r--r--support/texshop/texshop518.html41
-rw-r--r--support/texshop/texshop520.html40
-rw-r--r--systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl7
-rw-r--r--systems/texlive/tlnet/tlpkg/texlive.tlpdb609
-rw-r--r--systems/texlive/tlnet/tlpkg/texlive.tlpdb.md52
-rw-r--r--systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha5122
-rw-r--r--systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc16
-rw-r--r--systems/texlive/tlnet/tlpkg/texlive.tlpdb.xzbin2477744 -> 2483544 bytes
-rw-r--r--systems/win32/miktex/tm/packages/files.csv.lzmabin766556 -> 768272 bytes
-rw-r--r--systems/win32/miktex/tm/packages/next/files.csv.lzmabin766428 -> 768436 bytes
-rw-r--r--systems/win32/miktex/tm/packages/next/pr.ini10
-rw-r--r--systems/win32/miktex/tm/packages/pr.ini12
-rw-r--r--timestamp2
60 files changed, 23935 insertions, 435 deletions
diff --git a/FILES.byname b/FILES.byname
index a03189100b..b8f4c3ddfb 100644
--- a/FILES.byname
+++ b/FILES.byname
@@ -2059,12 +2059,12 @@
2023/10/05 | 1710 | biblio/citation-style-language/README.md
2023/10/05 | 12878 | biblio/citation-style-language/vancouver.csl
2023/10/05 | 4531754 | biblio/citation-style-language.zip
-2023/10/10 | 1678 | biblio/ctan-bibdata/biblatex-ctan/ctan.bbx
+2023/10/11 | 1678 | biblio/ctan-bibdata/biblatex-ctan/ctan.bbx
2022/10/08 | 127 | biblio/ctan-bibdata/biblatex-ctan/ctan.cbx
-2023/10/10 | 2815719 | biblio/ctan-bibdata/ctan.bib
-2023/10/10 | 3712530 | biblio/ctan-bibdata/ctan.pdf
+2023/10/11 | 2815719 | biblio/ctan-bibdata/ctan.bib
+2023/10/11 | 3713325 | biblio/ctan-bibdata/ctan.pdf
2023/01/16 | 1489 | biblio/ctan-bibdata/README
-2023/10/10 | 4115543 | biblio/ctan-bibdata.zip
+2023/10/11 | 4116473 | biblio/ctan-bibdata.zip
2023/02/23 | 3126 | biblio/pbibtex/pbibtex-base/cpp.awk
2023/02/23 | 1009 | biblio/pbibtex/pbibtex-base/generate.sh
2023/02/23 | 22362 | biblio/pbibtex/pbibtex-base/jabbrv.bst
@@ -5424,7 +5424,7 @@
1990/10/02 | 5440 | dviware/vutex/vaxvms.hlp
1990/10/02 | 812 | dviware/vutex/vaxvms.ins
1990/10/02 | 127576 | dviware/vutex/vutex.web
-2023/10/10 | 428167 | FILES.last07days
+2023/10/11 | 514147 | FILES.last07days
2021/07/24 | 1139410 | fonts/aboensis/Aboensis.glyphs
2021/07/24 | 18907382 | fonts/aboensis/aboensis.pdf
2021/07/24 | 137860 | fonts/aboensis/Aboensis-Regular.otf
@@ -194464,8 +194464,10 @@
2017/03/09 | 168862 | install/language/hebrew/cjhebrew.tds.zip
2022/03/13 | 7725339 | install/language/vietnamese/vntex.tds.zip
2022/10/16 | 1502578 | install/macros/eplain.tds.zip
+2023/10/10 | 37322 | install/macros/generic/advice.tds.zip
2012/03/29 | 378358 | install/macros/generic/bitelist.tds.zip
2015/11/14 | 558928 | install/macros/generic/catcodes.tds.zip
+2023/10/10 | 62818 | install/macros/generic/collargs.tds.zip
2015/11/16 | 603358 | install/macros/generic/commado.tds.zip
2015/11/14 | 1248858 | install/macros/generic/dowith.tds.zip
2023/01/23 | 862071 | install/macros/generic/expkv-bundle.tds.zip
@@ -194473,6 +194475,7 @@
2012/09/20 | 321508 | install/macros/generic/langcode.tds.zip
2023/04/27 | 1452921 | install/macros/generic/markdown.tds.zip
2014/06/11 | 428488 | install/macros/generic/mathdots.tds.zip
+2023/10/10 | 2801056 | install/macros/generic/memoize.tds.zip
2014/01/02 | 496633 | install/macros/generic/minifp.tds.zip
2012/09/20 | 369585 | install/macros/generic/plainpkg.tds.zip
2018/08/26 | 1014893 | install/macros/generic/tex-locale.tds.zip
@@ -194834,6 +194837,7 @@
2012/05/08 | 180596 | install/support/ctanupload.tds.zip
2007/03/17 | 12449 | install/support/ctanWeb/install_test.tds.zip
2007/03/21 | 12401 | install/support/ctanWeb/jhtest.tds.zip
+2023/10/10 | 18898 | install/support/easydtx.tds.zip
2021/03/13 | 47335840 | install/support/gregoriotex.tds.zip
2015/12/31 | 575855 | install/support/pmxchords.tds.zip
2020/09/28 | 171126 | install/support/texdef.tds.zip
@@ -202369,6 +202373,13 @@
2005/08/10 | 5742 | macros/generic/abbr/abbr.tex
2005/08/10 | 1062 | macros/generic/abbr/README
2005/08/10 | 3043 | macros/generic/abbr.zip
+2023/10/10 | 46048 | macros/generic/advice/advice.edtx
+2023/10/10 | 1281 | macros/generic/advice/advice.ins
+2023/10/10 | 2236 | macros/generic/advice/INSTALL.md
+2023/10/10 | 19102 | macros/generic/advice/LICENCE
+2023/10/10 | 162 | macros/generic/advice/Makefile
+2023/10/10 | 401 | macros/generic/advice/README.md
+2023/10/11 | 22201 | macros/generic/advice.zip
2018/04/22 | 133390 | macros/generic/apnum/apnum.d
2018/04/22 | 720414 | macros/generic/apnum/apnum.pdf
2018/04/18 | 50821 | macros/generic/apnum/apnum.tex
@@ -202510,6 +202521,13 @@
1996/04/17 | 716 | macros/generic/code128/README
1996/04/17 | 4503 | macros/generic/code128/test128.tex
2005/09/25 | 8755 | macros/generic/code128.zip
+2023/10/10 | 109800 | macros/generic/collargs/collargs.edtx
+2023/10/10 | 1301 | macros/generic/collargs/collargs.ins
+2023/10/10 | 2131 | macros/generic/collargs/INSTALL.md
+2023/10/10 | 19102 | macros/generic/collargs/LICENCE
+2023/10/10 | 162 | macros/generic/collargs/Makefile
+2023/10/10 | 435 | macros/generic/collargs/README.md
+2023/10/11 | 36401 | macros/generic/collargs.zip
2010/05/13 | 177 | macros/generic/colortab/Changes
2010/05/13 | 62039 | macros/generic/colortab/colortab-doc.pdf
2010/05/13 | 13703 | macros/generic/colortab/colortab-doc.tex
@@ -203020,6 +203038,10 @@
2005/07/31 | 1858 | macros/generic/epsf/tepsf3.tex
2005/07/23 | 5483 | macros/generic/epsf/tepsf.eps
2011/02/18 | 300284 | macros/generic/epsf.zip
+2023/10/10 | 3175 | macros/generic/etoolbox-generic/etoolbox-generic.tex
+2023/10/10 | 19102 | macros/generic/etoolbox-generic/LICENCE
+2023/10/10 | 355 | macros/generic/etoolbox-generic/README.md
+2023/10/11 | 8434 | macros/generic/etoolbox-generic.zip
2023/08/23 | 36792 | macros/generic/expex-acro/expex-acro.dtx
2023/08/23 | 1794 | macros/generic/expex-acro/expex-acro.ins
2023/08/23 | 88970 | macros/generic/expex-acro/expex-acro.pdf
@@ -203296,6 +203318,30 @@
2014/06/11 | 1340 | macros/generic/mathdots/plmdotest.tex
2014/06/11 | 2128 | macros/generic/mathdots/README
2014/06/12 | 424240 | macros/generic/mathdots.zip
+2023/10/10 | 31104 | macros/generic/memoize/doc/examples-src.zip
+2023/10/10 | 31068 | macros/generic/memoize/doc/examples.zip
+2023/10/10 | 1630 | macros/generic/memoize/doc/memoize-clean.1.md
+2023/10/10 | 621070 | macros/generic/memoize/doc/memoize-code.pdf
+2023/10/10 | 7924 | macros/generic/memoize/doc/memoize-code.sty
+2023/10/10 | 3158 | macros/generic/memoize/doc/memoize-code.tex
+2023/10/10 | 5166 | macros/generic/memoize/doc/memoize-doc-common.sty
+2023/10/10 | 21569 | macros/generic/memoize/doc/memoize-doc.sty
+2023/10/10 | 3340 | macros/generic/memoize/doc/memoize-extract.1.md
+2023/10/10 | 10 | macros/generic/memoize/doc/memoize.mst
+2023/10/10 | 2164795 | macros/generic/memoize/doc/memoize.pdf
+2023/10/10 | 453473 | macros/generic/memoize/doc/memoize.tex
+2023/10/10 | 12932 | macros/generic/memoize/doc/yadoc.sty
+2023/10/10 | 7078 | macros/generic/memoize/INSTALL.md
+2023/10/10 | 19102 | macros/generic/memoize/LICENCE
+2023/10/10 | 4514 | macros/generic/memoize/Makefile
+2023/10/10 | 5138 | macros/generic/memoize/memoize-clean.pl
+2023/10/10 | 6184 | macros/generic/memoize/memoize-clean.py
+2023/10/10 | 141402 | macros/generic/memoize/memoize.edtx
+2023/10/10 | 7715 | macros/generic/memoize/memoize-extract.pl
+2023/10/10 | 9008 | macros/generic/memoize/memoize-extract.py
+2023/10/10 | 1668 | macros/generic/memoize/memoize.ins
+2023/10/10 | 668 | macros/generic/memoize/README.md
+2023/10/11 | 2753204 | macros/generic/memoize.zip
1993/02/15 | 15966 | macros/generic/midnight/border.doc
1993/02/15 | 10837 | macros/generic/midnight/border.tex
1993/02/15 | 12687 | macros/generic/midnight/dolines.doc
@@ -281611,6 +281657,12 @@
2002/02/07 | 283 | support/dvispell/Win9x-ME/ortograi.bat
2002/02/07 | 283 | support/dvispell/Win9x-ME/ortogras.bat
2002/02/07 | 150 | support/dvispell/Win9x-ME/ortonull.bat
+2023/10/10 | 6004 | support/easydtx/easydoctex-mode.el
+2023/10/10 | 1532 | support/easydtx/edtx2dtx.1
+2023/10/10 | 2836 | support/easydtx/edtx2dtx.pl
+2023/10/10 | 35149 | support/easydtx/LICENCE
+2023/10/10 | 611 | support/easydtx/README.md
+2023/10/11 | 17299 | support/easydtx.zip
2004/09/23 | 76 | support/easylatex/clean.sh
2004/02/27 | 18354 | support/easylatex/COPYRIGHT
2004/02/29 | 253 | support/easylatex/demo-no-graph.txt
@@ -287360,9 +287412,9 @@
1999/09/13 | 17553 | support/texref/texref
1999/09/14 | 10702 | support/texref/texref.1
2006/03/12 | 12757 | support/texref.zip
-2023/09/20 | 754 | support/texshop/README.txt
-2023/09/21 | 3695 | support/texshop/texshop518.html
-2023/09/21 | 69921039 | support/texshop/texshop518.zip
+2023/10/10 | 752 | support/texshop/README.txt
+2023/10/09 | 3797 | support/texshop/texshop520.html
+2023/10/10 | 70697157 | support/texshop/texshop520.zip
1994/11/10 | 411107 | support/texspell/texspell.zip
1994/11/10 | 42315 | support/texspell/texspsrc.zip
1994/11/10 | 411107 | support/texspell.zip
@@ -292588,8 +292640,8 @@
2022/04/29 | 6048 | systems/texlive/tlnet/archive/circledtext.r63166.tar.xz
2022/04/08 | 23672 | systems/texlive/tlnet/archive/circ.r62977.tar.xz
2022/04/08 | 38440 | systems/texlive/tlnet/archive/circ.source.r62977.tar.xz
-2023/06/25 | 1809960 | systems/texlive/tlnet/archive/circuitikz.doc.r67458.tar.xz
-2023/06/25 | 173848 | systems/texlive/tlnet/archive/circuitikz.r67458.tar.xz
+2023/10/11 | 1822592 | systems/texlive/tlnet/archive/circuitikz.doc.r68502.tar.xz
+2023/10/11 | 174792 | systems/texlive/tlnet/archive/circuitikz.r68502.tar.xz
2023/09/14 | 3331920 | systems/texlive/tlnet/archive/circuit-macros.doc.r68264.tar.xz
2023/09/14 | 1500 | systems/texlive/tlnet/archive/circuit-macros.r68264.tar.xz
2023/10/08 | 182608 | systems/texlive/tlnet/archive/circularglyphs.doc.r68476.tar.xz
@@ -295900,10 +295952,10 @@
2021/06/21 | 38768 | systems/texlive/tlnet/archive/ha-prosper.source.r59651.tar.xz
2020/03/04 | 216528 | systems/texlive/tlnet/archive/har2nat.doc.r54080.tar.xz
2020/03/04 | 1112 | systems/texlive/tlnet/archive/har2nat.r54080.tar.xz
-2023/06/11 | 3032 | systems/texlive/tlnet/archive/haranoaji.doc.r67330.tar.xz
-2023/06/11 | 3044 | systems/texlive/tlnet/archive/haranoaji-extra.doc.r67329.tar.xz
-2023/06/11 | 26016156 | systems/texlive/tlnet/archive/haranoaji-extra.r67329.tar.xz
-2023/06/11 | 26145400 | systems/texlive/tlnet/archive/haranoaji.r67330.tar.xz
+2023/10/11 | 3032 | systems/texlive/tlnet/archive/haranoaji.doc.r68501.tar.xz
+2023/10/11 | 3044 | systems/texlive/tlnet/archive/haranoaji-extra.doc.r68500.tar.xz
+2023/10/11 | 26018152 | systems/texlive/tlnet/archive/haranoaji-extra.r68500.tar.xz
+2023/10/11 | 26182680 | systems/texlive/tlnet/archive/haranoaji.r68501.tar.xz
2019/02/28 | 120084 | systems/texlive/tlnet/archive/hardwrap.doc.r21396.tar.xz
2019/02/28 | 2732 | systems/texlive/tlnet/archive/hardwrap.r21396.tar.xz
2019/02/28 | 11108 | systems/texlive/tlnet/archive/hardwrap.source.r21396.tar.xz
@@ -296367,9 +296419,9 @@
2019/02/28 | 156688 | systems/texlive/tlnet/archive/index.doc.r24099.tar.xz
2019/02/28 | 11040 | systems/texlive/tlnet/archive/index.r24099.tar.xz
2019/02/28 | 14900 | systems/texlive/tlnet/archive/index.source.r24099.tar.xz
-2019/02/28 | 611172 | systems/texlive/tlnet/archive/indextools.doc.r38931.tar.xz
-2019/02/28 | 4560 | systems/texlive/tlnet/archive/indextools.r38931.tar.xz
-2019/02/28 | 21688 | systems/texlive/tlnet/archive/indextools.source.r38931.tar.xz
+2023/10/11 | 562396 | systems/texlive/tlnet/archive/indextools.doc.r68499.tar.xz
+2023/10/11 | 4564 | systems/texlive/tlnet/archive/indextools.r68499.tar.xz
+2023/10/11 | 21720 | systems/texlive/tlnet/archive/indextools.source.r68499.tar.xz
2019/12/05 | 284912 | systems/texlive/tlnet/archive/infwarerr.doc.r53023.tar.xz
2019/12/05 | 2668 | systems/texlive/tlnet/archive/infwarerr.r53023.tar.xz
2019/12/05 | 5712 | systems/texlive/tlnet/archive/infwarerr.source.r53023.tar.xz
@@ -296831,9 +296883,9 @@
2022/06/24 | 480 | systems/texlive/tlnet/archive/l2tabu.r63708.tar.xz
2019/02/28 | 227412 | systems/texlive/tlnet/archive/l2tabu-spanish.doc.r15878.tar.xz
2019/02/28 | 448 | systems/texlive/tlnet/archive/l2tabu-spanish.r15878.tar.xz
-2023/04/20 | 888376 | systems/texlive/tlnet/archive/l3backend.doc.r66896.tar.xz
-2023/04/20 | 16240 | systems/texlive/tlnet/archive/l3backend.r66896.tar.xz
-2023/04/20 | 33852 | systems/texlive/tlnet/archive/l3backend.source.r66896.tar.xz
+2023/10/11 | 889136 | systems/texlive/tlnet/archive/l3backend.doc.r68507.tar.xz
+2023/10/11 | 16220 | systems/texlive/tlnet/archive/l3backend.r68507.tar.xz
+2023/10/11 | 33852 | systems/texlive/tlnet/archive/l3backend.source.r68507.tar.xz
2019/02/28 | 344 | systems/texlive/tlnet/archive/l3build.aarch64-linux.r46894.tar.xz
2019/02/28 | 344 | systems/texlive/tlnet/archive/l3build.amd64-freebsd.r46894.tar.xz
2019/02/28 | 340 | systems/texlive/tlnet/archive/l3build.amd64-netbsd.r46894.tar.xz
@@ -296852,15 +296904,15 @@
2019/02/28 | 344 | systems/texlive/tlnet/archive/l3build.x86_64-linuxmusl.r46894.tar.xz
2019/02/28 | 340 | systems/texlive/tlnet/archive/l3build.x86_64-linux.r46894.tar.xz
2019/02/28 | 340 | systems/texlive/tlnet/archive/l3build.x86_64-solaris.r46894.tar.xz
-2023/05/12 | 3498172 | systems/texlive/tlnet/archive/l3experimental.doc.r67074.tar.xz
-2023/05/12 | 23660 | systems/texlive/tlnet/archive/l3experimental.r67074.tar.xz
-2023/05/12 | 80176 | systems/texlive/tlnet/archive/l3experimental.source.r67074.tar.xz
-2023/08/30 | 12007176 | systems/texlive/tlnet/archive/l3kernel.doc.r68106.tar.xz
-2023/08/30 | 173872 | systems/texlive/tlnet/archive/l3kernel.r68106.tar.xz
-2023/08/30 | 598548 | systems/texlive/tlnet/archive/l3kernel.source.r68106.tar.xz
-2023/09/04 | 1833200 | systems/texlive/tlnet/archive/l3packages.doc.r68165.tar.xz
-2023/09/04 | 22120 | systems/texlive/tlnet/archive/l3packages.r68165.tar.xz
-2023/09/04 | 46280 | systems/texlive/tlnet/archive/l3packages.source.r68165.tar.xz
+2023/10/11 | 3498508 | systems/texlive/tlnet/archive/l3experimental.doc.r68507.tar.xz
+2023/10/11 | 23632 | systems/texlive/tlnet/archive/l3experimental.r68507.tar.xz
+2023/10/11 | 80200 | systems/texlive/tlnet/archive/l3experimental.source.r68507.tar.xz
+2023/10/11 | 12036152 | systems/texlive/tlnet/archive/l3kernel.doc.r68507.tar.xz
+2023/10/11 | 174520 | systems/texlive/tlnet/archive/l3kernel.r68507.tar.xz
+2023/10/11 | 600376 | systems/texlive/tlnet/archive/l3kernel.source.r68507.tar.xz
+2023/10/11 | 1832932 | systems/texlive/tlnet/archive/l3packages.doc.r68507.tar.xz
+2023/10/11 | 22112 | systems/texlive/tlnet/archive/l3packages.r68507.tar.xz
+2023/10/11 | 46252 | systems/texlive/tlnet/archive/l3packages.source.r68507.tar.xz
2019/02/28 | 210236 | systems/texlive/tlnet/archive/labbook.doc.r15878.tar.xz
2019/02/28 | 4180 | systems/texlive/tlnet/archive/labbook.r15878.tar.xz
2019/02/28 | 23192 | systems/texlive/tlnet/archive/labbook.source.r15878.tar.xz
@@ -297854,9 +297906,9 @@
2023/05/08 | 1883936 | systems/texlive/tlnet/archive/luatex.i386-linux.r67047.tar.xz
2023/05/03 | 1457072 | systems/texlive/tlnet/archive/luatex.i386-netbsd.r66987.tar.xz
2023/05/06 | 1619368 | systems/texlive/tlnet/archive/luatex.i386-solaris.r67024.tar.xz
-2023/05/04 | 3244724 | systems/texlive/tlnet/archive/luatexja.doc.r67003.tar.xz
-2023/05/04 | 193016 | systems/texlive/tlnet/archive/luatexja.r67003.tar.xz
-2023/05/04 | 83900 | systems/texlive/tlnet/archive/luatexja.source.r67003.tar.xz
+2023/10/11 | 3245540 | systems/texlive/tlnet/archive/luatexja.doc.r68506.tar.xz
+2023/10/11 | 193052 | systems/texlive/tlnet/archive/luatexja.r68506.tar.xz
+2023/10/11 | 83900 | systems/texlive/tlnet/archive/luatexja.source.r68506.tar.xz
2023/09/12 | 350680 | systems/texlive/tlnet/archive/luatexko.doc.r68243.tar.xz
2023/09/12 | 23676 | systems/texlive/tlnet/archive/luatexko.r68243.tar.xz
2023/04/30 | 13712 | systems/texlive/tlnet/archive/luatex.r66967.tar.xz
@@ -299066,8 +299118,8 @@
2019/02/28 | 174560 | systems/texlive/tlnet/archive/nomentbl.doc.r16549.tar.xz
2019/02/28 | 2456 | systems/texlive/tlnet/archive/nomentbl.r16549.tar.xz
2019/02/28 | 6048 | systems/texlive/tlnet/archive/nomentbl.source.r16549.tar.xz
-2023/09/28 | 162820 | systems/texlive/tlnet/archive/non-decimal-units.doc.r68382.tar.xz
-2023/09/28 | 4732 | systems/texlive/tlnet/archive/non-decimal-units.r68382.tar.xz
+2023/10/11 | 157180 | systems/texlive/tlnet/archive/non-decimal-units.doc.r68504.tar.xz
+2023/10/11 | 5852 | systems/texlive/tlnet/archive/non-decimal-units.r68504.tar.xz
2019/02/28 | 306696 | systems/texlive/tlnet/archive/nonfloat.doc.r17598.tar.xz
2019/02/28 | 1484 | systems/texlive/tlnet/archive/nonfloat.r17598.tar.xz
2019/02/28 | 5596 | systems/texlive/tlnet/archive/nonfloat.source.r17598.tar.xz
@@ -299610,9 +299662,9 @@
2022/10/30 | 314616 | systems/texlive/tlnet/archive/pdflscape.doc.r64851.tar.xz
2022/10/30 | 2612 | systems/texlive/tlnet/archive/pdflscape.r64851.tar.xz
2022/10/30 | 6508 | systems/texlive/tlnet/archive/pdflscape.source.r64851.tar.xz
-2023/08/30 | 8746688 | systems/texlive/tlnet/archive/pdfmanagement-testphase.doc.r68107.tar.xz
-2023/08/30 | 53708 | systems/texlive/tlnet/archive/pdfmanagement-testphase.r68107.tar.xz
-2023/08/30 | 137424 | systems/texlive/tlnet/archive/pdfmanagement-testphase.source.r68107.tar.xz
+2023/10/11 | 8753320 | systems/texlive/tlnet/archive/pdfmanagement-testphase.doc.r68505.tar.xz
+2023/10/11 | 53900 | systems/texlive/tlnet/archive/pdfmanagement-testphase.r68505.tar.xz
+2023/10/11 | 137880 | systems/texlive/tlnet/archive/pdfmanagement-testphase.source.r68505.tar.xz
2019/02/28 | 381552 | systems/texlive/tlnet/archive/pdfmarginpar.doc.r23492.tar.xz
2019/02/28 | 2424 | systems/texlive/tlnet/archive/pdfmarginpar.r23492.tar.xz
2023/03/22 | 234168 | systems/texlive/tlnet/archive/pdfmsym.doc.r66618.tar.xz
@@ -302404,7 +302456,7 @@
2022/09/13 | 600 | systems/texlive/tlnet/archive/texlive-scripts.amd64-freebsd.r64356.tar.xz
2022/09/13 | 596 | systems/texlive/tlnet/archive/texlive-scripts.amd64-netbsd.r64356.tar.xz
2022/09/13 | 596 | systems/texlive/tlnet/archive/texlive-scripts.armhf-linux.r64356.tar.xz
-2023/10/10 | 430052 | systems/texlive/tlnet/archive/texlive-scripts.doc.r68489.tar.xz
+2023/10/11 | 430052 | systems/texlive/tlnet/archive/texlive-scripts.doc.r68498.tar.xz
2020/01/27 | 916 | systems/texlive/tlnet/archive/texlive-scripts-extra.aarch64-linux.r53577.tar.xz
2020/01/27 | 924 | systems/texlive/tlnet/archive/texlive-scripts-extra.amd64-freebsd.r53577.tar.xz
2020/01/27 | 916 | systems/texlive/tlnet/archive/texlive-scripts-extra.amd64-netbsd.r53577.tar.xz
@@ -302426,7 +302478,7 @@
2022/09/13 | 592 | systems/texlive/tlnet/archive/texlive-scripts.i386-linux.r64356.tar.xz
2022/09/13 | 596 | systems/texlive/tlnet/archive/texlive-scripts.i386-netbsd.r64356.tar.xz
2022/09/13 | 596 | systems/texlive/tlnet/archive/texlive-scripts.i386-solaris.r64356.tar.xz
-2023/10/10 | 114072 | systems/texlive/tlnet/archive/texlive-scripts.r68489.tar.xz
+2023/10/11 | 114076 | systems/texlive/tlnet/archive/texlive-scripts.r68498.tar.xz
2022/09/13 | 580 | systems/texlive/tlnet/archive/texlive-scripts.universal-darwin.r64356.tar.xz
2023/05/14 | 60312 | systems/texlive/tlnet/archive/texlive-scripts.windows.r67095.tar.xz
2022/09/13 | 596 | systems/texlive/tlnet/archive/texlive-scripts.x86_64-cygwin.r64356.tar.xz
@@ -302928,8 +302980,8 @@
2023/02/24 | 16308 | systems/texlive/tlnet/archive/tkz-base.r66115.tar.xz
2021/01/22 | 924656 | systems/texlive/tlnet/archive/tkz-berge.doc.r57485.tar.xz
2021/01/22 | 8444 | systems/texlive/tlnet/archive/tkz-berge.r57485.tar.xz
-2023/09/10 | 182972 | systems/texlive/tlnet/archive/tkz-bernoulli.doc.r68219.tar.xz
-2023/09/10 | 2516 | systems/texlive/tlnet/archive/tkz-bernoulli.r68219.tar.xz
+2023/10/11 | 189396 | systems/texlive/tlnet/archive/tkz-bernoulli.doc.r68503.tar.xz
+2023/10/11 | 2736 | systems/texlive/tlnet/archive/tkz-bernoulli.r68503.tar.xz
2023/02/24 | 40184 | systems/texlive/tlnet/archive/tkz-doc.doc.r66115.tar.xz
2023/02/24 | 508 | systems/texlive/tlnet/archive/tkz-doc.r66115.tar.xz
2023/02/04 | 1110880 | systems/texlive/tlnet/archive/tkz-euclide.doc.r65724.tar.xz
@@ -304306,16 +304358,16 @@
2020/07/18 | 47816 | systems/texlive/tlnet/archive/zztex.doc.r55862.tar.xz
2020/07/18 | 101724 | systems/texlive/tlnet/archive/zztex.r55862.tar.xz
2023/08/07 | 125713 | systems/texlive/tlnet/install-tl
-2023/10/10 | 5739739 | systems/texlive/tlnet/install-tl-unx.tar.gz
-2023/10/10 | 152 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512
-2023/10/10 | 488 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512.asc
+2023/10/11 | 5741760 | systems/texlive/tlnet/install-tl-unx.tar.gz
+2023/10/11 | 152 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512
+2023/10/11 | 488 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512.asc
2023/05/13 | 5083 | systems/texlive/tlnet/install-tl-windows.bat
-2023/10/10 | 21037851 | systems/texlive/tlnet/install-tl-windows.exe
-2023/10/10 | 153 | systems/texlive/tlnet/install-tl-windows.exe.sha512
-2023/10/10 | 488 | systems/texlive/tlnet/install-tl-windows.exe.sha512.asc
-2023/10/10 | 26029113 | systems/texlive/tlnet/install-tl.zip
-2023/10/10 | 145 | systems/texlive/tlnet/install-tl.zip.sha512
-2023/10/10 | 488 | systems/texlive/tlnet/install-tl.zip.sha512.asc
+2023/10/11 | 21036598 | systems/texlive/tlnet/install-tl-windows.exe
+2023/10/11 | 153 | systems/texlive/tlnet/install-tl-windows.exe.sha512
+2023/10/11 | 488 | systems/texlive/tlnet/install-tl-windows.exe.sha512.asc
+2023/10/11 | 26029112 | systems/texlive/tlnet/install-tl.zip
+2023/10/11 | 145 | systems/texlive/tlnet/install-tl.zip.sha512
+2023/10/11 | 488 | systems/texlive/tlnet/install-tl.zip.sha512.asc
2023/03/19 | 1229 | systems/texlive/tlnet/README.md
2023/03/19 | 0 | systems/texlive/tlnet/TEXLIVE_2023
2023/01/17 | 8401 | systems/texlive/tlnet/tlpkg/gpg/pubring.gpg
@@ -304325,7 +304377,7 @@
2023/01/17 | 1280 | systems/texlive/tlnet/tlpkg/gpg/trustdb.gpg
2023/09/20 | 50622 | systems/texlive/tlnet/tlpkg/installer/config.guess
2010/11/11 | 11651 | systems/texlive/tlnet/tlpkg/installer/COPYING.MinGW-runtime.txt
-2023/10/09 | 7165 | systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
+2023/10/10 | 7155 | systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
2023/08/23 | 221470 | systems/texlive/tlnet/tlpkg/installer/curl/curl-ca-bundle.crt
2020/04/15 | 2606592 | systems/texlive/tlnet/tlpkg/installer/curl/curl.exe
2017/04/16 | 2629 | systems/texlive/tlnet/tlpkg/installer/installer-options.txt
@@ -304367,12 +304419,12 @@
2023/02/21 | 20371 | systems/texlive/tlnet/tlpkg/TeXLive/TLCrypto.pm
2021/12/21 | 5429 | systems/texlive/tlnet/tlpkg/TeXLive/TLDownload.pm
2023/04/08 | 28167 | systems/texlive/tlnet/tlpkg/TeXLive/TLPaper.pm
-2023/10/10 | 18284219 | systems/texlive/tlnet/tlpkg/texlive.tlpdb
-2023/10/10 | 48 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
+2023/10/11 | 18284246 | systems/texlive/tlnet/tlpkg/texlive.tlpdb
+2023/10/11 | 48 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
2023/09/18 | 87727 | systems/texlive/tlnet/tlpkg/TeXLive/TLPDB.pm
-2023/10/10 | 144 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
-2023/10/10 | 488 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
-2023/10/10 | 2481360 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
+2023/10/11 | 144 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
+2023/10/11 | 488 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
+2023/10/11 | 2477744 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
2023/02/20 | 58928 | systems/texlive/tlnet/tlpkg/TeXLive/TLPOBJ.pm
2023/06/11 | 42749 | systems/texlive/tlnet/tlpkg/TeXLive/TLPSRC.pm
2023/02/21 | 16138 | systems/texlive/tlnet/tlpkg/TeXLive/TLTREE.pm
@@ -309039,8 +309091,8 @@
2022/05/04 | 6254 | systems/win32/miktex/tm/packages/circledtext.tar.lzma
2010/03/08 | 182332 | systems/win32/miktex/tm/packages/circle.tar.lzma
2009/07/13 | 270032 | systems/win32/miktex/tm/packages/circ.tar.lzma
-2023/07/04 | 1809747 | systems/win32/miktex/tm/packages/circuitikz__doc.tar.lzma
-2023/07/04 | 192267 | systems/win32/miktex/tm/packages/circuitikz.tar.lzma
+2023/10/11 | 1822327 | systems/win32/miktex/tm/packages/circuitikz__doc.tar.lzma
+2023/10/11 | 193248 | systems/win32/miktex/tm/packages/circuitikz.tar.lzma
2023/10/07 | 179146 | systems/win32/miktex/tm/packages/circularglyphs__doc.tar.lzma
2023/10/07 | 4882 | systems/win32/miktex/tm/packages/circularglyphs__source.tar.lzma
2023/10/07 | 3044 | systems/win32/miktex/tm/packages/circularglyphs.tar.lzma
@@ -310059,7 +310111,7 @@
2022/11/01 | 5115 | systems/win32/miktex/tm/packages/filehook.tar.lzma
2012/12/04 | 924573 | systems/win32/miktex/tm/packages/fileinfo.tar.lzma
2011/09/21 | 281409 | systems/win32/miktex/tm/packages/filemod.tar.lzma
-2023/10/10 | 766556 | systems/win32/miktex/tm/packages/files.csv.lzma
+2023/10/11 | 768272 | systems/win32/miktex/tm/packages/files.csv.lzma
2001/05/14 | 5617 | systems/win32/miktex/tm/packages/finbib.tar.lzma
2015/10/20 | 44379 | systems/win32/miktex/tm/packages/findhyph.tar.lzma
2011/10/21 | 89323 | systems/win32/miktex/tm/packages/fink.tar.lzma
@@ -310514,11 +310566,11 @@
2012/01/10 | 52557 | systems/win32/miktex/tm/packages/happy4th.tar.lzma
2005/09/15 | 278342 | systems/win32/miktex/tm/packages/ha-prosper.cab
2005/12/29 | 1366 | systems/win32/miktex/tm/packages/har2nat.cab
-2023/06/16 | 3317 | systems/win32/miktex/tm/packages/haranoaji__doc.tar.lzma
-2023/06/16 | 3313 | systems/win32/miktex/tm/packages/haranoaji-extra__doc.tar.lzma
-2023/06/16 | 26264174 | systems/win32/miktex/tm/packages/haranoaji-extra.tar.lzma
+2023/10/11 | 3319 | systems/win32/miktex/tm/packages/haranoaji__doc.tar.lzma
+2023/10/11 | 3317 | systems/win32/miktex/tm/packages/haranoaji-extra__doc.tar.lzma
+2023/10/11 | 26261739 | systems/win32/miktex/tm/packages/haranoaji-extra.tar.lzma
2022/02/07 | 935 | systems/win32/miktex/tm/packages/haranoaji__source.tar.lzma
-2023/06/16 | 26235169 | systems/win32/miktex/tm/packages/haranoaji.tar.lzma
+2023/10/11 | 26270426 | systems/win32/miktex/tm/packages/haranoaji.tar.lzma
2011/02/15 | 134243 | systems/win32/miktex/tm/packages/hardwrap.tar.lzma
2007/05/12 | 6681 | systems/win32/miktex/tm/packages/harmony.tar.bz2
2012/05/29 | 52924 | systems/win32/miktex/tm/packages/harnon-cv.tar.lzma
@@ -310774,7 +310826,9 @@
2023/09/22 | 1571492 | systems/win32/miktex/tm/packages/inconsolata-nerd-font.tar.lzma
2019/06/24 | 478244 | systems/win32/miktex/tm/packages/inconsolata.tar.lzma
2004/04/10 | 184997 | systems/win32/miktex/tm/packages/index.cab
-2015/11/25 | 638376 | systems/win32/miktex/tm/packages/indextools.tar.lzma
+2023/10/11 | 564503 | systems/win32/miktex/tm/packages/indextools__doc.tar.lzma
+2023/10/11 | 22457 | systems/win32/miktex/tm/packages/indextools__source.tar.lzma
+2023/10/11 | 4831 | systems/win32/miktex/tm/packages/indextools.tar.lzma
2006/12/10 | 7740794 | systems/win32/miktex/tm/packages/indic-type1.tar.bz2
2008/10/14 | 23308 | systems/win32/miktex/tm/packages/indxcite.tar.lzma
2019/12/05 | 293465 | systems/win32/miktex/tm/packages/infwarerr.tar.lzma
@@ -311025,22 +311079,22 @@
2013/08/19 | 270728 | systems/win32/miktex/tm/packages/l2tabu-french.tar.lzma
2012/02/01 | 258354 | systems/win32/miktex/tm/packages/l2tabu-italian.tar.lzma
2016/02/07 | 246670 | systems/win32/miktex/tm/packages/l2tabu.tar.lzma
-2023/04/27 | 890480 | systems/win32/miktex/tm/packages/l3backend__doc.tar.lzma
-2023/04/27 | 34437 | systems/win32/miktex/tm/packages/l3backend__source.tar.lzma
-2023/04/27 | 16433 | systems/win32/miktex/tm/packages/l3backend.tar.lzma
+2023/10/11 | 891227 | systems/win32/miktex/tm/packages/l3backend__doc.tar.lzma
+2023/10/11 | 34428 | systems/win32/miktex/tm/packages/l3backend__source.tar.lzma
+2023/10/11 | 16458 | systems/win32/miktex/tm/packages/l3backend.tar.lzma
2023/09/22 | 737965 | systems/win32/miktex/tm/packages/l3build__doc.tar.lzma
2023/09/22 | 32022 | systems/win32/miktex/tm/packages/l3build__source.tar.lzma
2023/09/22 | 36784 | systems/win32/miktex/tm/packages/l3build.tar.lzma
2013/05/29 | 156214 | systems/win32/miktex/tm/packages/l3ctr2e.tar.lzma
-2023/05/12 | 3499237 | systems/win32/miktex/tm/packages/l3experimental__doc.tar.lzma
-2023/05/12 | 80929 | systems/win32/miktex/tm/packages/l3experimental__source.tar.lzma
-2023/05/12 | 23987 | systems/win32/miktex/tm/packages/l3experimental.tar.lzma
-2023/09/03 | 12001787 | systems/win32/miktex/tm/packages/l3kernel__doc.tar.lzma
-2023/09/03 | 601177 | systems/win32/miktex/tm/packages/l3kernel__source.tar.lzma
-2023/09/03 | 174259 | systems/win32/miktex/tm/packages/l3kernel.tar.lzma
-2023/09/03 | 1835058 | systems/win32/miktex/tm/packages/l3packages__doc.tar.lzma
-2023/09/03 | 46874 | systems/win32/miktex/tm/packages/l3packages__source.tar.lzma
-2023/09/03 | 22392 | systems/win32/miktex/tm/packages/l3packages.tar.lzma
+2023/10/11 | 3499716 | systems/win32/miktex/tm/packages/l3experimental__doc.tar.lzma
+2023/10/11 | 80889 | systems/win32/miktex/tm/packages/l3experimental__source.tar.lzma
+2023/10/11 | 23969 | systems/win32/miktex/tm/packages/l3experimental.tar.lzma
+2023/10/11 | 12031600 | systems/win32/miktex/tm/packages/l3kernel__doc.tar.lzma
+2023/10/11 | 602890 | systems/win32/miktex/tm/packages/l3kernel__source.tar.lzma
+2023/10/11 | 174964 | systems/win32/miktex/tm/packages/l3kernel.tar.lzma
+2023/10/11 | 1835393 | systems/win32/miktex/tm/packages/l3packages__doc.tar.lzma
+2023/10/11 | 46865 | systems/win32/miktex/tm/packages/l3packages__source.tar.lzma
+2023/10/11 | 22389 | systems/win32/miktex/tm/packages/l3packages.tar.lzma
2008/04/02 | 115132 | systems/win32/miktex/tm/packages/labbook.tar.lzma
2006/11/14 | 45130 | systems/win32/miktex/tm/packages/labelcas.cab
2019/05/15 | 27323 | systems/win32/miktex/tm/packages/labels4easylist.tar.lzma
@@ -311484,9 +311538,9 @@
2021/06/06 | 4099 | systems/win32/miktex/tm/packages/luatex85__source.tar.lzma
2021/06/06 | 2000 | systems/win32/miktex/tm/packages/luatex85.tar.lzma
2015/10/06 | 276167 | systems/win32/miktex/tm/packages/luatexbase.tar.lzma
-2023/05/10 | 3107615 | systems/win32/miktex/tm/packages/luatexja__doc.tar.lzma
-2023/04/15 | 221713 | systems/win32/miktex/tm/packages/luatexja__source.tar.lzma
-2023/05/10 | 194129 | systems/win32/miktex/tm/packages/luatexja.tar.lzma
+2023/10/11 | 3108660 | systems/win32/miktex/tm/packages/luatexja__doc.tar.lzma
+2023/10/11 | 221721 | systems/win32/miktex/tm/packages/luatexja__source.tar.lzma
+2023/10/11 | 194188 | systems/win32/miktex/tm/packages/luatexja.tar.lzma
2023/09/22 | 339697 | systems/win32/miktex/tm/packages/luatexko__doc.tar.lzma
2023/09/22 | 12524 | systems/win32/miktex/tm/packages/luatexko__source.tar.lzma
2023/09/22 | 23900 | systems/win32/miktex/tm/packages/luatexko.tar.lzma
@@ -311993,9 +312047,9 @@
2018/01/12 | 157226 | systems/win32/miktex/tm/packages/miktex-zip-bin-x64.tar.lzma
2022/07/26 | 39695 | systems/win32/miktex/tm/packages/miktex-zlib-bin-2.9.tar.lzma
2023/10/05 | 45827 | systems/win32/miktex/tm/packages/miktex-zlib-bin-x64-2.9.tar.lzma
-2023/10/10 | 334799 | systems/win32/miktex/tm/packages/miktex-zzdb1-2.9.tar.lzma
-2023/10/10 | 1952183 | systems/win32/miktex/tm/packages/miktex-zzdb2-2.9.tar.lzma
-2023/10/10 | 1684896 | systems/win32/miktex/tm/packages/miktex-zzdb3-2.9.tar.lzma
+2023/10/11 | 334869 | systems/win32/miktex/tm/packages/miktex-zzdb1-2.9.tar.lzma
+2023/10/11 | 1951494 | systems/win32/miktex/tm/packages/miktex-zzdb2-2.9.tar.lzma
+2023/10/11 | 1684668 | systems/win32/miktex/tm/packages/miktex-zzdb3-2.9.tar.lzma
2022/07/26 | 13519 | systems/win32/miktex/tm/packages/miktex-zzip-bin-2.9.tar.lzma
2023/10/05 | 14579 | systems/win32/miktex/tm/packages/miktex-zzip-bin-x64-2.9.tar.lzma
2016/07/15 | 35914 | systems/win32/miktex/tm/packages/mil3.tar.lzma
@@ -312273,102 +312327,102 @@
2022/11/01 | 230073 | systems/win32/miktex/tm/packages/newverbs__doc.tar.lzma
2022/11/01 | 7969 | systems/win32/miktex/tm/packages/newverbs__source.tar.lzma
2022/11/01 | 3030 | systems/win32/miktex/tm/packages/newverbs.tar.lzma
-2023/10/10 | 766428 | systems/win32/miktex/tm/packages/next/files.csv.lzma
-2023/10/10 | 36744 | systems/win32/miktex/tm/packages/next/miktex-arctrl-bin-x64-2.9.tar.lzma
-2023/10/10 | 1171965 | systems/win32/miktex/tm/packages/next/miktex-asymptote-bin-x64-2.9.tar.lzma
-2023/10/10 | 32065 | systems/win32/miktex/tm/packages/next/miktex-autosp-bin-x64-2.9.tar.lzma
-2023/10/10 | 36805 | systems/win32/miktex/tm/packages/next/miktex-axohelp-bin-x64-2.9.tar.lzma
-2023/10/10 | 67440 | systems/win32/miktex/tm/packages/next/miktex-bibarts-bin-x64-2.9.tar.lzma
-2023/10/10 | 103622 | systems/win32/miktex/tm/packages/next/miktex-bibtex8bit-bin-x64-2.9.tar.lzma
-2023/10/10 | 78361 | systems/win32/miktex/tm/packages/next/miktex-bibtex-bin-x64-2.9.tar.lzma
-2023/10/10 | 31563 | systems/win32/miktex/tm/packages/next/miktex-bzip2-bin-x64-2.9.tar.lzma
-2023/10/10 | 395454 | systems/win32/miktex/tm/packages/next/miktex-cairo-bin-x64-2.9.tar.lzma
-2023/10/10 | 40401 | systems/win32/miktex/tm/packages/next/miktex-chktex-bin-x64-2.9.tar.lzma
-2023/10/10 | 59242 | systems/win32/miktex/tm/packages/next/miktex-cjkutils-bin-x64-2.9.tar.lzma
-2023/10/10 | 272188 | systems/win32/miktex/tm/packages/next/miktex-console-bin-x64-2.9.tar.lzma
-2023/10/10 | 221451 | systems/win32/miktex/tm/packages/next/miktex-curl-bin-x64-2.9.tar.lzma
-2023/10/10 | 106590 | systems/win32/miktex/tm/packages/next/miktex-cweb-bin-x64-2.9.tar.lzma
-2023/10/10 | 25629 | systems/win32/miktex/tm/packages/next/miktex-devnag-bin-x64-2.9.tar.lzma
-2023/10/10 | 473015 | systems/win32/miktex/tm/packages/next/miktex-doc.tar.lzma
-2023/10/10 | 54163 | systems/win32/miktex/tm/packages/next/miktex-dvicopy-bin-x64-2.9.tar.lzma
-2023/10/10 | 329887 | systems/win32/miktex/tm/packages/next/miktex-dvipdfmx-bin-x64-2.9.tar.lzma
-2023/10/10 | 47432 | systems/win32/miktex/tm/packages/next/miktex-dvipng-bin-x64-2.9.tar.lzma
-2023/10/10 | 137625 | systems/win32/miktex/tm/packages/next/miktex-dvips-bin-x64-2.9.tar.lzma
-2023/10/10 | 1442511 | systems/win32/miktex/tm/packages/next/miktex-dvisvgm-bin-x64-2.9.tar.lzma
-2023/10/10 | 104397 | systems/win32/miktex/tm/packages/next/miktex-epstopdf-bin-x64-2.9.tar.lzma
-2023/10/10 | 49712 | systems/win32/miktex/tm/packages/next/miktex-expat-bin-x64-2.9.tar.lzma
-2023/10/10 | 29108 | systems/win32/miktex/tm/packages/next/miktex-findtexmf-bin-x64-2.9.tar.lzma
-2023/10/10 | 77295 | systems/win32/miktex/tm/packages/next/miktex-fmt-bin-x64-2.9.tar.lzma
-2023/10/10 | 159865 | systems/win32/miktex/tm/packages/next/miktex-fontconfig-bin-x64-2.9.tar.lzma
-2023/10/10 | 81627 | systems/win32/miktex/tm/packages/next/miktex-fonts-bin-x64-2.9.tar.lzma
-2023/10/10 | 82181 | systems/win32/miktex/tm/packages/next/miktex-freeglut-bin-x64-2.9.tar.lzma
-2023/10/10 | 305432 | systems/win32/miktex/tm/packages/next/miktex-freetype2-bin-x64-2.9.tar.lzma
-2023/10/10 | 25601 | systems/win32/miktex/tm/packages/next/miktex-fribidixetex-bin-x64-2.9.tar.lzma
-2023/10/10 | 105734 | systems/win32/miktex/tm/packages/next/miktex-gd-bin-x64-2.9.tar.lzma
-2023/10/10 | 73440 | systems/win32/miktex/tm/packages/next/miktex-graphite2-bin-x64-2.9.tar.lzma
-2023/10/10 | 117784 | systems/win32/miktex/tm/packages/next/miktex-gregorio-bin-x64-2.9.tar.lzma
-2023/10/10 | 44372 | systems/win32/miktex/tm/packages/next/miktex-gsf2pk-bin-x64-2.9.tar.lzma
-2023/10/10 | 698705 | systems/win32/miktex/tm/packages/next/miktex-harfbuzz-bin-x64-2.9.tar.lzma
-2023/10/10 | 249317 | systems/win32/miktex/tm/packages/next/miktex-hitex-bin-x64.tar.lzma
-2023/10/10 | 217246 | systems/win32/miktex/tm/packages/next/miktex-hunspell-bin-x64-2.9.tar.lzma
-2023/10/10 | 109894 | systems/win32/miktex/tm/packages/next/miktex-jpeg-bin-x64-2.9.tar.lzma
-2023/10/10 | 19994 | systems/win32/miktex/tm/packages/next/miktex-kpathsea-bin-x64-2.9.tar.lzma
-2023/10/10 | 32890 | systems/win32/miktex/tm/packages/next/miktex-lacheck-bin-x64-2.9.tar.lzma
-2023/10/10 | 706691 | systems/win32/miktex/tm/packages/next/miktex-lcdf-typetools-bin-x64-2.9.tar.lzma
-2023/10/10 | 601987 | systems/win32/miktex/tm/packages/next/miktex-libressl-bin-x64-2.9.tar.lzma
-2023/10/10 | 530466 | systems/win32/miktex/tm/packages/next/miktex-log4cxx-bin-x64-2.9.tar.lzma
-2023/10/10 | 104151 | systems/win32/miktex/tm/packages/next/miktex-lua53-bin-x64-2.9.tar.lzma
-2023/10/10 | 1993837 | systems/win32/miktex/tm/packages/next/miktex-luatex-bin-x64-2.9.tar.lzma
-2023/10/10 | 82013 | systems/win32/miktex/tm/packages/next/miktex-lzma-bin-x64-2.9.tar.lzma
-2023/10/10 | 33858 | systems/win32/miktex/tm/packages/next/miktex-makeindex-bin-x64-2.9.tar.lzma
-2023/10/10 | 8882 | systems/win32/miktex/tm/packages/next/miktex-md5-bin-x64-2.9.tar.lzma
-2023/10/10 | 232070 | systems/win32/miktex/tm/packages/next/miktex-metafont-bin-x64-2.9.tar.lzma
-2023/10/10 | 287579 | systems/win32/miktex/tm/packages/next/miktex-metapost-bin-x64-2.9.tar.lzma
-2023/10/10 | 108579 | systems/win32/miktex/tm/packages/next/miktex-mfware-bin-x64-2.9.tar.lzma
-2023/10/10 | 142010 | systems/win32/miktex/tm/packages/next/miktex-mktex-bin-x64-2.9.tar.lzma
-2023/10/10 | 291611 | systems/win32/miktex/tm/packages/next/miktex-mo-bin-x64-2.9.tar.lzma
-2023/10/10 | 182738 | systems/win32/miktex/tm/packages/next/miktex-mpfr-bin-x64-2.9.tar.lzma
-2023/10/10 | 55969 | systems/win32/miktex/tm/packages/next/miktex-mpmcli-bin-x64-2.9.tar.lzma
-2023/10/10 | 35357 | systems/win32/miktex/tm/packages/next/miktex-mspack-bin-x64-2.9.tar.lzma
-2023/10/10 | 44073 | systems/win32/miktex/tm/packages/next/miktex-mthelp-bin-x64-2.9.tar.lzma
-2023/10/10 | 48189 | systems/win32/miktex/tm/packages/next/miktex-mtprint-bin-x64-2.9.tar.lzma
-2023/10/10 | 52695 | systems/win32/miktex/tm/packages/next/miktex-m-tx-bin-x64-2.9.tar.lzma
-2023/10/10 | 218853 | systems/win32/miktex/tm/packages/next/miktex-omegaware-bin-x64-2.9.tar.lzma
-2023/10/10 | 43114 | systems/win32/miktex/tm/packages/next/miktex-patgen-bin-x64.tar.lzma
-2023/10/10 | 829866 | systems/win32/miktex/tm/packages/next/miktex-pdftex-bin-x64-2.9.tar.lzma
-2023/10/10 | 203009 | systems/win32/miktex/tm/packages/next/miktex-pixman-bin-x64-2.9.tar.lzma
-2023/10/10 | 245850 | systems/win32/miktex/tm/packages/next/miktex-pmx-bin-x64-2.9.tar.lzma
-2023/10/10 | 88657 | systems/win32/miktex/tm/packages/next/miktex-png-bin-x64-2.9.tar.lzma
-2023/10/10 | 1341359 | systems/win32/miktex/tm/packages/next/miktex-poppler-bin-x64-2.9.tar.lzma
-2023/10/10 | 24126 | systems/win32/miktex/tm/packages/next/miktex-popt-bin-x64-2.9.tar.lzma
-2023/10/10 | 37646 | systems/win32/miktex/tm/packages/next/miktex-posix-bin-x64-2.9.tar.lzma
-2023/10/10 | 75113 | systems/win32/miktex/tm/packages/next/miktex-ps2pk-bin-x64-2.9.tar.lzma
-2023/10/10 | 61030 | systems/win32/miktex/tm/packages/next/miktex-psutils-bin-x64-2.9.tar.lzma
-2023/10/10 | 499564 | systems/win32/miktex/tm/packages/next/miktex-ptex-bin-x64.tar.lzma
-2023/10/10 | 1530778 | systems/win32/miktex/tm/packages/next/miktex-runtime-bin-x64-2.9.tar.lzma
-2023/10/10 | 54768 | systems/win32/miktex/tm/packages/next/miktex-synctex-bin-x64-2.9.tar.lzma
-2023/10/10 | 65176 | systems/win32/miktex/tm/packages/next/miktex-tdsutil-bin-x64.tar.lzma
-2023/10/10 | 27112 | systems/win32/miktex/tm/packages/next/miktex-teckit-bin-x64-2.9.tar.lzma
-2023/10/10 | 19967 | systems/win32/miktex/tm/packages/next/miktex-tex2xindy-bin-x64-2.9.tar.lzma
-2023/10/10 | 73413 | systems/win32/miktex/tm/packages/next/miktex-tex4ht-bin-x64-2.9.tar.lzma
-2023/10/10 | 174204 | systems/win32/miktex/tm/packages/next/miktex-tex-bin-x64-2.9.tar.lzma
-2023/10/10 | 69681 | systems/win32/miktex/tm/packages/next/miktex-texify-bin-x64-2.9.tar.lzma
-2023/10/10 | 112490 | systems/win32/miktex/tm/packages/next/miktex-texware-bin-x64-2.9.tar.lzma
-2023/10/10 | 2844479 | systems/win32/miktex/tm/packages/next/miktex-texworks-bin-x64-2.9.tar.lzma
-2023/10/10 | 64795 | systems/win32/miktex/tm/packages/next/miktex-ttf2pk2-bin-x64-2.9.tar.lzma
-2023/10/10 | 44091 | systems/win32/miktex/tm/packages/next/miktex-upmendex-bin-x64.tar.lzma
-2023/10/10 | 33875 | systems/win32/miktex/tm/packages/next/miktex-uriparser-bin-x64-2.9.tar.lzma
-2023/10/10 | 76197 | systems/win32/miktex/tm/packages/next/miktex-web-bin-x64-2.9.tar.lzma
-2023/10/10 | 351802 | systems/win32/miktex/tm/packages/next/miktex-xetex-bin-x64-2.9.tar.lzma
-2023/10/10 | 58943 | systems/win32/miktex/tm/packages/next/miktex-xml2pmx-bin-x64.tar.lzma
-2023/10/10 | 606755 | systems/win32/miktex/tm/packages/next/miktex-yap-bin-x64-2.9.tar.lzma
-2023/10/10 | 45935 | systems/win32/miktex/tm/packages/next/miktex-zlib-bin-x64-2.9.tar.lzma
-2023/10/10 | 334871 | systems/win32/miktex/tm/packages/next/miktex-zzdb1-2.9.tar.lzma
-2023/10/10 | 1949822 | systems/win32/miktex/tm/packages/next/miktex-zzdb2-2.9.tar.lzma
-2023/10/10 | 1684918 | systems/win32/miktex/tm/packages/next/miktex-zzdb3-2.9.tar.lzma
-2023/10/10 | 14600 | systems/win32/miktex/tm/packages/next/miktex-zzip-bin-x64-2.9.tar.lzma
+2023/10/11 | 768436 | systems/win32/miktex/tm/packages/next/files.csv.lzma
+2023/10/11 | 36702 | systems/win32/miktex/tm/packages/next/miktex-arctrl-bin-x64-2.9.tar.lzma
+2023/10/11 | 1172027 | systems/win32/miktex/tm/packages/next/miktex-asymptote-bin-x64-2.9.tar.lzma
+2023/10/11 | 32092 | systems/win32/miktex/tm/packages/next/miktex-autosp-bin-x64-2.9.tar.lzma
+2023/10/11 | 36806 | systems/win32/miktex/tm/packages/next/miktex-axohelp-bin-x64-2.9.tar.lzma
+2023/10/11 | 67507 | systems/win32/miktex/tm/packages/next/miktex-bibarts-bin-x64-2.9.tar.lzma
+2023/10/11 | 103691 | systems/win32/miktex/tm/packages/next/miktex-bibtex8bit-bin-x64-2.9.tar.lzma
+2023/10/11 | 78397 | systems/win32/miktex/tm/packages/next/miktex-bibtex-bin-x64-2.9.tar.lzma
+2023/10/11 | 31590 | systems/win32/miktex/tm/packages/next/miktex-bzip2-bin-x64-2.9.tar.lzma
+2023/10/11 | 395348 | systems/win32/miktex/tm/packages/next/miktex-cairo-bin-x64-2.9.tar.lzma
+2023/10/11 | 40387 | systems/win32/miktex/tm/packages/next/miktex-chktex-bin-x64-2.9.tar.lzma
+2023/10/11 | 59246 | systems/win32/miktex/tm/packages/next/miktex-cjkutils-bin-x64-2.9.tar.lzma
+2023/10/11 | 271948 | systems/win32/miktex/tm/packages/next/miktex-console-bin-x64-2.9.tar.lzma
+2023/10/11 | 221532 | systems/win32/miktex/tm/packages/next/miktex-curl-bin-x64-2.9.tar.lzma
+2023/10/11 | 106652 | systems/win32/miktex/tm/packages/next/miktex-cweb-bin-x64-2.9.tar.lzma
+2023/10/11 | 25580 | systems/win32/miktex/tm/packages/next/miktex-devnag-bin-x64-2.9.tar.lzma
+2023/10/11 | 473178 | systems/win32/miktex/tm/packages/next/miktex-doc.tar.lzma
+2023/10/11 | 54190 | systems/win32/miktex/tm/packages/next/miktex-dvicopy-bin-x64-2.9.tar.lzma
+2023/10/11 | 330066 | systems/win32/miktex/tm/packages/next/miktex-dvipdfmx-bin-x64-2.9.tar.lzma
+2023/10/11 | 47369 | systems/win32/miktex/tm/packages/next/miktex-dvipng-bin-x64-2.9.tar.lzma
+2023/10/11 | 137772 | systems/win32/miktex/tm/packages/next/miktex-dvips-bin-x64-2.9.tar.lzma
+2023/10/11 | 1438855 | systems/win32/miktex/tm/packages/next/miktex-dvisvgm-bin-x64-2.9.tar.lzma
+2023/10/11 | 104463 | systems/win32/miktex/tm/packages/next/miktex-epstopdf-bin-x64-2.9.tar.lzma
+2023/10/11 | 49746 | systems/win32/miktex/tm/packages/next/miktex-expat-bin-x64-2.9.tar.lzma
+2023/10/11 | 29102 | systems/win32/miktex/tm/packages/next/miktex-findtexmf-bin-x64-2.9.tar.lzma
+2023/10/11 | 77307 | systems/win32/miktex/tm/packages/next/miktex-fmt-bin-x64-2.9.tar.lzma
+2023/10/11 | 159866 | systems/win32/miktex/tm/packages/next/miktex-fontconfig-bin-x64-2.9.tar.lzma
+2023/10/11 | 81632 | systems/win32/miktex/tm/packages/next/miktex-fonts-bin-x64-2.9.tar.lzma
+2023/10/11 | 82025 | systems/win32/miktex/tm/packages/next/miktex-freeglut-bin-x64-2.9.tar.lzma
+2023/10/11 | 305307 | systems/win32/miktex/tm/packages/next/miktex-freetype2-bin-x64-2.9.tar.lzma
+2023/10/11 | 25614 | systems/win32/miktex/tm/packages/next/miktex-fribidixetex-bin-x64-2.9.tar.lzma
+2023/10/11 | 105776 | systems/win32/miktex/tm/packages/next/miktex-gd-bin-x64-2.9.tar.lzma
+2023/10/11 | 73370 | systems/win32/miktex/tm/packages/next/miktex-graphite2-bin-x64-2.9.tar.lzma
+2023/10/11 | 117749 | systems/win32/miktex/tm/packages/next/miktex-gregorio-bin-x64-2.9.tar.lzma
+2023/10/11 | 44392 | systems/win32/miktex/tm/packages/next/miktex-gsf2pk-bin-x64-2.9.tar.lzma
+2023/10/11 | 699530 | systems/win32/miktex/tm/packages/next/miktex-harfbuzz-bin-x64-2.9.tar.lzma
+2023/10/11 | 249308 | systems/win32/miktex/tm/packages/next/miktex-hitex-bin-x64.tar.lzma
+2023/10/11 | 217540 | systems/win32/miktex/tm/packages/next/miktex-hunspell-bin-x64-2.9.tar.lzma
+2023/10/11 | 109916 | systems/win32/miktex/tm/packages/next/miktex-jpeg-bin-x64-2.9.tar.lzma
+2023/10/11 | 19988 | systems/win32/miktex/tm/packages/next/miktex-kpathsea-bin-x64-2.9.tar.lzma
+2023/10/11 | 32873 | systems/win32/miktex/tm/packages/next/miktex-lacheck-bin-x64-2.9.tar.lzma
+2023/10/11 | 707534 | systems/win32/miktex/tm/packages/next/miktex-lcdf-typetools-bin-x64-2.9.tar.lzma
+2023/10/11 | 603097 | systems/win32/miktex/tm/packages/next/miktex-libressl-bin-x64-2.9.tar.lzma
+2023/10/11 | 530335 | systems/win32/miktex/tm/packages/next/miktex-log4cxx-bin-x64-2.9.tar.lzma
+2023/10/11 | 104120 | systems/win32/miktex/tm/packages/next/miktex-lua53-bin-x64-2.9.tar.lzma
+2023/10/11 | 2002088 | systems/win32/miktex/tm/packages/next/miktex-luatex-bin-x64-2.9.tar.lzma
+2023/10/11 | 82038 | systems/win32/miktex/tm/packages/next/miktex-lzma-bin-x64-2.9.tar.lzma
+2023/10/11 | 33844 | systems/win32/miktex/tm/packages/next/miktex-makeindex-bin-x64-2.9.tar.lzma
+2023/10/11 | 8879 | systems/win32/miktex/tm/packages/next/miktex-md5-bin-x64-2.9.tar.lzma
+2023/10/11 | 232083 | systems/win32/miktex/tm/packages/next/miktex-metafont-bin-x64-2.9.tar.lzma
+2023/10/11 | 287525 | systems/win32/miktex/tm/packages/next/miktex-metapost-bin-x64-2.9.tar.lzma
+2023/10/11 | 108523 | systems/win32/miktex/tm/packages/next/miktex-mfware-bin-x64-2.9.tar.lzma
+2023/10/11 | 141919 | systems/win32/miktex/tm/packages/next/miktex-mktex-bin-x64-2.9.tar.lzma
+2023/10/11 | 291596 | systems/win32/miktex/tm/packages/next/miktex-mo-bin-x64-2.9.tar.lzma
+2023/10/11 | 182720 | systems/win32/miktex/tm/packages/next/miktex-mpfr-bin-x64-2.9.tar.lzma
+2023/10/11 | 55908 | systems/win32/miktex/tm/packages/next/miktex-mpmcli-bin-x64-2.9.tar.lzma
+2023/10/11 | 35340 | systems/win32/miktex/tm/packages/next/miktex-mspack-bin-x64-2.9.tar.lzma
+2023/10/11 | 44062 | systems/win32/miktex/tm/packages/next/miktex-mthelp-bin-x64-2.9.tar.lzma
+2023/10/11 | 48170 | systems/win32/miktex/tm/packages/next/miktex-mtprint-bin-x64-2.9.tar.lzma
+2023/10/11 | 52693 | systems/win32/miktex/tm/packages/next/miktex-m-tx-bin-x64-2.9.tar.lzma
+2023/10/11 | 219285 | systems/win32/miktex/tm/packages/next/miktex-omegaware-bin-x64-2.9.tar.lzma
+2023/10/11 | 43098 | systems/win32/miktex/tm/packages/next/miktex-patgen-bin-x64.tar.lzma
+2023/10/11 | 830111 | systems/win32/miktex/tm/packages/next/miktex-pdftex-bin-x64-2.9.tar.lzma
+2023/10/11 | 203221 | systems/win32/miktex/tm/packages/next/miktex-pixman-bin-x64-2.9.tar.lzma
+2023/10/11 | 245929 | systems/win32/miktex/tm/packages/next/miktex-pmx-bin-x64-2.9.tar.lzma
+2023/10/11 | 88641 | systems/win32/miktex/tm/packages/next/miktex-png-bin-x64-2.9.tar.lzma
+2023/10/11 | 1342068 | systems/win32/miktex/tm/packages/next/miktex-poppler-bin-x64-2.9.tar.lzma
+2023/10/11 | 24123 | systems/win32/miktex/tm/packages/next/miktex-popt-bin-x64-2.9.tar.lzma
+2023/10/11 | 37633 | systems/win32/miktex/tm/packages/next/miktex-posix-bin-x64-2.9.tar.lzma
+2023/10/11 | 75143 | systems/win32/miktex/tm/packages/next/miktex-ps2pk-bin-x64-2.9.tar.lzma
+2023/10/11 | 60976 | systems/win32/miktex/tm/packages/next/miktex-psutils-bin-x64-2.9.tar.lzma
+2023/10/11 | 499476 | systems/win32/miktex/tm/packages/next/miktex-ptex-bin-x64.tar.lzma
+2023/10/11 | 1531198 | systems/win32/miktex/tm/packages/next/miktex-runtime-bin-x64-2.9.tar.lzma
+2023/10/11 | 54813 | systems/win32/miktex/tm/packages/next/miktex-synctex-bin-x64-2.9.tar.lzma
+2023/10/11 | 65103 | systems/win32/miktex/tm/packages/next/miktex-tdsutil-bin-x64.tar.lzma
+2023/10/11 | 27192 | systems/win32/miktex/tm/packages/next/miktex-teckit-bin-x64-2.9.tar.lzma
+2023/10/11 | 19947 | systems/win32/miktex/tm/packages/next/miktex-tex2xindy-bin-x64-2.9.tar.lzma
+2023/10/11 | 73456 | systems/win32/miktex/tm/packages/next/miktex-tex4ht-bin-x64-2.9.tar.lzma
+2023/10/11 | 174088 | systems/win32/miktex/tm/packages/next/miktex-tex-bin-x64-2.9.tar.lzma
+2023/10/11 | 69742 | systems/win32/miktex/tm/packages/next/miktex-texify-bin-x64-2.9.tar.lzma
+2023/10/11 | 112445 | systems/win32/miktex/tm/packages/next/miktex-texware-bin-x64-2.9.tar.lzma
+2023/10/11 | 2844447 | systems/win32/miktex/tm/packages/next/miktex-texworks-bin-x64-2.9.tar.lzma
+2023/10/11 | 64669 | systems/win32/miktex/tm/packages/next/miktex-ttf2pk2-bin-x64-2.9.tar.lzma
+2023/10/11 | 44080 | systems/win32/miktex/tm/packages/next/miktex-upmendex-bin-x64.tar.lzma
+2023/10/11 | 33889 | systems/win32/miktex/tm/packages/next/miktex-uriparser-bin-x64-2.9.tar.lzma
+2023/10/11 | 76152 | systems/win32/miktex/tm/packages/next/miktex-web-bin-x64-2.9.tar.lzma
+2023/10/11 | 352243 | systems/win32/miktex/tm/packages/next/miktex-xetex-bin-x64-2.9.tar.lzma
+2023/10/11 | 58925 | systems/win32/miktex/tm/packages/next/miktex-xml2pmx-bin-x64.tar.lzma
+2023/10/11 | 607027 | systems/win32/miktex/tm/packages/next/miktex-yap-bin-x64-2.9.tar.lzma
+2023/10/11 | 46016 | systems/win32/miktex/tm/packages/next/miktex-zlib-bin-x64-2.9.tar.lzma
+2023/10/11 | 334870 | systems/win32/miktex/tm/packages/next/miktex-zzdb1-2.9.tar.lzma
+2023/10/11 | 1952527 | systems/win32/miktex/tm/packages/next/miktex-zzdb2-2.9.tar.lzma
+2023/10/11 | 1685135 | systems/win32/miktex/tm/packages/next/miktex-zzdb3-2.9.tar.lzma
+2023/10/11 | 14613 | systems/win32/miktex/tm/packages/next/miktex-zzip-bin-x64-2.9.tar.lzma
2019/03/12 | 1412 | systems/win32/miktex/tm/packages/nextpage.tar.lzma
-2023/10/10 | 1150 | systems/win32/miktex/tm/packages/next/pr.ini
+2023/10/11 | 1150 | systems/win32/miktex/tm/packages/next/pr.ini
2018/07/06 | 145915 | systems/win32/miktex/tm/packages/nexus-otf.tar.lzma
2017/03/30 | 191149 | systems/win32/miktex/tm/packages/nfssext-cfr.tar.lzma
2023/02/23 | 608421 | systems/win32/miktex/tm/packages/nicefilelist__doc.tar.lzma
@@ -312422,9 +312476,9 @@
2021/11/13 | 19036 | systems/win32/miktex/tm/packages/nomencl__source.tar.lzma
2021/11/13 | 4020 | systems/win32/miktex/tm/packages/nomencl.tar.lzma
2006/04/22 | 54211 | systems/win32/miktex/tm/packages/nomentbl.cab
-2023/09/29 | 158562 | systems/win32/miktex/tm/packages/non-decimal-units__doc.tar.lzma
-2023/09/29 | 5742 | systems/win32/miktex/tm/packages/non-decimal-units__source.tar.lzma
-2023/09/29 | 4882 | systems/win32/miktex/tm/packages/non-decimal-units.tar.lzma
+2023/10/11 | 151971 | systems/win32/miktex/tm/packages/non-decimal-units__doc.tar.lzma
+2023/10/11 | 6694 | systems/win32/miktex/tm/packages/non-decimal-units__source.tar.lzma
+2023/10/11 | 6081 | systems/win32/miktex/tm/packages/non-decimal-units.tar.lzma
2005/06/02 | 128501 | systems/win32/miktex/tm/packages/nonfloat.cab
2011/04/19 | 792767 | systems/win32/miktex/tm/packages/nonumonpart.tar.lzma
2010/05/10 | 171659 | systems/win32/miktex/tm/packages/nopageno.tar.lzma
@@ -312698,9 +312752,9 @@
2022/11/01 | 315249 | systems/win32/miktex/tm/packages/pdflscape__doc.tar.lzma
2022/11/01 | 6886 | systems/win32/miktex/tm/packages/pdflscape__source.tar.lzma
2022/11/15 | 2831 | systems/win32/miktex/tm/packages/pdflscape.tar.lzma
-2023/09/03 | 8720302 | systems/win32/miktex/tm/packages/pdfmanagement-testphase__doc.tar.lzma
-2023/09/03 | 140819 | systems/win32/miktex/tm/packages/pdfmanagement-testphase__source.tar.lzma
-2023/09/03 | 53904 | systems/win32/miktex/tm/packages/pdfmanagement-testphase.tar.lzma
+2023/10/11 | 8727193 | systems/win32/miktex/tm/packages/pdfmanagement-testphase__doc.tar.lzma
+2023/10/11 | 141313 | systems/win32/miktex/tm/packages/pdfmanagement-testphase__source.tar.lzma
+2023/10/11 | 54108 | systems/win32/miktex/tm/packages/pdfmanagement-testphase.tar.lzma
2011/08/11 | 384460 | systems/win32/miktex/tm/packages/pdfmarginpar.tar.lzma
2023/03/17 | 227057 | systems/win32/miktex/tm/packages/pdfmsym__doc.tar.lzma
2023/03/17 | 8829 | systems/win32/miktex/tm/packages/pdfmsym__source.tar.lzma
@@ -312981,7 +313035,7 @@
2023/03/17 | 425296 | systems/win32/miktex/tm/packages/principia__doc.tar.lzma
2023/03/17 | 16206 | systems/win32/miktex/tm/packages/principia__source.tar.lzma
2023/03/17 | 8606 | systems/win32/miktex/tm/packages/principia.tar.lzma
-2023/10/10 | 950 | systems/win32/miktex/tm/packages/pr.ini
+2023/10/11 | 1024 | systems/win32/miktex/tm/packages/pr.ini
2010/09/27 | 248469 | systems/win32/miktex/tm/packages/printlen.tar.lzma
2008/06/17 | 77313 | systems/win32/miktex/tm/packages/proba.tar.lzma
2017/07/12 | 988486 | systems/win32/miktex/tm/packages/probsoln.tar.lzma
@@ -314310,9 +314364,9 @@
2022/07/25 | 56034 | systems/win32/miktex/tm/packages/tkz-base__source.tar.lzma
2022/07/25 | 16392 | systems/win32/miktex/tm/packages/tkz-base.tar.lzma
2021/01/22 | 945692 | systems/win32/miktex/tm/packages/tkz-berge.tar.lzma
-2023/09/10 | 179911 | systems/win32/miktex/tm/packages/tkz-bernoulli__doc.tar.lzma
-2023/09/10 | 4124 | systems/win32/miktex/tm/packages/tkz-bernoulli__source.tar.lzma
-2023/09/10 | 2709 | systems/win32/miktex/tm/packages/tkz-bernoulli.tar.lzma
+2023/10/11 | 186071 | systems/win32/miktex/tm/packages/tkz-bernoulli__doc.tar.lzma
+2023/10/11 | 4403 | systems/win32/miktex/tm/packages/tkz-bernoulli__source.tar.lzma
+2023/10/11 | 2927 | systems/win32/miktex/tm/packages/tkz-bernoulli.tar.lzma
2022/07/25 | 34549 | systems/win32/miktex/tm/packages/tkz-doc__source.tar.lzma
2022/07/25 | 7365 | systems/win32/miktex/tm/packages/tkz-doc.tar.lzma
2023/02/05 | 1032253 | systems/win32/miktex/tm/packages/tkz-euclide__doc.tar.lzma
@@ -315220,7 +315274,7 @@
2014/07/05 | 611 | systems/win32/yandy/README
2014/07/05 | 1004628 | systems/win32/yandy/yandy-src.tar.xz
2014/07/05 | 1012416 | systems/win32/yandy.zip
-2023/10/11 | 186 | timestamp
+2023/10/12 | 186 | timestamp
2002/08/26 | 61898 | usergrps/dante/antrag.pdf
2002/08/26 | 118217 | usergrps/dante/antrag.ps
2021/11/11 | 917 | usergrps/dante/dtk/doc/beispiel.bib
diff --git a/FILES.byname.gz b/FILES.byname.gz
index 5c22426985..be5ba28676 100644
--- a/FILES.byname.gz
+++ b/FILES.byname.gz
Binary files differ
diff --git a/FILES.last07days b/FILES.last07days
index 54548eb3fc..3ff5d8f59c 100644
--- a/FILES.last07days
+++ b/FILES.last07days
@@ -1,3 +1,192 @@
+2023/10/11 | 891227 | systems/win32/miktex/tm/packages/l3backend__doc.tar.lzma
+2023/10/11 | 889136 | systems/texlive/tlnet/archive/l3backend.doc.r68507.tar.xz
+2023/10/11 | 8879 | systems/win32/miktex/tm/packages/next/miktex-md5-bin-x64-2.9.tar.lzma
+2023/10/11 | 88641 | systems/win32/miktex/tm/packages/next/miktex-png-bin-x64-2.9.tar.lzma
+2023/10/11 | 8753320 | systems/texlive/tlnet/archive/pdfmanagement-testphase.doc.r68505.tar.xz
+2023/10/11 | 8727193 | systems/win32/miktex/tm/packages/pdfmanagement-testphase__doc.tar.lzma
+2023/10/11 | 8434 | macros/generic/etoolbox-generic.zip
+2023/10/11 | 83900 | systems/texlive/tlnet/archive/luatexja.source.r68506.tar.xz
+2023/10/11 | 830111 | systems/win32/miktex/tm/packages/next/miktex-pdftex-bin-x64-2.9.tar.lzma
+2023/10/11 | 82038 | systems/win32/miktex/tm/packages/next/miktex-lzma-bin-x64-2.9.tar.lzma
+2023/10/11 | 82025 | systems/win32/miktex/tm/packages/next/miktex-freeglut-bin-x64-2.9.tar.lzma
+2023/10/11 | 81632 | systems/win32/miktex/tm/packages/next/miktex-fonts-bin-x64-2.9.tar.lzma
+2023/10/11 | 80889 | systems/win32/miktex/tm/packages/l3experimental__source.tar.lzma
+2023/10/11 | 80200 | systems/texlive/tlnet/archive/l3experimental.source.r68507.tar.xz
+2023/10/11 | 78397 | systems/win32/miktex/tm/packages/next/miktex-bibtex-bin-x64-2.9.tar.lzma
+2023/10/11 | 77307 | systems/win32/miktex/tm/packages/next/miktex-fmt-bin-x64-2.9.tar.lzma
+2023/10/11 | 768436 | systems/win32/miktex/tm/packages/next/files.csv.lzma
+2023/10/11 | 768272 | systems/win32/miktex/tm/packages/files.csv.lzma
+2023/10/11 | 76152 | systems/win32/miktex/tm/packages/next/miktex-web-bin-x64-2.9.tar.lzma
+2023/10/11 | 75143 | systems/win32/miktex/tm/packages/next/miktex-ps2pk-bin-x64-2.9.tar.lzma
+2023/10/11 | 73456 | systems/win32/miktex/tm/packages/next/miktex-tex4ht-bin-x64-2.9.tar.lzma
+2023/10/11 | 73370 | systems/win32/miktex/tm/packages/next/miktex-graphite2-bin-x64-2.9.tar.lzma
+2023/10/11 | 707534 | systems/win32/miktex/tm/packages/next/miktex-lcdf-typetools-bin-x64-2.9.tar.lzma
+2023/10/11 | 699530 | systems/win32/miktex/tm/packages/next/miktex-harfbuzz-bin-x64-2.9.tar.lzma
+2023/10/11 | 69742 | systems/win32/miktex/tm/packages/next/miktex-texify-bin-x64-2.9.tar.lzma
+2023/10/11 | 67507 | systems/win32/miktex/tm/packages/next/miktex-bibarts-bin-x64-2.9.tar.lzma
+2023/10/11 | 6694 | systems/win32/miktex/tm/packages/non-decimal-units__source.tar.lzma
+2023/10/11 | 65103 | systems/win32/miktex/tm/packages/next/miktex-tdsutil-bin-x64.tar.lzma
+2023/10/11 | 64669 | systems/win32/miktex/tm/packages/next/miktex-ttf2pk2-bin-x64-2.9.tar.lzma
+2023/10/11 | 60976 | systems/win32/miktex/tm/packages/next/miktex-psutils-bin-x64-2.9.tar.lzma
+2023/10/11 | 6081 | systems/win32/miktex/tm/packages/non-decimal-units.tar.lzma
+2023/10/11 | 607027 | systems/win32/miktex/tm/packages/next/miktex-yap-bin-x64-2.9.tar.lzma
+2023/10/11 | 603097 | systems/win32/miktex/tm/packages/next/miktex-libressl-bin-x64-2.9.tar.lzma
+2023/10/11 | 602890 | systems/win32/miktex/tm/packages/l3kernel__source.tar.lzma
+2023/10/11 | 600376 | systems/texlive/tlnet/archive/l3kernel.source.r68507.tar.xz
+2023/10/11 | 59246 | systems/win32/miktex/tm/packages/next/miktex-cjkutils-bin-x64-2.9.tar.lzma
+2023/10/11 | 58925 | systems/win32/miktex/tm/packages/next/miktex-xml2pmx-bin-x64.tar.lzma
+2023/10/11 | 5852 | systems/texlive/tlnet/archive/non-decimal-units.r68504.tar.xz
+2023/10/11 | 5741760 | systems/texlive/tlnet/install-tl-unx.tar.gz
+2023/10/11 | 564503 | systems/win32/miktex/tm/packages/indextools__doc.tar.lzma
+2023/10/11 | 562396 | systems/texlive/tlnet/archive/indextools.doc.r68499.tar.xz
+2023/10/11 | 55908 | systems/win32/miktex/tm/packages/next/miktex-mpmcli-bin-x64-2.9.tar.lzma
+2023/10/11 | 54813 | systems/win32/miktex/tm/packages/next/miktex-synctex-bin-x64-2.9.tar.lzma
+2023/10/11 | 54190 | systems/win32/miktex/tm/packages/next/miktex-dvicopy-bin-x64-2.9.tar.lzma
+2023/10/11 | 54108 | systems/win32/miktex/tm/packages/pdfmanagement-testphase.tar.lzma
+2023/10/11 | 53900 | systems/texlive/tlnet/archive/pdfmanagement-testphase.r68505.tar.xz
+2023/10/11 | 530335 | systems/win32/miktex/tm/packages/next/miktex-log4cxx-bin-x64-2.9.tar.lzma
+2023/10/11 | 52693 | systems/win32/miktex/tm/packages/next/miktex-m-tx-bin-x64-2.9.tar.lzma
+2023/10/11 | 499476 | systems/win32/miktex/tm/packages/next/miktex-ptex-bin-x64.tar.lzma
+2023/10/11 | 49746 | systems/win32/miktex/tm/packages/next/miktex-expat-bin-x64-2.9.tar.lzma
+2023/10/11 | 48 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
+2023/10/11 | 488 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
+2023/10/11 | 488 | systems/texlive/tlnet/install-tl.zip.sha512.asc
+2023/10/11 | 488 | systems/texlive/tlnet/install-tl-windows.exe.sha512.asc
+2023/10/11 | 488 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512.asc
+2023/10/11 | 4831 | systems/win32/miktex/tm/packages/indextools.tar.lzma
+2023/10/11 | 48170 | systems/win32/miktex/tm/packages/next/miktex-mtprint-bin-x64-2.9.tar.lzma
+2023/10/11 | 47369 | systems/win32/miktex/tm/packages/next/miktex-dvipng-bin-x64-2.9.tar.lzma
+2023/10/11 | 473178 | systems/win32/miktex/tm/packages/next/miktex-doc.tar.lzma
+2023/10/11 | 46865 | systems/win32/miktex/tm/packages/l3packages__source.tar.lzma
+2023/10/11 | 46252 | systems/texlive/tlnet/archive/l3packages.source.r68507.tar.xz
+2023/10/11 | 46016 | systems/win32/miktex/tm/packages/next/miktex-zlib-bin-x64-2.9.tar.lzma
+2023/10/11 | 4564 | systems/texlive/tlnet/archive/indextools.r68499.tar.xz
+2023/10/11 | 44392 | systems/win32/miktex/tm/packages/next/miktex-gsf2pk-bin-x64-2.9.tar.lzma
+2023/10/11 | 44080 | systems/win32/miktex/tm/packages/next/miktex-upmendex-bin-x64.tar.lzma
+2023/10/11 | 44062 | systems/win32/miktex/tm/packages/next/miktex-mthelp-bin-x64-2.9.tar.lzma
+2023/10/11 | 4403 | systems/win32/miktex/tm/packages/tkz-bernoulli__source.tar.lzma
+2023/10/11 | 43098 | systems/win32/miktex/tm/packages/next/miktex-patgen-bin-x64.tar.lzma
+2023/10/11 | 430052 | systems/texlive/tlnet/archive/texlive-scripts.doc.r68498.tar.xz
+2023/10/11 | 4116473 | biblio/ctan-bibdata.zip
+2023/10/11 | 40387 | systems/win32/miktex/tm/packages/next/miktex-chktex-bin-x64-2.9.tar.lzma
+2023/10/11 | 395348 | systems/win32/miktex/tm/packages/next/miktex-cairo-bin-x64-2.9.tar.lzma
+2023/10/11 | 37633 | systems/win32/miktex/tm/packages/next/miktex-posix-bin-x64-2.9.tar.lzma
+2023/10/11 | 3713325 | biblio/ctan-bibdata/ctan.pdf
+2023/10/11 | 36806 | systems/win32/miktex/tm/packages/next/miktex-axohelp-bin-x64-2.9.tar.lzma
+2023/10/11 | 36702 | systems/win32/miktex/tm/packages/next/miktex-arctrl-bin-x64-2.9.tar.lzma
+2023/10/11 | 36401 | macros/generic/collargs.zip
+2023/10/11 | 35340 | systems/win32/miktex/tm/packages/next/miktex-mspack-bin-x64-2.9.tar.lzma
+2023/10/11 | 352243 | systems/win32/miktex/tm/packages/next/miktex-xetex-bin-x64-2.9.tar.lzma
+2023/10/11 | 3499716 | systems/win32/miktex/tm/packages/l3experimental__doc.tar.lzma
+2023/10/11 | 3498508 | systems/texlive/tlnet/archive/l3experimental.doc.r68507.tar.xz
+2023/10/11 | 34428 | systems/win32/miktex/tm/packages/l3backend__source.tar.lzma
+2023/10/11 | 33889 | systems/win32/miktex/tm/packages/next/miktex-uriparser-bin-x64-2.9.tar.lzma
+2023/10/11 | 33852 | systems/texlive/tlnet/archive/l3backend.source.r68507.tar.xz
+2023/10/11 | 33844 | systems/win32/miktex/tm/packages/next/miktex-makeindex-bin-x64-2.9.tar.lzma
+2023/10/11 | 334870 | systems/win32/miktex/tm/packages/next/miktex-zzdb1-2.9.tar.lzma
+2023/10/11 | 334869 | systems/win32/miktex/tm/packages/miktex-zzdb1-2.9.tar.lzma
+2023/10/11 | 3319 | systems/win32/miktex/tm/packages/haranoaji__doc.tar.lzma
+2023/10/11 | 3317 | systems/win32/miktex/tm/packages/haranoaji-extra__doc.tar.lzma
+2023/10/11 | 330066 | systems/win32/miktex/tm/packages/next/miktex-dvipdfmx-bin-x64-2.9.tar.lzma
+2023/10/11 | 32873 | systems/win32/miktex/tm/packages/next/miktex-lacheck-bin-x64-2.9.tar.lzma
+2023/10/11 | 3245540 | systems/texlive/tlnet/archive/luatexja.doc.r68506.tar.xz
+2023/10/11 | 32092 | systems/win32/miktex/tm/packages/next/miktex-autosp-bin-x64-2.9.tar.lzma
+2023/10/11 | 31590 | systems/win32/miktex/tm/packages/next/miktex-bzip2-bin-x64-2.9.tar.lzma
+2023/10/11 | 3108660 | systems/win32/miktex/tm/packages/luatexja__doc.tar.lzma
+2023/10/11 | 305307 | systems/win32/miktex/tm/packages/next/miktex-freetype2-bin-x64-2.9.tar.lzma
+2023/10/11 | 3044 | systems/texlive/tlnet/archive/haranoaji-extra.doc.r68500.tar.xz
+2023/10/11 | 3032 | systems/texlive/tlnet/archive/haranoaji.doc.r68501.tar.xz
+2023/10/11 | 2927 | systems/win32/miktex/tm/packages/tkz-bernoulli.tar.lzma
+2023/10/11 | 291596 | systems/win32/miktex/tm/packages/next/miktex-mo-bin-x64-2.9.tar.lzma
+2023/10/11 | 29102 | systems/win32/miktex/tm/packages/next/miktex-findtexmf-bin-x64-2.9.tar.lzma
+2023/10/11 | 287525 | systems/win32/miktex/tm/packages/next/miktex-metapost-bin-x64-2.9.tar.lzma
+2023/10/11 | 2844447 | systems/win32/miktex/tm/packages/next/miktex-texworks-bin-x64-2.9.tar.lzma
+2023/10/11 | 2815719 | biblio/ctan-bibdata/ctan.bib
+2023/10/11 | 2753204 | macros/generic/memoize.zip
+2023/10/11 | 2736 | systems/texlive/tlnet/archive/tkz-bernoulli.r68503.tar.xz
+2023/10/11 | 271948 | systems/win32/miktex/tm/packages/next/miktex-console-bin-x64-2.9.tar.lzma
+2023/10/11 | 27192 | systems/win32/miktex/tm/packages/next/miktex-teckit-bin-x64-2.9.tar.lzma
+2023/10/11 | 26270426 | systems/win32/miktex/tm/packages/haranoaji.tar.lzma
+2023/10/11 | 26261739 | systems/win32/miktex/tm/packages/haranoaji-extra.tar.lzma
+2023/10/11 | 26182680 | systems/texlive/tlnet/archive/haranoaji.r68501.tar.xz
+2023/10/11 | 26029112 | systems/texlive/tlnet/install-tl.zip
+2023/10/11 | 26018152 | systems/texlive/tlnet/archive/haranoaji-extra.r68500.tar.xz
+2023/10/11 | 25614 | systems/win32/miktex/tm/packages/next/miktex-fribidixetex-bin-x64-2.9.tar.lzma
+2023/10/11 | 25580 | systems/win32/miktex/tm/packages/next/miktex-devnag-bin-x64-2.9.tar.lzma
+2023/10/11 | 249308 | systems/win32/miktex/tm/packages/next/miktex-hitex-bin-x64.tar.lzma
+2023/10/11 | 2477744 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
+2023/10/11 | 245929 | systems/win32/miktex/tm/packages/next/miktex-pmx-bin-x64-2.9.tar.lzma
+2023/10/11 | 24123 | systems/win32/miktex/tm/packages/next/miktex-popt-bin-x64-2.9.tar.lzma
+2023/10/11 | 23969 | systems/win32/miktex/tm/packages/l3experimental.tar.lzma
+2023/10/11 | 23632 | systems/texlive/tlnet/archive/l3experimental.r68507.tar.xz
+2023/10/11 | 232083 | systems/win32/miktex/tm/packages/next/miktex-metafont-bin-x64-2.9.tar.lzma
+2023/10/11 | 22457 | systems/win32/miktex/tm/packages/indextools__source.tar.lzma
+2023/10/11 | 22389 | systems/win32/miktex/tm/packages/l3packages.tar.lzma
+2023/10/11 | 22201 | macros/generic/advice.zip
+2023/10/11 | 221721 | systems/win32/miktex/tm/packages/luatexja__source.tar.lzma
+2023/10/11 | 221532 | systems/win32/miktex/tm/packages/next/miktex-curl-bin-x64-2.9.tar.lzma
+2023/10/11 | 22112 | systems/texlive/tlnet/archive/l3packages.r68507.tar.xz
+2023/10/11 | 219285 | systems/win32/miktex/tm/packages/next/miktex-omegaware-bin-x64-2.9.tar.lzma
+2023/10/11 | 217540 | systems/win32/miktex/tm/packages/next/miktex-hunspell-bin-x64-2.9.tar.lzma
+2023/10/11 | 21720 | systems/texlive/tlnet/archive/indextools.source.r68499.tar.xz
+2023/10/11 | 21036598 | systems/texlive/tlnet/install-tl-windows.exe
+2023/10/11 | 203221 | systems/win32/miktex/tm/packages/next/miktex-pixman-bin-x64-2.9.tar.lzma
+2023/10/11 | 2002088 | systems/win32/miktex/tm/packages/next/miktex-luatex-bin-x64-2.9.tar.lzma
+2023/10/11 | 19988 | systems/win32/miktex/tm/packages/next/miktex-kpathsea-bin-x64-2.9.tar.lzma
+2023/10/11 | 19947 | systems/win32/miktex/tm/packages/next/miktex-tex2xindy-bin-x64-2.9.tar.lzma
+2023/10/11 | 1952527 | systems/win32/miktex/tm/packages/next/miktex-zzdb2-2.9.tar.lzma
+2023/10/11 | 1951494 | systems/win32/miktex/tm/packages/miktex-zzdb2-2.9.tar.lzma
+2023/10/11 | 194188 | systems/win32/miktex/tm/packages/luatexja.tar.lzma
+2023/10/11 | 193248 | systems/win32/miktex/tm/packages/circuitikz.tar.lzma
+2023/10/11 | 193052 | systems/texlive/tlnet/archive/luatexja.r68506.tar.xz
+2023/10/11 | 189396 | systems/texlive/tlnet/archive/tkz-bernoulli.doc.r68503.tar.xz
+2023/10/11 | 186071 | systems/win32/miktex/tm/packages/tkz-bernoulli__doc.tar.lzma
+2023/10/11 | 1835393 | systems/win32/miktex/tm/packages/l3packages__doc.tar.lzma
+2023/10/11 | 1832932 | systems/texlive/tlnet/archive/l3packages.doc.r68507.tar.xz
+2023/10/11 | 18284246 | systems/texlive/tlnet/tlpkg/texlive.tlpdb
+2023/10/11 | 182720 | systems/win32/miktex/tm/packages/next/miktex-mpfr-bin-x64-2.9.tar.lzma
+2023/10/11 | 1822592 | systems/texlive/tlnet/archive/circuitikz.doc.r68502.tar.xz
+2023/10/11 | 1822327 | systems/win32/miktex/tm/packages/circuitikz__doc.tar.lzma
+2023/10/11 | 174964 | systems/win32/miktex/tm/packages/l3kernel.tar.lzma
+2023/10/11 | 174792 | systems/texlive/tlnet/archive/circuitikz.r68502.tar.xz
+2023/10/11 | 174520 | systems/texlive/tlnet/archive/l3kernel.r68507.tar.xz
+2023/10/11 | 174088 | systems/win32/miktex/tm/packages/next/miktex-tex-bin-x64-2.9.tar.lzma
+2023/10/11 | 17299 | support/easydtx.zip
+2023/10/11 | 1685135 | systems/win32/miktex/tm/packages/next/miktex-zzdb3-2.9.tar.lzma
+2023/10/11 | 1684668 | systems/win32/miktex/tm/packages/miktex-zzdb3-2.9.tar.lzma
+2023/10/11 | 1678 | biblio/ctan-bibdata/biblatex-ctan/ctan.bbx
+2023/10/11 | 16458 | systems/win32/miktex/tm/packages/l3backend.tar.lzma
+2023/10/11 | 16220 | systems/texlive/tlnet/archive/l3backend.r68507.tar.xz
+2023/10/11 | 159866 | systems/win32/miktex/tm/packages/next/miktex-fontconfig-bin-x64-2.9.tar.lzma
+2023/10/11 | 157180 | systems/texlive/tlnet/archive/non-decimal-units.doc.r68504.tar.xz
+2023/10/11 | 153 | systems/texlive/tlnet/install-tl-windows.exe.sha512
+2023/10/11 | 1531198 | systems/win32/miktex/tm/packages/next/miktex-runtime-bin-x64-2.9.tar.lzma
+2023/10/11 | 152 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512
+2023/10/11 | 151971 | systems/win32/miktex/tm/packages/non-decimal-units__doc.tar.lzma
+2023/10/11 | 14613 | systems/win32/miktex/tm/packages/next/miktex-zzip-bin-x64-2.9.tar.lzma
+2023/10/11 | 145 | systems/texlive/tlnet/install-tl.zip.sha512
+2023/10/11 | 144 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
+2023/10/11 | 1438855 | systems/win32/miktex/tm/packages/next/miktex-dvisvgm-bin-x64-2.9.tar.lzma
+2023/10/11 | 141919 | systems/win32/miktex/tm/packages/next/miktex-mktex-bin-x64-2.9.tar.lzma
+2023/10/11 | 141313 | systems/win32/miktex/tm/packages/pdfmanagement-testphase__source.tar.lzma
+2023/10/11 | 137880 | systems/texlive/tlnet/archive/pdfmanagement-testphase.source.r68505.tar.xz
+2023/10/11 | 137772 | systems/win32/miktex/tm/packages/next/miktex-dvips-bin-x64-2.9.tar.lzma
+2023/10/11 | 1342068 | systems/win32/miktex/tm/packages/next/miktex-poppler-bin-x64-2.9.tar.lzma
+2023/10/11 | 12036152 | systems/texlive/tlnet/archive/l3kernel.doc.r68507.tar.xz
+2023/10/11 | 12031600 | systems/win32/miktex/tm/packages/l3kernel__doc.tar.lzma
+2023/10/11 | 117749 | systems/win32/miktex/tm/packages/next/miktex-gregorio-bin-x64-2.9.tar.lzma
+2023/10/11 | 1172027 | systems/win32/miktex/tm/packages/next/miktex-asymptote-bin-x64-2.9.tar.lzma
+2023/10/11 | 1150 | systems/win32/miktex/tm/packages/next/pr.ini
+2023/10/11 | 114076 | systems/texlive/tlnet/archive/texlive-scripts.r68498.tar.xz
+2023/10/11 | 112445 | systems/win32/miktex/tm/packages/next/miktex-texware-bin-x64-2.9.tar.lzma
+2023/10/11 | 109916 | systems/win32/miktex/tm/packages/next/miktex-jpeg-bin-x64-2.9.tar.lzma
+2023/10/11 | 108523 | systems/win32/miktex/tm/packages/next/miktex-mfware-bin-x64-2.9.tar.lzma
+2023/10/11 | 106652 | systems/win32/miktex/tm/packages/next/miktex-cweb-bin-x64-2.9.tar.lzma
+2023/10/11 | 105776 | systems/win32/miktex/tm/packages/next/miktex-gd-bin-x64-2.9.tar.lzma
+2023/10/11 | 104463 | systems/win32/miktex/tm/packages/next/miktex-epstopdf-bin-x64-2.9.tar.lzma
+2023/10/11 | 104120 | systems/win32/miktex/tm/packages/next/miktex-lua53-bin-x64-2.9.tar.lzma
+2023/10/11 | 103691 | systems/win32/miktex/tm/packages/next/miktex-bibtex8bit-bin-x64-2.9.tar.lzma
+2023/10/11 | 1024 | systems/win32/miktex/tm/packages/pr.ini
2023/10/10 | 9 | support/texlab/crates/parser/src/test_data/latex/label/label_reference_simple.txt
2023/10/10 | 9 | support/texlab/crates/parser/src/test_data/latex/glossary/glossary_entry_reference_simple.txt
2023/10/10 | 9 | support/texlab/crates/parser/src/test_data/latex/citation/citation_missing_brace.txt
@@ -20,7 +209,6 @@
2023/10/10 | 96044 | macros/latex/contrib/l3experimental/l3galley.dtx
2023/10/10 | 953 | support/texlab/crates/parser/src/snapshots/parser__build_log__tests__parse@005.txt.snap
2023/10/10 | 9538 | graphics/pgf/contrib/circuitikz/tex/pgfcirccurrent.tex
-2023/10/10 | 950 | systems/win32/miktex/tm/packages/pr.ini
2023/10/10 | 9479 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__knuth_1984.txt.snap
2023/10/10 | 946 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_multiple_entries.snap
2023/10/10 | 9465 | macros/latex/contrib/l3kernel/l3news08.tex
@@ -42,14 +230,13 @@
2023/10/10 | 904 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_857.txt.snap
2023/10/10 | 901 | support/texlab/crates/references/src/label.rs
2023/10/10 | 900 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__graphics_include_command.txt.snap
+2023/10/10 | 9008 | macros/generic/memoize/memoize-extract.py
2023/10/10 | 898 | support/texlab/crates/parser/src/test_data/bibtex/samples/kastenholz_2006.txt
2023/10/10 | 896 | macros/luatex/generic/luatexja/tool/otf-KozMinPr6N-Regular.txt
2023/10/10 | 8955 | support/texlab/crates/bibtex-utils/src/field/text.rs
2023/10/10 | 89007 | macros/latex/contrib/l3kernel/l3expan.dtx
2023/10/10 | 8883804 | systems/win32/miktex/tm/packages/profcollege__doc.tar.lzma
-2023/10/10 | 8882 | systems/win32/miktex/tm/packages/next/miktex-md5-bin-x64-2.9.tar.lzma
2023/10/10 | 8868 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__kastenholz_2006.txt.snap
-2023/10/10 | 88657 | systems/win32/miktex/tm/packages/next/miktex-png-bin-x64-2.9.tar.lzma
2023/10/10 | 885 | macros/luatex/generic/luatexja/src/patches/lltjp-stfloats.sty
2023/10/10 | 88106 | macros/latex/contrib/l3kernel/l3coffins.dtx
2023/10/10 | 87744 | macros/latex/contrib/l3kernel/l3box.dtx
@@ -74,18 +261,14 @@
2023/10/10 | 834142 | graphics/pgf/contrib/circuitikz/tex/t-circuitikz-1.0.tex
2023/10/10 | 83184 | macros/latex/contrib/l3kernel/l3clist.dtx
2023/10/10 | 82 | support/texlab/crates/parser/src/test_data/bibtex/comment.txt
-2023/10/10 | 829866 | systems/win32/miktex/tm/packages/next/miktex-pdftex-bin-x64-2.9.tar.lzma
2023/10/10 | 825 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@label__label_reference_incomplete.txt.snap
2023/10/10 | 825 | macros/luatex/generic/luatexja/src/patches/lltjp-collcell.sty
2023/10/10 | 82529 | macros/latex/contrib/l3kernel/l3prefixes.pdf
2023/10/10 | 8249 | support/texlab/crates/texlab/src/util/diagnostics.rs
2023/10/10 | 82320 | macros/latex/contrib/l3kernel/l3msg.dtx
2023/10/10 | 821 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@group__equation_missing_end.txt.snap
-2023/10/10 | 82181 | systems/win32/miktex/tm/packages/next/miktex-freeglut-bin-x64-2.9.tar.lzma
2023/10/10 | 820 | support/texlab/crates/distro/src/texlive.rs
-2023/10/10 | 82013 | systems/win32/miktex/tm/packages/next/miktex-lzma-bin-x64-2.9.tar.lzma
2023/10/10 | 818 | support/texlab/crates/hover/src/label.rs
-2023/10/10 | 81627 | systems/win32/miktex/tm/packages/next/miktex-fonts-bin-x64-2.9.tar.lzma
2023/10/10 | 815 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@glossary__acronym_reference_options.txt.snap
2023/10/10 | 815036 | macros/latex/contrib/pdfmanagement-testphase/l3pdfmeta.pdf
2023/10/10 | 814 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@equation_missing_begin.txt.snap
@@ -98,22 +281,19 @@
2023/10/10 | 7 | support/texlab/crates/parser/src/test_data/latex/citation/citation_empty.txt
2023/10/10 | 79 | support/texlab/crates/diagnostics/src/grammar.rs
2023/10/10 | 79587 | macros/latex/contrib/l3kernel/l3str.dtx
-2023/10/10 | 78361 | systems/win32/miktex/tm/packages/next/miktex-bibtex-bin-x64-2.9.tar.lzma
+2023/10/10 | 7924 | macros/generic/memoize/doc/memoize-code.sty
2023/10/10 | 7790 | macros/luatex/generic/luatexja/tool/jfm-convert.lua
2023/10/10 | 778 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap
2023/10/10 | 7762 | support/texlab/crates/parser/src/test_data/build_log/007.txt
2023/10/10 | 7732475 | support/texlab.zip
2023/10/10 | 772 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@caption__caption_figure.txt.snap
-2023/10/10 | 77295 | systems/win32/miktex/tm/packages/next/miktex-fmt-bin-x64-2.9.tar.lzma
+2023/10/10 | 7715 | macros/generic/memoize/memoize-extract.pl
2023/10/10 | 770 | support/texlab/crates/diagnostics/src/types.rs
2023/10/10 | 76 | support/texlab/crates/parser/src/test_data/latex/glossary/acronym_definition_options.txt
2023/10/10 | 7691 | macros/luatex/generic/luatexja/src/ltj-unicode-ccfix.lua
-2023/10/10 | 766556 | systems/win32/miktex/tm/packages/files.csv.lzma
-2023/10/10 | 766428 | systems/win32/miktex/tm/packages/next/files.csv.lzma
2023/10/10 | 7654 | macros/latex/contrib/pdfmanagement-testphase/color-ltx.sty
2023/10/10 | 762 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__graphics_include_complicated_options.txt.snap
2023/10/10 | 761 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@issue_809.txt.snap
-2023/10/10 | 76197 | systems/win32/miktex/tm/packages/next/miktex-web-bin-x64-2.9.tar.lzma
2023/10/10 | 760 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@glossary__acronym_package.txt.snap
2023/10/10 | 760 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@command_definition__command_definition_optional.txt.snap
2023/10/10 | 758 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@glossary__acronym_definition_simple.txt.snap
@@ -122,9 +302,9 @@
2023/10/10 | 7555 | macros/latex/contrib/l3packages/CHANGELOG.md
2023/10/10 | 7546 | macros/luatex/generic/luatexja/src/ltj-math.lua
2023/10/10 | 7531 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__aksin_2006.txt.snap
+2023/10/10 | 752 | support/texshop/README.txt
2023/10/10 | 7528 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__jain_1999.txt.snap
2023/10/10 | 751663 | graphics/pgf/contrib/circuitikz/tex/t-circuitikz-0.9.6.tex
-2023/10/10 | 75113 | systems/win32/miktex/tm/packages/next/miktex-ps2pk-bin-x64-2.9.tar.lzma
2023/10/10 | 751045 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield.pdf
2023/10/10 | 750 | support/texlab/crates/diagnostics/src/util.rs
2023/10/10 | 747768 | systems/win32/miktex/tm/packages/cascadia-code__doc.tar.lzma
@@ -137,8 +317,6 @@
2023/10/10 | 73835 | macros/latex/contrib/l3kernel/l3fp-trig.dtx
2023/10/10 | 7374 | macros/latex/contrib/l3packages/xfp.dtx
2023/10/10 | 734 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@color__color_definition_simple.txt.snap
-2023/10/10 | 73440 | systems/win32/miktex/tm/packages/next/miktex-graphite2-bin-x64-2.9.tar.lzma
-2023/10/10 | 73413 | systems/win32/miktex/tm/packages/next/miktex-tex4ht-bin-x64-2.9.tar.lzma
2023/10/10 | 7322 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__almendro_1998.txt.snap
2023/10/10 | 728 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_568.txt.snap
2023/10/10 | 728 | graphics/pgf/contrib/circuitikz/tex/circuitikz-0.4.sty
@@ -148,13 +326,15 @@
2023/10/10 | 717 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__graphics_include_options.txt.snap
2023/10/10 | 716 | support/texlab/crates/parser/src/snapshots/parser__build_log__tests__parse@001.txt.snap
2023/10/10 | 7157 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__combi_2004.txt.snap
+2023/10/10 | 7155 | systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
2023/10/10 | 711 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_texlabroot.snap
2023/10/10 | 710 | support/texlab/crates/distro/src/kpsewhich.rs
2023/10/10 | 7079 | macros/latex/contrib/l3kernel/l3term-glossary.tex
+2023/10/10 | 7078 | macros/generic/memoize/INSTALL.md
2023/10/10 | 706 | support/texlab/crates/parser/src/test_data/bibtex/samples/almendro_1998.txt
2023/10/10 | 706 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@structure__structure_siblings.txt.snap
+2023/10/10 | 70697157 | support/texshop/texshop520.zip
2023/10/10 | 70679 | macros/latex/contrib/l3kernel/l3fp.dtx
-2023/10/10 | 706691 | systems/win32/miktex/tm/packages/next/miktex-lcdf-typetools-bin-x64-2.9.tar.lzma
2023/10/10 | 706088 | macros/latex/contrib/pdfmanagement-testphase/l3backend-testphase.pdf
2023/10/10 | 70517 | macros/latex/contrib/l3kernel/expl3.dtx
2023/10/10 | 70482 | macros/latex/contrib/l3kernel/l3prg.dtx
@@ -164,9 +344,7 @@
2023/10/10 | 6 | support/texlab/crates/parser/src/test_data/latex/group/escaped_brackets.txt
2023/10/10 | 699 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_import.snap
2023/10/10 | 699 | support/texlab/crates/completion/src/providers.rs
-2023/10/10 | 698705 | systems/win32/miktex/tm/packages/next/miktex-harfbuzz-bin-x64-2.9.tar.lzma
2023/10/10 | 6970534 | support/texlab/crates/completion-data/data/completion.json.gz
-2023/10/10 | 69681 | systems/win32/miktex/tm/packages/next/miktex-texify-bin-x64-2.9.tar.lzma
2023/10/10 | 6963 | support/texlab/crates/syntax/src/bibtex/cst.rs
2023/10/10 | 6952 | macros/luatex/generic/luatexja/src/ltj-pretreat.lua
2023/10/10 | 694 | support/texlab/crates/syntax/src/bibtex.rs
@@ -185,18 +363,16 @@
2023/10/10 | 676 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap
2023/10/10 | 674 | support/texlab/crates/parser/src/test_data/bibtex/samples/jain_1999.txt
2023/10/10 | 674 | support/texlab/crates/parser/src/test_data/bibtex/samples/combi_2004.txt
-2023/10/10 | 67440 | systems/win32/miktex/tm/packages/next/miktex-bibarts-bin-x64-2.9.tar.lzma
2023/10/10 | 673 | support/texlab/crates/parser/src/snapshots/parser__build_log__tests__parse@003.txt.snap
+2023/10/10 | 668 | macros/generic/memoize/README.md
2023/10/10 | 6677 | macros/latex/contrib/l3kernel/l3news02.tex
2023/10/10 | 6644 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__blom_2021.txt.snap
2023/10/10 | 6571 | macros/luatex/generic/luatexja/src/ltj-latex.sty
2023/10/10 | 6529 | macros/luatex/generic/luatexja/src/patches/lltjdefs.sty
-2023/10/10 | 65176 | systems/win32/miktex/tm/packages/next/miktex-tdsutil-bin-x64.tar.lzma
2023/10/10 | 64 | support/texlab/crates/parser/src/test_data/latex/glossary/acronym_declaration.txt
2023/10/10 | 649 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@inline_double_dollar.txt.snap
2023/10/10 | 6482 | macros/latex/contrib/l3kernel/l3news03.tex
2023/10/10 | 647 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@caption__caption_default.txt.snap
-2023/10/10 | 64795 | systems/win32/miktex/tm/packages/next/miktex-ttf2pk2-bin-x64-2.9.tar.lzma
2023/10/10 | 6477 | support/texlab/crates/base-db/src/util/line_index.rs
2023/10/10 | 6472 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__rivest_1978.txt.snap
2023/10/10 | 645 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@command_definition__command_definition_simple.txt.snap
@@ -214,6 +390,7 @@
2023/10/10 | 631 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@inline.txt.snap
2023/10/10 | 631 | graphics/pgf/contrib/circuitikz/tex/circuitikz-1.4.6.sty
2023/10/10 | 62840 | macros/latex/contrib/l3kernel/l3tl-analysis.dtx
+2023/10/10 | 62818 | install/macros/generic/collargs.tds.zip
2023/10/10 | 626 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@caption__caption_default_error.txt.snap
2023/10/10 | 626 | graphics/pgf/contrib/circuitikz/tex/circuitikz-1.0.sty
2023/10/10 | 6267 | macros/latex/contrib/l3kernel/l3syntax-changes.tex
@@ -221,29 +398,28 @@
2023/10/10 | 6246 | macros/luatex/generic/luatexja/src/ltj-base.sty
2023/10/10 | 6224 | macros/latex/contrib/l3kernel/l3.ins
2023/10/10 | 622212 | macros/latex/contrib/l3kernel/expl3.pdf
+2023/10/10 | 621070 | macros/generic/memoize/doc/memoize-code.pdf
2023/10/10 | 619 | support/texlab/texlab.1
2023/10/10 | 6195 | macros/latex/contrib/l3packages/xparse-2020-10-01.sty
+2023/10/10 | 6184 | macros/generic/memoize/memoize-clean.py
2023/10/10 | 617 | macros/luatex/generic/luatexja/src/patches/lltjp-array.sty
2023/10/10 | 615 | support/texlab/crates/parser/src/test_data/bibtex/samples/erwin_2007.txt
2023/10/10 | 6135 | macros/luatex/generic/luatexja/src/patches/lltjp-tascmac.sty
2023/10/10 | 612 | support/texlab/crates/hover/src/field_type.rs
-2023/10/10 | 61030 | systems/win32/miktex/tm/packages/next/miktex-psutils-bin-x64-2.9.tar.lzma
+2023/10/10 | 611 | support/easydtx/README.md
2023/10/10 | 60 | support/texlab/crates/parser/src/test_data/latex/structure/structure_enum_item.txt
2023/10/10 | 60 | support/texlab/crates/bibtex-utils/src/field.rs
2023/10/10 | 608 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@citation__citation_prenote_postnote.txt.snap
-2023/10/10 | 606755 | systems/win32/miktex/tm/packages/next/miktex-yap-bin-x64-2.9.tar.lzma
2023/10/10 | 6060 | macros/luatex/generic/luatexja/tool/kyoikukanjiChars.tex
2023/10/10 | 60383 | macros/latex/contrib/l3kernel/l3prop.dtx
-2023/10/10 | 601987 | systems/win32/miktex/tm/packages/next/miktex-libressl-bin-x64-2.9.tar.lzma
2023/10/10 | 6018 | support/texlab/crates/texlab/src/util/capabilities.rs
+2023/10/10 | 6004 | support/easydtx/easydoctex-mode.el
2023/10/10 | 59625 | macros/latex/contrib/l3packages/xparse.dtx
2023/10/10 | 594 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_bibtex.snap
2023/10/10 | 594477 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-radiobutton.pdf
2023/10/10 | 5931 | macros/luatex/generic/luatexja/src/ltj-lotf_aux.lua
-2023/10/10 | 59242 | systems/win32/miktex/tm/packages/next/miktex-cjkutils-bin-x64-2.9.tar.lzma
2023/10/10 | 590327 | macros/latex/contrib/pdfmanagement-testphase/ltdocinit.pdf
2023/10/10 | 5900 | support/texlab/crates/base-db/src/util/label.rs
-2023/10/10 | 58943 | systems/win32/miktex/tm/packages/next/miktex-xml2pmx-bin-x64.tar.lzma
2023/10/10 | 588 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@color__color_set_definition_error2.txt.snap
2023/10/10 | 588246 | macros/latex/contrib/pdfmanagement-testphase/l3pdfannot.pdf
2023/10/10 | 5864 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__betram_1996.txt.snap
@@ -257,7 +433,6 @@
2023/10/10 | 580 | macros/luatex/generic/luatexja/tool/blocks2defcharrange.rb
2023/10/10 | 58083 | macros/latex/contrib/l3experimental/xgalley.dtx
2023/10/10 | 577176 | macros/latex/contrib/indextools/indextools.pdf
-2023/10/10 | 5739739 | systems/texlive/tlnet/install-tl-unx.tar.gz
2023/10/10 | 5728981 | systems/win32/miktex/tm/packages/cascadia-code.tar.lzma
2023/10/10 | 57153 | graphics/pgf/contrib/circuitikz/tex/pgfcircmonopoles.tex
2023/10/10 | 5684 | support/texlab/crates/parser/src/build_log.rs
@@ -269,7 +444,6 @@
2023/10/10 | 561 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap
2023/10/10 | 560 | support/texlab/crates/base-db/src/lib.rs
2023/10/10 | 55 | support/texlab/crates/parser/src/test_data/latex/issue_857.txt
-2023/10/10 | 55969 | systems/win32/miktex/tm/packages/next/miktex-mpmcli-bin-x64-2.9.tar.lzma
2023/10/10 | 558 | support/texlab/crates/commands/Cargo.toml
2023/10/10 | 558915 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-action.pdf
2023/10/10 | 557 | support/texlab/crates/parser/src/test_data/bibtex/samples/rivest_1978.txt
@@ -283,14 +457,12 @@
2023/10/10 | 551 | macros/luatex/generic/luatexja/tool/jfm-readable.rb
2023/10/10 | 550 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__begin_environment_without_snippet_support.snap
2023/10/10 | 549 | macros/latex/contrib/l3backend/README.md
-2023/10/10 | 54768 | systems/win32/miktex/tm/packages/next/miktex-synctex-bin-x64-2.9.tar.lzma
2023/10/10 | 544 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple_end.snap
2023/10/10 | 544283 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-choice.pdf
2023/10/10 | 54427 | macros/luatex/generic/luatexja/src/ltj-jisx0208.lua
2023/10/10 | 543188 | macros/luatex/generic/luatexja/doc/luatexja.dtx
2023/10/10 | 5429 | macros/latex/contrib/l3kernel/l3news04.tex
2023/10/10 | 542008 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-checkbox.pdf
-2023/10/10 | 54163 | systems/win32/miktex/tm/packages/next/miktex-dvicopy-bin-x64-2.9.tar.lzma
2023/10/10 | 541082 | graphics/pgf/contrib/circuitikz/doc/circuitikzmanual.tex
2023/10/10 | 5386 | support/texlab/crates/parser/src/latex/lexer/commands.rs
2023/10/10 | 5374 | support/texlab/crates/base-db/src/document.rs
@@ -301,13 +473,11 @@
2023/10/10 | 533 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap
2023/10/10 | 533 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap
2023/10/10 | 532070 | macros/latex/contrib/pdfmanagement-testphase/l3pdftools.pdf
-2023/10/10 | 530466 | systems/win32/miktex/tm/packages/next/miktex-log4cxx-bin-x64-2.9.tar.lzma
2023/10/10 | 5302 | macros/luatex/generic/luatexja/src/addons/luatexja-adjust.sty
2023/10/10 | 52 | support/texlab/crates/parser/src/test_data/latex/include/graphics_include_command.txt
2023/10/10 | 52 | support/texlab/crates/parser/src/test_data/latex/environment/environment_nested_missing_braces.txt
2023/10/10 | 52846 | macros/latex/contrib/l3kernel/CHANGELOG.md
2023/10/10 | 526 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_828.txt.snap
-2023/10/10 | 52695 | systems/win32/miktex/tm/packages/next/miktex-m-tx-bin-x64-2.9.tar.lzma
2023/10/10 | 52600 | graphics/pgf/contrib/circuitikz/doc/changelog.tex
2023/10/10 | 5230 | macros/luatex/generic/luatexja/src/ltj-debug.lua
2023/10/10 | 520 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap
@@ -316,9 +486,11 @@
2023/10/10 | 51 | support/texlab/crates/parser/src/test_data/latex/issue_568.txt
2023/10/10 | 517 | support/texlab/crates/parser/src/test_data/bibtex/samples/matuz_1990.txt
2023/10/10 | 517831 | macros/latex/contrib/l3experimental/l3draw.pdf
+2023/10/10 | 5166 | macros/generic/memoize/doc/memoize-doc-common.sty
2023/10/10 | 516622 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-textfield.pdf
2023/10/10 | 515 | support/texlab/crates/base-db/Cargo.toml
2023/10/10 | 515760 | macros/latex/contrib/pdfmanagement-testphase/l3pdfdict.pdf
+2023/10/10 | 5138 | macros/generic/memoize/memoize-clean.pl
2023/10/10 | 512 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_857_1.snap
2023/10/10 | 51081 | macros/latex/contrib/l3kernel/l3fp-extended.dtx
2023/10/10 | 50 | support/texlab/crates/parser/src/test_data/latex/environment/environment_asymptote.txt
@@ -334,31 +506,23 @@
2023/10/10 | 4 | support/texlab/crates/parser/src/test_data/latex/group/unmatched_brackets_with_group.txt
2023/10/10 | 4 | support/texlab/crates/parser/src/test_data/latex/generic_command_empty.txt
2023/10/10 | 499 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@caption__caption_minimal_error.txt.snap
-2023/10/10 | 499564 | systems/win32/miktex/tm/packages/next/miktex-ptex-bin-x64.tar.lzma
2023/10/10 | 4977 | macros/latex/contrib/l3kernel/l3news07.tex
-2023/10/10 | 49712 | systems/win32/miktex/tm/packages/next/miktex-expat-bin-x64-2.9.tar.lzma
2023/10/10 | 49600 | macros/latex/contrib/l3kernel/l3text.dtx
2023/10/10 | 494 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple.snap
2023/10/10 | 4937 | macros/latex/contrib/l3kernel/l3news01.tex
2023/10/10 | 49311 | macros/latex/contrib/l3kernel/l3fp-expo.dtx
2023/10/10 | 492 | support/texlab/crates/bibtex-utils/Cargo.toml
2023/10/10 | 4922 | macros/latex/contrib/l3backend/l3backend.ins
-2023/10/10 | 48 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
2023/10/10 | 48 | support/texlab/crates/parser/src/test_data/latex/block_comments.txt
2023/10/10 | 489 | support/texlab/crates/citeproc/Cargo.toml
2023/10/10 | 48961 | macros/luatex/generic/luatexja/src/ltj-jfont.lua
2023/10/10 | 4890 | macros/latex/contrib/l3kernel/l3news.tex
-2023/10/10 | 488 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
-2023/10/10 | 488 | systems/texlive/tlnet/install-tl.zip.sha512.asc
-2023/10/10 | 488 | systems/texlive/tlnet/install-tl-windows.exe.sha512.asc
-2023/10/10 | 488 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512.asc
2023/10/10 | 486 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_closed.snap
2023/10/10 | 485 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_open.snap
2023/10/10 | 485 | support/texlab/crates/syntax/src/lib.rs
2023/10/10 | 483 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__package_include_multiple.txt.snap
2023/10/10 | 483 | support/texlab/crates/hover/Cargo.toml
2023/10/10 | 482959 | macros/latex/contrib/l3packages/xfrac.pdf
-2023/10/10 | 48189 | systems/win32/miktex/tm/packages/next/miktex-mtprint-bin-x64-2.9.tar.lzma
2023/10/10 | 4808 | macros/luatex/generic/luatexja/src/jfm-tmin.lua
2023/10/10 | 47 | support/texlab/crates/texlab/tests/lsp/main.rs
2023/10/10 | 47 | support/texlab/crates/parser/src/test_data/latex/label/label_reference_incomplete.txt
@@ -367,9 +531,7 @@
2023/10/10 | 477 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__latex_input_path_brackets.txt.snap
2023/10/10 | 4761 | macros/latex/contrib/pdfmanagement-testphase/pdfmanagement-testphase.ins
2023/10/10 | 4755 | support/texlab/crates/completion/src/providers/include.rs
-2023/10/10 | 47432 | systems/win32/miktex/tm/packages/next/miktex-dvipng-bin-x64-2.9.tar.lzma
2023/10/10 | 4730 | support/texlab/crates/citeproc/src/entry.rs
-2023/10/10 | 473015 | systems/win32/miktex/tm/packages/next/miktex-doc.tar.lzma
2023/10/10 | 472 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@citation__citation_prenote.txt.snap
2023/10/10 | 47274 | macros/latex/contrib/l3kernel/l3prefixes.csv
2023/10/10 | 47216 | macros/latex/contrib/l3kernel/l3fp-aux.dtx
@@ -379,18 +541,20 @@
2023/10/10 | 464 | support/texlab/crates/parser/src/snapshots/parser__build_log__tests__parse@007.txt.snap
2023/10/10 | 463827 | macros/latex/contrib/pdfmanagement-testphase/pdfmanagement-testphase.pdf
2023/10/10 | 460 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@generic_command_args.txt.snap
+2023/10/10 | 46048 | macros/generic/advice/advice.edtx
2023/10/10 | 460413 | macros/luatex/generic/luatexja/doc/ltjsclasses.pdf
2023/10/10 | 459 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_closed_brace.snap
2023/10/10 | 459 | support/texlab/crates/symbols/Cargo.toml
-2023/10/10 | 45935 | systems/win32/miktex/tm/packages/next/miktex-zlib-bin-x64-2.9.tar.lzma
2023/10/10 | 457 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@color__color_set_definition_error3.txt.snap
2023/10/10 | 4574 | macros/latex/contrib/l3kernel/l3legacy.dtx
2023/10/10 | 456 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@label__label_reference_multiple.txt.snap
2023/10/10 | 453 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@citation__citation_multiple_keys.txt.snap
+2023/10/10 | 453473 | macros/generic/memoize/doc/memoize.tex
2023/10/10 | 452 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_closed_brace.snap
2023/10/10 | 452 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@label__label_definition_line_break.txt.snap
2023/10/10 | 4521 | macros/luatex/generic/luatexja/src/ltj-stack.lua
2023/10/10 | 451 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_open_brace.snap
+2023/10/10 | 4514 | macros/generic/memoize/Makefile
2023/10/10 | 450604 | macros/latex/contrib/l3packages/xtemplate.pdf
2023/10/10 | 44 | support/texlab/crates/parser/src/test_data/latex/include/class_include_options.txt
2023/10/10 | 44 | support/texlab/crates/parser/src/test_data/latex/glossary/acronym_definition_simple.txt
@@ -405,21 +569,17 @@
2023/10/10 | 4457163 | install/macros/latex/contrib/l3experimental.tds.zip
2023/10/10 | 4452 | macros/luatex/generic/luatexja/doc/jfm-ujisc33.lua
2023/10/10 | 4448 | macros/latex/contrib/l3experimental/l3draw-state.dtx
-2023/10/10 | 44372 | systems/win32/miktex/tm/packages/next/miktex-gsf2pk-bin-x64-2.9.tar.lzma
2023/10/10 | 4432 | support/texlab/crates/test-utils/src/fixture.rs
2023/10/10 | 441 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_field_name.snap
2023/10/10 | 4419131 | macros/latex/contrib/l3experimental.zip
2023/10/10 | 44178 | support/texlab/crates/completion/src/tests.rs
-2023/10/10 | 44091 | systems/win32/miktex/tm/packages/next/miktex-upmendex-bin-x64.tar.lzma
-2023/10/10 | 44073 | systems/win32/miktex/tm/packages/next/miktex-mthelp-bin-x64-2.9.tar.lzma
2023/10/10 | 440395 | macros/latex/contrib/pdfmanagement-testphase/pdfmanagement-firstaid.pdf
2023/10/10 | 43 | support/texlab/crates/parser/src/test_data/latex/environment/environment_nested.txt
+2023/10/10 | 435 | macros/generic/collargs/README.md
2023/10/10 | 4323 | macros/latex/contrib/l3experimental/l3draw-boxes.dtx
2023/10/10 | 43223 | macros/latex/contrib/l3kernel/l3debug.dtx
-2023/10/10 | 43114 | systems/win32/miktex/tm/packages/next/miktex-patgen-bin-x64.tar.lzma
2023/10/10 | 4308 | macros/luatex/generic/luatexja/src/patches/lltjp-atbegshi.sty
2023/10/10 | 4300 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_745.txt.snap
-2023/10/10 | 430052 | systems/texlive/tlnet/archive/texlive-scripts.doc.r68489.tar.xz
2023/10/10 | 42 | support/texlab/crates/parser/src/test_data/latex/include/biblatex_include_options.txt
2023/10/10 | 429 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__latex_include_equality_sign.txt.snap
2023/10/10 | 4297 | support/texlab/crates/completion/src/providers/environment.rs
@@ -448,7 +608,6 @@
2023/10/10 | 4126 | support/texlab/crates/texlab/src/features/symbols.rs
2023/10/10 | 4126 | macros/luatex/generic/luatexja/src/patches/lltjp-siunitx.sty
2023/10/10 | 412557 | macros/latex/contrib/l3packages/l3keys2e.pdf
-2023/10/10 | 4115543 | biblio/ctan-bibdata.zip
2023/10/10 | 41088 | systems/win32/miktex/tm/packages/proflycee.tar.lzma
2023/10/10 | 408 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_simple.snap
2023/10/10 | 408917 | macros/latex/contrib/l3experimental/l3galley.pdf
@@ -467,11 +626,11 @@
2023/10/10 | 4047 | support/texlab/crates/texlab/src/util/chktex.rs
2023/10/10 | 404408 | macros/latex/contrib/l3experimental/l3bitset.pdf
2023/10/10 | 4041 | macros/latex/contrib/pdfmanagement-testphase/l3ref-tmp.sty
-2023/10/10 | 40401 | systems/win32/miktex/tm/packages/next/miktex-chktex-bin-x64-2.9.tar.lzma
2023/10/10 | 403 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_open_brace.snap
2023/10/10 | 4038 | support/texlab/crates/base-db/src/config.rs
2023/10/10 | 403681 | macros/luatex/generic/luatexja/doc/ltjclasses.pdf
2023/10/10 | 403567 | graphics/pgf/contrib/circuitikz/tex/circuitikz-0.7-body.tex
+2023/10/10 | 401 | macros/generic/advice/README.md
2023/10/10 | 4011 | macros/latex/contrib/l3experimental/l3opacity.dtx
2023/10/10 | 4004 | support/texlab/crates/texlab/src/util/lsp_enums.rs
2023/10/10 | 39 | support/texlab/crates/parser/src/test_data/latex/include/graphics_include_options.txt
@@ -481,7 +640,6 @@
2023/10/10 | 39 | support/texlab/crates/parser/src/test_data/latex/caption/caption_figure.txt
2023/10/10 | 399 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_empty.snap
2023/10/10 | 396222 | macros/latex/contrib/l3kernel/l3news.pdf
-2023/10/10 | 395454 | systems/win32/miktex/tm/packages/next/miktex-cairo-bin-x64-2.9.tar.lzma
2023/10/10 | 394 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap
2023/10/10 | 394 | support/texlab/crates/diagnostics/Cargo.toml
2023/10/10 | 394481 | macros/latex/contrib/l3experimental/xcoffins.pdf
@@ -519,18 +677,15 @@
2023/10/10 | 376 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__bibtex_include_simple.txt.snap
2023/10/10 | 376 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@command_definition__math_operator_no_impl.txt.snap
2023/10/10 | 376737 | systems/win32/miktex/tm/packages/japanese-otf.tar.lzma
-2023/10/10 | 37646 | systems/win32/miktex/tm/packages/next/miktex-posix-bin-x64-2.9.tar.lzma
2023/10/10 | 375 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__class_include_simple.txt.snap
2023/10/10 | 3756 | macros/luatex/generic/luatexja/src/ltj-compat.lua
2023/10/10 | 373 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__inkscape_include_simple.txt.snap
2023/10/10 | 373 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@preamble.txt.snap
+2023/10/10 | 37322 | install/macros/generic/advice.tds.zip
2023/10/10 | 372 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__svg_include_simple.txt.snap
2023/10/10 | 372 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@glossary__acronym_reference_simple.txt.snap
-2023/10/10 | 3712530 | biblio/ctan-bibdata/ctan.pdf
2023/10/10 | 368 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_import.snap
-2023/10/10 | 36805 | systems/win32/miktex/tm/packages/next/miktex-axohelp-bin-x64-2.9.tar.lzma
2023/10/10 | 368030 | macros/latex/contrib/l3experimental/l3str-format.pdf
-2023/10/10 | 36744 | systems/win32/miktex/tm/packages/next/miktex-arctrl-bin-x64-2.9.tar.lzma
2023/10/10 | 3667 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__aho_2006.txt.snap
2023/10/10 | 365 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@glossary__glossary_entry_reference_simple.txt.snap
2023/10/10 | 3650 | macros/luatex/generic/luatexja/src/ltj-inputbuf.lua
@@ -551,13 +706,13 @@
2023/10/10 | 355 | support/texlab/crates/folding/Cargo.toml
2023/10/10 | 355 | macros/luatex/generic/luatexja/tool/otf-AdobeMingStd-Light.txt
2023/10/10 | 355 | macros/luatex/generic/luatexja/doc/luatexja.ins
+2023/10/10 | 355 | macros/generic/etoolbox-generic/README.md
2023/10/10 | 35441 | macros/latex/contrib/l3kernel/l3quark.dtx
2023/10/10 | 353 | support/texlab/crates/rename/Cargo.toml
-2023/10/10 | 35357 | systems/win32/miktex/tm/packages/next/miktex-mspack-bin-x64-2.9.tar.lzma
2023/10/10 | 35324 | support/texlab/crates/parser/src/latex.rs
2023/10/10 | 351 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_environment.snap
-2023/10/10 | 351802 | systems/win32/miktex/tm/packages/next/miktex-xetex-bin-x64-2.9.tar.lzma
2023/10/10 | 35149 | support/texlab/LICENSE
+2023/10/10 | 35149 | support/easydtx/LICENCE
2023/10/10 | 35092 | macros/latex/contrib/l3experimental/xcoffins.dtx
2023/10/10 | 3501 | support/texlab/crates/completion/src/providers/label.rs
2023/10/10 | 34 | support/texlab/crates/parser/src/test_data/latex/include/svg_include_options.txt
@@ -574,14 +729,11 @@
2023/10/10 | 33 | support/texlab/crates/parser/src/test_data/latex/graphics_path_options.txt
2023/10/10 | 33 | support/texlab/crates/parser/src/test_data/latex/environment/environment_simple.txt
2023/10/10 | 33 | support/texlab/crates/parser/src/test_data/latex/color/color_definition_simple.txt
-2023/10/10 | 33875 | systems/win32/miktex/tm/packages/next/miktex-uriparser-bin-x64-2.9.tar.lzma
-2023/10/10 | 33858 | systems/win32/miktex/tm/packages/next/miktex-makeindex-bin-x64-2.9.tar.lzma
2023/10/10 | 33773 | macros/latex/contrib/l3kernel/l3cctab.dtx
2023/10/10 | 3371 | macros/luatex/generic/luatexja/src/patches/lltjp-xunicode.sty
2023/10/10 | 336 | support/texlab/crates/references/Cargo.toml
-2023/10/10 | 334871 | systems/win32/miktex/tm/packages/next/miktex-zzdb1-2.9.tar.lzma
-2023/10/10 | 334799 | systems/win32/miktex/tm/packages/miktex-zzdb1-2.9.tar.lzma
2023/10/10 | 33461 | macros/luatex/generic/luatexja/src/addons/luatexja-ajmacros.sty
+2023/10/10 | 3340 | macros/generic/memoize/doc/memoize-extract.1.md
2023/10/10 | 332 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@group__curly_group_simple.txt.snap
2023/10/10 | 332260 | macros/latex/contrib/l3packages/xfp.pdf
2023/10/10 | 3317797 | install/graphics/pgf/contrib/circuitikz.tds.zip
@@ -591,10 +743,8 @@
2023/10/10 | 3301 | support/texlab/crates/completion/src/providers/tikz_library.rs
2023/10/10 | 32 | support/texlab/crates/parser/src/test_data/latex/graphics_path_command.txt
2023/10/10 | 32 | support/texlab/crates/parser/src/test_data/latex/glossary/acronym_reference_options.txt
-2023/10/10 | 329887 | systems/win32/miktex/tm/packages/next/miktex-dvipdfmx-bin-x64-2.9.tar.lzma
2023/10/10 | 32988465 | fonts/haranoaji.zip
2023/10/10 | 3296870 | graphics/pgf/contrib/circuitikz.zip
-2023/10/10 | 32890 | systems/win32/miktex/tm/packages/next/miktex-lacheck-bin-x64-2.9.tar.lzma
2023/10/10 | 3288 | support/texlab/crates/diagnostics/src/tests.rs
2023/10/10 | 32826 | graphics/pgf/contrib/circuitikz/tex/pgfcircshapes.tex
2023/10/10 | 326 | macros/luatex/generic/luatexja/tool/otf-AdobeMyungjoStd-Medium.txt
@@ -611,7 +761,6 @@
2023/10/10 | 321 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@citation__citation_missing_brace.txt.snap
2023/10/10 | 3218 | support/texlab/crates/diagnostics/src/grammar/bib.rs
2023/10/10 | 3207 | support/texlab/crates/commands/src/fwd_search.rs
-2023/10/10 | 32065 | systems/win32/miktex/tm/packages/next/miktex-autosp-bin-x64-2.9.tar.lzma
2023/10/10 | 32021 | support/texlab/CHANGELOG.md
2023/10/10 | 31 | support/texlab/crates/parser/src/test_data/latex/theorem_definition/theorem_definition_full.txt
2023/10/10 | 31 | support/texlab/crates/parser/src/test_data/latex/issue_931.txt
@@ -621,8 +770,9 @@
2023/10/10 | 3193 | fonts/haranoaji-extra/README
2023/10/10 | 31827 | macros/latex/contrib/l3experimental/l3str-format.dtx
2023/10/10 | 317 | macros/luatex/generic/luatexja/tool/otf-AdobeSongStd-Light.txt
+2023/10/10 | 3175 | macros/generic/etoolbox-generic/etoolbox-generic.tex
2023/10/10 | 316 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__import_incomplete.txt.snap
-2023/10/10 | 31563 | systems/win32/miktex/tm/packages/next/miktex-bzip2-bin-x64-2.9.tar.lzma
+2023/10/10 | 3158 | macros/generic/memoize/doc/memoize-code.tex
2023/10/10 | 3150 | graphics/pgf/contrib/circuitikz/tex/ctikzstyle-legacy.tex
2023/10/10 | 314 | support/texlab/crates/parser/src/test_data/bibtex/samples/aho_2006.txt
2023/10/10 | 314253 | systems/win32/miktex/tm/packages/setspaceenhanced__doc.tar.lzma
@@ -631,6 +781,8 @@
2023/10/10 | 313597 | macros/latex/contrib/l3experimental/l3opacity.pdf
2023/10/10 | 312 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@group__curly_group_missing_end.txt.snap
2023/10/10 | 31145 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-radiobutton.dtx
+2023/10/10 | 31104 | macros/generic/memoize/doc/examples-src.zip
+2023/10/10 | 31068 | macros/generic/memoize/doc/examples.zip
2023/10/10 | 3100 | macros/luatex/generic/luatexja/tool/table_jisx0208.tex
2023/10/10 | 30 | support/texlab/crates/parser/src/test_data/latex/include/inkscape_include_options.txt
2023/10/10 | 30 | support/texlab/crates/parser/src/test_data/latex/color/color_set_definition_error2.txt
@@ -640,7 +792,6 @@
2023/10/10 | 3058 | macros/latex/contrib/l3kernel/README.md
2023/10/10 | 3057 | support/texlab/crates/parser/src/test_data/build_log/004.txt
2023/10/10 | 305576 | macros/latex/contrib/l3kernel/l3regex.dtx
-2023/10/10 | 305432 | systems/win32/miktex/tm/packages/next/miktex-freetype2-bin-x64-2.9.tar.lzma
2023/10/10 | 30508 | macros/latex/contrib/l3kernel/l3intarray.dtx
2023/10/10 | 3027 | support/texlab/crates/diagnostics/src/citations.rs
2023/10/10 | 3021 | support/texlab/crates/diagnostics/src/labels.rs
@@ -664,22 +815,19 @@
2023/10/10 | 29569 | macros/latex/contrib/l3backend/l3backend-graphics.dtx
2023/10/10 | 2952 | systems/texlive/tlnet/archive/tikz-osci.r68491.tar.xz
2023/10/10 | 291 | support/texlab/crates/test-utils/Cargo.toml
-2023/10/10 | 291611 | systems/win32/miktex/tm/packages/next/miktex-mo-bin-x64-2.9.tar.lzma
-2023/10/10 | 29108 | systems/win32/miktex/tm/packages/next/miktex-findtexmf-bin-x64-2.9.tar.lzma
2023/10/10 | 28 | support/texlab/crates/parser/src/test_data/latex/include/package_include_multiple.txt
2023/10/10 | 28 | support/texlab/crates/parser/src/test_data/latex/include/biblatex_include_simple.txt
2023/10/10 | 28 | support/texlab/crates/parser/src/test_data/latex/group/equation_missing_end.txt
2023/10/10 | 28 | support/texlab/crates/parser/src/test_data/latex/graphics_path.txt
2023/10/10 | 28 | support/texlab/crates/parser/src/test_data/latex/equation_missing_begin.txt
2023/10/10 | 2882 | macros/latex/contrib/pdfmanagement-testphase/colorspace-patches-tmp-ltx.sty
-2023/10/10 | 287579 | systems/win32/miktex/tm/packages/next/miktex-metapost-bin-x64-2.9.tar.lzma
2023/10/10 | 28627 | macros/latex/contrib/pdfmanagement-testphase/l3pdfannot.dtx
-2023/10/10 | 2844479 | systems/win32/miktex/tm/packages/next/miktex-texworks-bin-x64-2.9.tar.lzma
2023/10/10 | 2843 | macros/latex/contrib/pdfmanagement-testphase/xcolor-patches-tmp-ltx.sty
+2023/10/10 | 2836 | support/easydtx/edtx2dtx.pl
2023/10/10 | 2834 | support/texlab/crates/parser/src/latex/lexer/types.rs
2023/10/10 | 2821 | macros/latex/contrib/l3kernel/l3prefixes.tex
-2023/10/10 | 2815719 | biblio/ctan-bibdata/ctan.bib
2023/10/10 | 280 | graphics/pgf/contrib/circuitikz/tex/ctikzstyle-example.tex
+2023/10/10 | 2801056 | install/macros/generic/memoize.tds.zip
2023/10/10 | 27 | support/texlab/crates/parser/src/test_data/latex/structure/structure_invalid_nesting.txt
2023/10/10 | 27 | support/texlab/crates/parser/src/test_data/latex/include/verbatim_include_simple.txt
2023/10/10 | 27 | support/texlab/crates/parser/src/test_data/latex/caption/caption_default.txt
@@ -690,9 +838,7 @@
2023/10/10 | 278116 | systems/win32/miktex/tm/packages/autosp__doc.tar.lzma
2023/10/10 | 273 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_command.snap
2023/10/10 | 27270 | macros/latex/contrib/l3kernel/l3kernel-functions.dtx
-2023/10/10 | 272188 | systems/win32/miktex/tm/packages/next/miktex-console-bin-x64-2.9.tar.lzma
2023/10/10 | 271 | support/texlab/crates/parser/src/test_data/latex/issue_745.txt
-2023/10/10 | 27112 | systems/win32/miktex/tm/packages/next/miktex-teckit-bin-x64-2.9.tar.lzma
2023/10/10 | 27058 | macros/luatex/generic/luatexja/src/lltjext.sty
2023/10/10 | 26 | support/texlab/crates/parser/src/test_data/latex/theorem_definition/theorem_definition_name_with_description_and_counter.txt
2023/10/10 | 26 | support/texlab/crates/parser/src/test_data/latex/command_definition/math_operator_no_impl.txt
@@ -707,7 +853,6 @@
2023/10/10 | 2612 | support/texlab/crates/completion/src/providers/glossary.rs
2023/10/10 | 2610 | support/texlab/crates/symbols/src/types.rs
2023/10/10 | 2609 | support/texlab/crates/texlab/src/server/extensions.rs
-2023/10/10 | 26029113 | systems/texlive/tlnet/install-tl.zip
2023/10/10 | 25 | support/texlab/crates/parser/src/test_data/latex/glossary/glossary_entry_reference_options.txt
2023/10/10 | 25 | support/texlab/crates/parser/src/test_data/latex/color/color_set_definition_error3.txt
2023/10/10 | 25 | support/texlab/crates/parser/src/test_data/bibtex/preamble.txt
@@ -718,8 +863,6 @@
2023/10/10 | 2582 | macros/luatex/generic/luatexja/src/jfm-kaiming.lua
2023/10/10 | 257 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_class.snap
2023/10/10 | 2573 | macros/luatex/generic/luatexja/src/jfm-quanjiao.lua
-2023/10/10 | 25629 | systems/win32/miktex/tm/packages/next/miktex-devnag-bin-x64-2.9.tar.lzma
-2023/10/10 | 25601 | systems/win32/miktex/tm/packages/next/miktex-fribidixetex-bin-x64-2.9.tar.lzma
2023/10/10 | 255 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_end.snap
2023/10/10 | 254696 | systems/texlive/tlnet/archive/japanese-otf.r68492.tar.xz
2023/10/10 | 2543 | support/texlab/crates/distro/src/lib.rs
@@ -730,20 +873,16 @@
2023/10/10 | 25001 | macros/latex/contrib/l3kernel/source3body.tex
2023/10/10 | 24 | support/texlab/crates/parser/src/test_data/latex/include/svg_include_simple.txt
2023/10/10 | 2493 | support/texlab/crates/completion/src/providers/argument.rs
-2023/10/10 | 249317 | systems/win32/miktex/tm/packages/next/miktex-hitex-bin-x64.tar.lzma
2023/10/10 | 248 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@color__color_set_definition_error4.txt.snap
2023/10/10 | 2481 | support/texlab/crates/completion/src/providers/import.rs
-2023/10/10 | 2481360 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
2023/10/10 | 247 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_883.snap
2023/10/10 | 2467 | support/texlab/crates/distro/src/miktex.rs
-2023/10/10 | 245850 | systems/win32/miktex/tm/packages/next/miktex-pmx-bin-x64-2.9.tar.lzma
2023/10/10 | 2455 | support/texlab/crates/parser/src/test_data/build_log/002.txt
2023/10/10 | 244 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@group__unmatched_brackets.txt.snap
2023/10/10 | 244 | support/texlab/crates/base-db/src/util.rs
2023/10/10 | 242 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@hello_world.txt.snap
2023/10/10 | 242 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@group__unmatched_braces.txt.snap
2023/10/10 | 242906 | macros/latex/contrib/l3kernel/l3syntax-changes.pdf
-2023/10/10 | 24126 | systems/win32/miktex/tm/packages/next/miktex-popt-bin-x64-2.9.tar.lzma
2023/10/10 | 2411 | support/texlab/crates/texlab/src/server/dispatch.rs
2023/10/10 | 23 | support/texlab/crates/parser/src/test_data/latex/include/class_include_simple.txt
2023/10/10 | 23 | support/texlab/crates/parser/src/test_data/latex/command_definition/command_definition_simple.txt
@@ -758,7 +897,6 @@
2023/10/10 | 2322 | support/texlab/crates/diagnostics/src/lib.rs
2023/10/10 | 232120 | systems/texlive/tlnet/archive/tikz-osci.doc.r68491.tar.xz
2023/10/10 | 2320 | support/texlab/crates/completion/src/util/patterns.rs
-2023/10/10 | 232070 | systems/win32/miktex/tm/packages/next/miktex-metafont-bin-x64-2.9.tar.lzma
2023/10/10 | 23009 | macros/latex/contrib/l3kernel/l3fp-logic.dtx
2023/10/10 | 22 | support/texlab/crates/parser/src/test_data/latex/include/bibtex_include_simple.txt
2023/10/10 | 22 | support/texlab/crates/parser/src/test_data/latex/command_definition/command_definition_no_argc.txt
@@ -773,8 +911,8 @@
2023/10/10 | 2257270 | install/macros/latex/contrib/l3packages.tds.zip
2023/10/10 | 223 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple.snap
2023/10/10 | 2238289 | macros/latex/contrib/l3packages.zip
+2023/10/10 | 2236 | macros/generic/advice/INSTALL.md
2023/10/10 | 22204 | support/texlab/crates/citeproc/src/driver.rs
-2023/10/10 | 221451 | systems/win32/miktex/tm/packages/next/miktex-curl-bin-x64-2.9.tar.lzma
2023/10/10 | 22125 | macros/luatex/generic/luatexja/src/ltj-adjust.lua
2023/10/10 | 2203 | macros/luatex/generic/luatexja/src/jfm-CCT.lua
2023/10/10 | 21 | support/texlab/crates/parser/src/test_data/latex/theorem_definition/theorem_definition_name_with_description.txt
@@ -785,17 +923,17 @@
2023/10/10 | 21991 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-textfield.dtx
2023/10/10 | 2193 | macros/luatex/generic/luatexja/src/addons/luatexja-zhfonts.sty
2023/10/10 | 2188 | graphics/pgf/contrib/circuitikz/tex/ctikzstyle-romano.tex
-2023/10/10 | 218853 | systems/win32/miktex/tm/packages/next/miktex-omegaware-bin-x64-2.9.tar.lzma
2023/10/10 | 218060 | macros/latex/contrib/l3kernel/l3term-glossary.pdf
2023/10/10 | 217 | support/texlab/crates/parser/src/test_data/latex/issue_919.txt
-2023/10/10 | 217246 | systems/win32/miktex/tm/packages/next/miktex-hunspell-bin-x64-2.9.tar.lzma
2023/10/10 | 216 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@generic_command_empty.txt.snap
+2023/10/10 | 2164795 | macros/generic/memoize/doc/memoize.pdf
2023/10/10 | 215 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@generic_command_escape.txt.snap
+2023/10/10 | 21569 | macros/generic/memoize/doc/memoize-doc.sty
2023/10/10 | 2135265 | systems/win32/miktex/tm/packages/musixtex__doc.tar.lzma
+2023/10/10 | 2131 | macros/generic/collargs/INSTALL.md
2023/10/10 | 211 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_word.snap
2023/10/10 | 2107 | support/texlab/crates/completion/src/providers/color.rs
2023/10/10 | 2104 | systems/win32/miktex/tm/packages/setspaceenhanced.tar.lzma
-2023/10/10 | 21037851 | systems/texlive/tlnet/install-tl-windows.exe
2023/10/10 | 20 | support/texlab/crates/parser/src/test_data/latex/label/label_reference_range_simple.txt
2023/10/10 | 20 | support/texlab/crates/parser/src/test_data/latex/include/tikz_library_import_simple.txt
2023/10/10 | 20 | support/texlab/crates/parser/src/test_data/latex/include/package_include_simple.txt
@@ -814,7 +952,6 @@
2023/10/10 | 20430 | macros/latex/contrib/pdfmanagement-testphase/l3pdffield-choice.dtx
2023/10/10 | 2042040 | systems/texlive/tlnet/archive/culmus.source.r68495.tar.xz
2023/10/10 | 2040 | support/texlab/crates/parser/src/latex/lexer.rs
-2023/10/10 | 203009 | systems/win32/miktex/tm/packages/next/miktex-pixman-bin-x64-2.9.tar.lzma
2023/10/10 | 200 | macros/luatex/generic/luatexja/src/jfm-prop.lua
2023/10/10 | 1 | support/texlab/crates/parser/src/test_data/latex/parameter_error.txt
2023/10/10 | 19 | support/texlab/crates/parser/src/test_data/latex/label/label_reference_range_error.txt
@@ -823,18 +960,13 @@
2023/10/10 | 19 | support/texlab/crates/parser/src/test_data/latex/inline.txt
2023/10/10 | 19 | support/texlab/crates/parser/src/test_data/latex/include/pgf_library_import_simple.txt
2023/10/10 | 19 | support/texlab/crates/parser/src/test_data/latex/glossary/acronym_reference_simple.txt
-2023/10/10 | 19994 | systems/win32/miktex/tm/packages/next/miktex-kpathsea-bin-x64-2.9.tar.lzma
-2023/10/10 | 19967 | systems/win32/miktex/tm/packages/next/miktex-tex2xindy-bin-x64-2.9.tar.lzma
-2023/10/10 | 1993837 | systems/win32/miktex/tm/packages/next/miktex-luatex-bin-x64-2.9.tar.lzma
2023/10/10 | 197 | support/texlab/crates/texlab/src/features.rs
2023/10/10 | 1974 | support/texlab/crates/symbols/src/document/bib.rs
2023/10/10 | 1973 | macros/luatex/generic/luatexja/src/luatexja.sty
2023/10/10 | 196 | macros/luatex/generic/luatexja/src/jfm-propw.lua
2023/10/10 | 196 | macros/luatex/generic/luatexja/src/jfm-propv.lua
2023/10/10 | 19641 | macros/latex/contrib/l3kernel/l3fp-convert.dtx
-2023/10/10 | 1952183 | systems/win32/miktex/tm/packages/miktex-zzdb2-2.9.tar.lzma
2023/10/10 | 194 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_preamble.snap
-2023/10/10 | 1949822 | systems/win32/miktex/tm/packages/next/miktex-zzdb2-2.9.tar.lzma
2023/10/10 | 19342 | macros/latex/contrib/pdfmanagement-testphase/pdfmanagement-testphase.dtx
2023/10/10 | 192 | macros/luatex/generic/luatexja/src/jfm-mono.lua
2023/10/10 | 1926 | support/texlab/crates/texlab/Cargo.toml
@@ -842,11 +974,16 @@
2023/10/10 | 1922 | support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__smoke.snap
2023/10/10 | 1917 | support/texlab/crates/distro/src/file_name_db.rs
2023/10/10 | 191160 | graphics/pgf/contrib/tkz-bernoulli.zip
+2023/10/10 | 19102 | macros/generic/memoize/LICENCE
+2023/10/10 | 19102 | macros/generic/etoolbox-generic/LICENCE
+2023/10/10 | 19102 | macros/generic/collargs/LICENCE
+2023/10/10 | 19102 | macros/generic/advice/LICENCE
2023/10/10 | 19089 | macros/latex/contrib/non-decimal-units/latex/non-decimal-units.sty
2023/10/10 | 1906 | macros/latex/contrib/l3experimental/l3draw.ins
2023/10/10 | 189 | macros/luatex/generic/luatexja/src/patches/lltjp-preview.sty
2023/10/10 | 1896 | systems/texlive/tlnet/archive/setspaceenhanced.r68493.tar.xz
2023/10/10 | 189539 | macros/luatex/generic/luatexja/src/ltjsclasses.dtx
+2023/10/10 | 18898 | install/support/easydtx.tds.zip
2023/10/10 | 188693 | graphics/pgf/contrib/tkz-bernoulli/doc/tkz-bernoulli-doc.pdf
2023/10/10 | 1883 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@structure__paragraphs.txt.snap
2023/10/10 | 187 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@parameter_error.txt.snap
@@ -859,8 +996,6 @@
2023/10/10 | 18301 | macros/latex/contrib/non-decimal-units/docs/non-decimal-units.tex
2023/10/10 | 182 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_article.snap
2023/10/10 | 182 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@parameter.txt.snap
-2023/10/10 | 18284219 | systems/texlive/tlnet/tlpkg/texlive.tlpdb
-2023/10/10 | 182738 | systems/win32/miktex/tm/packages/next/miktex-mpfr-bin-x64-2.9.tar.lzma
2023/10/10 | 1820 | support/texlab/crates/commands/src/clean.rs
2023/10/10 | 181 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_join_strings.snap
2023/10/10 | 181 | support/texlab/CONTRIBUTING.md
@@ -882,7 +1017,6 @@
2023/10/10 | 175 | support/texlab/crates/symbols/src/lib.rs
2023/10/10 | 1749 | support/texlab/crates/folding/src/tests.rs
2023/10/10 | 1745 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@structure__structure_nested.txt.snap
-2023/10/10 | 174204 | systems/win32/miktex/tm/packages/next/miktex-tex-bin-x64-2.9.tar.lzma
2023/10/10 | 1740 | macros/luatex/generic/luatexja/tool/test_exist_nodelib.tex
2023/10/10 | 1737 | support/texlab/crates/texlab/tests/lsp/text_document/inlay_hint.rs
2023/10/10 | 17330 | macros/latex/contrib/pdfmanagement-testphase/l3pdfdict.dtx
@@ -895,12 +1029,10 @@
2023/10/10 | 16 | support/texlab/crates/parser/src/test_data/latex/include/class_include_empty.txt
2023/10/10 | 16 | support/texlab/crates/parser/src/test_data/latex/command_definition/command_definition_no_impl_error.txt
2023/10/10 | 1695110 | graphics/pgf/contrib/circuitikz/doc/circuitikzmanual.pdf
-2023/10/10 | 1684918 | systems/win32/miktex/tm/packages/next/miktex-zzdb3-2.9.tar.lzma
-2023/10/10 | 1684896 | systems/win32/miktex/tm/packages/miktex-zzdb3-2.9.tar.lzma
2023/10/10 | 167 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_command.snap
-2023/10/10 | 1678 | biblio/ctan-bibdata/biblatex-ctan/ctan.bbx
2023/10/10 | 1672 | support/texlab/crates/parser/src/snapshots/parser__build_log__tests__parse@006.txt.snap
2023/10/10 | 16722 | graphics/pgf/contrib/circuitikz/tex/pgfcircpath.tex
+2023/10/10 | 1668 | macros/generic/memoize/memoize.ins
2023/10/10 | 166557 | macros/luatex/generic/luatexja/doc/lltjp-geometry.pdf
2023/10/10 | 16639 | macros/latex/contrib/l3kernel/l3candidates.dtx
2023/10/10 | 16631 | macros/latex/contrib/l3kernel/l3text-map.dtx
@@ -909,6 +1041,9 @@
2023/10/10 | 1637 | macros/luatex/generic/luatexja/src/addons/luatexja-fontspec.sty
2023/10/10 | 163484 | macros/latex/contrib/l3kernel/l3news08.pdf
2023/10/10 | 163409 | macros/latex/contrib/non-decimal-units.zip
+2023/10/10 | 1630 | macros/generic/memoize/doc/memoize-clean.1.md
+2023/10/10 | 162 | macros/generic/collargs/Makefile
+2023/10/10 | 162 | macros/generic/advice/Makefile
2023/10/10 | 1626 | support/texlab/crates/bibtex-utils/src/field/number.rs
2023/10/10 | 1624 | macros/latex/contrib/l3experimental/xgalley.ins
2023/10/10 | 16217 | macros/latex/contrib/l3backend/l3backend-basics.dtx
@@ -921,7 +1056,6 @@
2023/10/10 | 15 | support/texlab/crates/parser/src/test_data/latex/citation/citation_prenote.txt
2023/10/10 | 15 | support/texlab/crates/parser/src/test_data/latex/citation/citation_multiple_keys.txt
2023/10/10 | 15 | support/texlab/crates/bibtex-utils/src/lib.rs
-2023/10/10 | 159865 | systems/win32/miktex/tm/packages/next/miktex-fontconfig-bin-x64-2.9.tar.lzma
2023/10/10 | 1595 | support/texlab/crates/texlab/benches/bench_main.rs
2023/10/10 | 1590 | support/texlab/crates/commands/src/dep_graph.rs
2023/10/10 | 1583 | support/texlab/crates/commands/src/placeholders.rs
@@ -943,11 +1077,9 @@
2023/10/10 | 1547 | macros/latex/contrib/l3experimental/l3opacity.ins
2023/10/10 | 15442 | graphics/pgf/contrib/circuitikz/tex/pgfcirclabel.tex
2023/10/10 | 15429 | macros/luatex/generic/luatexja/src/ltj-rmlgbm.lua
-2023/10/10 | 153 | systems/texlive/tlnet/install-tl-windows.exe.sha512
2023/10/10 | 1536 | macros/luatex/generic/luatexja/COPYING
2023/10/10 | 1534 | support/texlab/crates/texlab/src/features/rename.rs
-2023/10/10 | 1530778 | systems/win32/miktex/tm/packages/next/miktex-runtime-bin-x64-2.9.tar.lzma
-2023/10/10 | 152 | systems/texlive/tlnet/install-tl-unx.tar.gz.sha512
+2023/10/10 | 1532 | support/easydtx/edtx2dtx.1
2023/10/10 | 1518404 | systems/texlive/tlnet/archive/culmus.r68495.tar.xz
2023/10/10 | 151752 | macros/latex/contrib/l3kernel/l3docstrip.pdf
2023/10/10 | 151591 | macros/latex/contrib/l3kernel/l3news06.pdf
@@ -969,21 +1101,17 @@
2023/10/10 | 14669 | macros/latex/contrib/l3backend/l3backend-header.dtx
2023/10/10 | 1464 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@glossary__acronym_declaration.txt.snap
2023/10/10 | 1462 | support/texlab/crates/rename/src/tests.rs
-2023/10/10 | 14600 | systems/win32/miktex/tm/packages/next/miktex-zzip-bin-x64-2.9.tar.lzma
-2023/10/10 | 145 | systems/texlive/tlnet/install-tl.zip.sha512
2023/10/10 | 14587 | graphics/pgf/contrib/circuitikz/tex/pgfcircutils.tex
2023/10/10 | 1453368 | systems/texlive/tlnet/archive/tex4ht.source.r68494.tar.xz
-2023/10/10 | 144 | systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
2023/10/10 | 14479 | graphics/pgf/contrib/tkz-bernoulli/doc/tkz-bernoulli-doc.tex
2023/10/10 | 1444 | macros/latex/contrib/l3packages/l3keys2e-demo.tex
2023/10/10 | 14431 | macros/latex/contrib/l3backend/l3backend-box.dtx
2023/10/10 | 144300 | systems/texlive/tlnet/archive/culmus.doc.r68495.tar.xz
-2023/10/10 | 1442511 | systems/win32/miktex/tm/packages/next/miktex-dvisvgm-bin-x64-2.9.tar.lzma
2023/10/10 | 144087 | macros/latex/contrib/l3kernel/l3file.dtx
2023/10/10 | 143 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_string.snap
2023/10/10 | 14338 | support/texlab/crates/symbols/src/document/tests.rs
2023/10/10 | 1432 | support/texlab/crates/hover/src/lib.rs
-2023/10/10 | 142010 | systems/win32/miktex/tm/packages/next/miktex-mktex-bin-x64-2.9.tar.lzma
+2023/10/10 | 141402 | macros/generic/memoize/memoize.edtx
2023/10/10 | 1412 | support/texlab/crates/texlab/src/server/progress.rs
2023/10/10 | 1409 | support/texlab/crates/references/src/entry.rs
2023/10/10 | 14036719 | install/macros/latex/contrib/l3kernel.tds.zip
@@ -996,7 +1124,6 @@
2023/10/10 | 13895 | macros/luatex/generic/luatexja/src/jfm-ujis.lua
2023/10/10 | 1382 | support/texlab/crates/completion/src/util/builder.rs
2023/10/10 | 13775882 | macros/latex/contrib/l3kernel.zip
-2023/10/10 | 137625 | systems/win32/miktex/tm/packages/next/miktex-dvips-bin-x64-2.9.tar.lzma
2023/10/10 | 13737 | graphics/pgf/contrib/circuitikz/tex/circuitikz.sty
2023/10/10 | 13726 | macros/luatex/generic/luatexja/doc/lltjp-geometry.tex
2023/10/10 | 136384 | systems/texlive/tlnet/archive/tex4ht.doc.r68494.tar.xz
@@ -1010,7 +1137,6 @@
2023/10/10 | 1348 | support/texlab/crates/definition/src/command.rs
2023/10/10 | 13485 | systems/win32/miktex/tm/packages/msu-thesis.tar.lzma
2023/10/10 | 13459 | graphics/pgf/contrib/circuitikz/doc/circuitikz-context.pdf
-2023/10/10 | 1341359 | systems/win32/miktex/tm/packages/next/miktex-poppler-bin-x64-2.9.tar.lzma
2023/10/10 | 13353 | support/texlab/crates/parser/src/test_data/build_log/005.txt
2023/10/10 | 1331 | macros/latex/contrib/l3backend/l3backend-code.tex
2023/10/10 | 13316 | macros/luatex/generic/luatexja/src/ltj-setwidth.lua
@@ -1024,13 +1150,16 @@
2023/10/10 | 130759 | systems/win32/miktex/tm/packages/autosp__source.tar.lzma
2023/10/10 | 1306 | macros/latex/contrib/l3packages/xfrac.ins
2023/10/10 | 1304 | support/texlab/crates/texlab/src/features/definition.rs
+2023/10/10 | 1301 | macros/generic/collargs/collargs.ins
2023/10/10 | 12 | support/texlab/crates/texlab/tests/lsp/workspace.rs
2023/10/10 | 12 | support/texlab/crates/parser/src/test_data/latex/hello_world.txt
2023/10/10 | 12 | support/texlab/crates/parser/src/test_data/latex/group/curly_group_missing_end.txt
2023/10/10 | 12 | support/texlab/crates/parser/src/test_data/latex/citation/citation_redundant_comma.txt
2023/10/10 | 1298 | support/texlab/crates/texlab/src/features/inlay_hint.rs
2023/10/10 | 129885 | macros/latex/contrib/l3kernel/l3keys.dtx
+2023/10/10 | 12932 | macros/generic/memoize/doc/yadoc.sty
2023/10/10 | 128344 | macros/latex/contrib/l3kernel/l3news07.pdf
+2023/10/10 | 1281 | macros/generic/advice/advice.ins
2023/10/10 | 12806 | macros/latex/contrib/l3kernel/l3bootstrap.dtx
2023/10/10 | 12798 | macros/latex/contrib/pdfmanagement-testphase/ltdocinit.dtx
2023/10/10 | 1278 | macros/luatex/generic/luatexja/src/ltjclasses.ins
@@ -1061,17 +1190,13 @@
2023/10/10 | 117880 | graphics/pgf/contrib/circuitikz/tex/pgfcircmultipoles.tex
2023/10/10 | 11781 | macros/latex/contrib/l3kernel/l3fparray.dtx
2023/10/10 | 1177 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@command_definition__command_definition_with_begin.txt.snap
-2023/10/10 | 117784 | systems/win32/miktex/tm/packages/next/miktex-gregorio-bin-x64-2.9.tar.lzma
-2023/10/10 | 1171965 | systems/win32/miktex/tm/packages/next/miktex-asymptote-bin-x64-2.9.tar.lzma
2023/10/10 | 1170 | support/texlab/crates/base-db/src/semantics/auxiliary.rs
2023/10/10 | 1157 | support/texlab/crates/texlab/tests/lsp/text_document/document_link.rs
-2023/10/10 | 1150 | systems/win32/miktex/tm/packages/next/pr.ini
2023/10/10 | 11506 | macros/luatex/generic/luatexja/src/jfm-ujisv.lua
2023/10/10 | 114754 | macros/latex/contrib/l3kernel/l3news04.pdf
2023/10/10 | 1146 | support/texlab/crates/definition/src/label.rs
2023/10/10 | 1144113 | macros/luatex/generic/luatexja/doc/luatexja-ja.pdf
2023/10/10 | 11420 | support/texlab/crates/parser/src/bibtex.rs
-2023/10/10 | 114072 | systems/texlive/tlnet/archive/texlive-scripts.r68489.tar.xz
2023/10/10 | 11391011 | macros/latex/contrib/pdfmanagement-testphase.zip
2023/10/10 | 113435 | macros/latex/contrib/l3kernel/l3str-convert.dtx
2023/10/10 | 11335 | macros/luatex/generic/luatexja/tool/unicodeBlocks.tex
@@ -1079,7 +1204,6 @@
2023/10/10 | 113014 | systems/win32/miktex/tm/packages/msu-thesis__doc.tar.lzma
2023/10/10 | 112524 | macros/latex/contrib/l3kernel/l3news05.pdf
2023/10/10 | 1124 | support/texlab/crates/distro/src/language.rs
-2023/10/10 | 112490 | systems/win32/miktex/tm/packages/next/miktex-texware-bin-x64-2.9.tar.lzma
2023/10/10 | 112255 | macros/latex/contrib/l3kernel/l3color.dtx
2023/10/10 | 1121 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@environment__environment_nested.txt.snap
2023/10/10 | 1119 | support/texlab/crates/texlab/src/features/highlight/label.rs
@@ -1092,9 +1216,9 @@
2023/10/10 | 11015 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__nietzsche_1998.txt.snap
2023/10/10 | 10 | support/texlab/crates/parser/src/test_data/latex/citation/citation_star.txt
2023/10/10 | 10 | support/texlab/crates/parser/src/test_data/latex/citation/citation_simple.txt
-2023/10/10 | 109894 | systems/win32/miktex/tm/packages/next/miktex-jpeg-bin-x64-2.9.tar.lzma
+2023/10/10 | 10 | macros/generic/memoize/doc/memoize.mst
+2023/10/10 | 109800 | macros/generic/collargs/collargs.edtx
2023/10/10 | 108 | support/texlab/crates/texlab/src/lib.rs
-2023/10/10 | 108579 | systems/win32/miktex/tm/packages/next/miktex-mfware-bin-x64-2.9.tar.lzma
2023/10/10 | 1083 | support/texlab/crates/texlab/src/features/formatting.rs
2023/10/10 | 1081680 | graphics/pgf/contrib/circuitikz/tex/circuitikz-1.4.6-body.tex
2023/10/10 | 1076 | support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_885.snap
@@ -1104,20 +1228,15 @@
2023/10/10 | 1070 | support/texlab/crates/references/src/lib.rs
2023/10/10 | 1067 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__package_include_options.txt.snap
2023/10/10 | 1066 | support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@include__class_include_options.txt.snap
-2023/10/10 | 106590 | systems/win32/miktex/tm/packages/next/miktex-cweb-bin-x64-2.9.tar.lzma
2023/10/10 | 10650 | macros/luatex/generic/luatexja/src/addons/luatexja-ruby.sty
2023/10/10 | 1064 | support/texlab/crates/rename/src/lib.rs
2023/10/10 | 1059 | support/texlab/crates/hover/src/string_ref.rs
2023/10/10 | 105739 | systems/win32/miktex/tm/packages/musixtex.tar.lzma
-2023/10/10 | 105734 | systems/win32/miktex/tm/packages/next/miktex-gd-bin-x64-2.9.tar.lzma
2023/10/10 | 1056 | support/texlab/crates/definition/src/include.rs
2023/10/10 | 1051 | support/texlab/crates/texlab/tests/lsp/workspace/symbol.rs
2023/10/10 | 105012 | macros/latex/contrib/l3kernel/l3fp-parse.dtx
2023/10/10 | 1048 | support/texlab/crates/definition/src/string_ref.rs
-2023/10/10 | 104397 | systems/win32/miktex/tm/packages/next/miktex-epstopdf-bin-x64-2.9.tar.lzma
-2023/10/10 | 104151 | systems/win32/miktex/tm/packages/next/miktex-lua53-bin-x64-2.9.tar.lzma
2023/10/10 | 10380 | support/texlab/crates/parser/src/snapshots/parser__bibtex__tests__parse@samples__averroes_1998.txt.snap
-2023/10/10 | 103622 | systems/win32/miktex/tm/packages/next/miktex-bibtex8bit-bin-x64-2.9.tar.lzma
2023/10/10 | 10328 | macros/latex/contrib/l3kernel/l3flag.dtx
2023/10/10 | 1025 | support/texlab/crates/completion/src/util/matchers.rs
2023/10/10 | 1023 | support/texlab/crates/completion/benches/bench_main.rs
@@ -1315,7 +1434,6 @@
2023/10/09 | 7356 | macros/jptex/latex/japanese-otf/vf/cidjgb--h.vf
2023/10/09 | 72 | macros/jptex/latex/japanese-otf/vf/utfjmgrx-v.vf
2023/10/09 | 72 | macros/jptex/latex/japanese-otf/vf/utfjmgrx-h.vf
-2023/10/09 | 7165 | systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
2023/10/09 | 704 | macros/jptex/latex/japanese-otf/tfm/otf-ccmr-v.tfm
2023/10/09 | 704 | macros/jptex/latex/japanese-otf/tfm/otf-ccml-v.tfm
2023/10/09 | 704 | macros/jptex/latex/japanese-otf/tfm/otf-ccmgr-v.tfm
@@ -2860,6 +2978,7 @@
2023/10/09 | 3876 | macros/jptex/latex/japanese-otf/vf/utftmrl-h.vf
2023/10/09 | 3876 | macros/jptex/latex/japanese-otf/vf/utftgrl-v.vf
2023/10/09 | 3876 | macros/jptex/latex/japanese-otf/vf/utftgrl-h.vf
+2023/10/09 | 3797 | support/texshop/texshop520.html
2023/10/09 | 3796 | macros/jptex/latex/japanese-otf/vf/utfmrq-v.vf
2023/10/09 | 3796 | macros/jptex/latex/japanese-otf/vf/utfmrq-h.vf
2023/10/09 | 3796 | macros/jptex/latex/japanese-otf/vf/utfgrq-v.vf
@@ -6454,20 +6573,3 @@
2023/10/05 | 104123 | systems/win32/miktex/tm/packages/miktex-lua53-bin-x64-2.9.tar.lzma
2023/10/05 | 103586 | systems/win32/miktex/tm/packages/miktex-bibtex8bit-bin-x64-2.9.tar.lzma
2023/10/05 | 10052 | biblio/citation-style-language/citation-style-language-init.sty
-2023/10/04 | 97864 | macros/luatex/generic/opbible/macros/opbible.opm
-2023/10/04 | 919860 | systems/texlive/tlnet/archive/beebe.r68444.tar.xz
-2023/10/04 | 77755 | macros/musixtex/doc/musixdoc/extensions.tex
-2023/10/04 | 7436 | systems/texlive/tlnet/archive/minimalist.doc.r68447.tar.xz
-2023/10/04 | 724 | systems/texlive/tlnet/archive/nlctdoc.doc.r68448.tar.xz
-2023/10/04 | 64411 | macros/luatex/generic/opbible/examples/english/txs/RNKJV-Dan.txs
-2023/10/04 | 497 | graphics/pgf/contrib/circularglyphs/README.md
-2023/10/04 | 3580 | systems/texlive/tlnet/archive/homework.r68446.tar.xz
-2023/10/04 | 351420 | systems/texlive/tlnet/archive/homework.doc.r68446.tar.xz
-2023/10/04 | 290531 | support/TeX4ht/source/tex4ht-sty.tex
-2023/10/04 | 2592 | systems/texlive/tlnet/archive/schemabloc.r68445.tar.xz
-2023/10/04 | 24400 | systems/texlive/tlnet/archive/nlctdoc.r68448.tar.xz
-2023/10/04 | 204048 | systems/texlive/tlnet/archive/schemabloc.doc.r68445.tar.xz
-2023/10/04 | 169852 | macros/luatex/generic/opbible/examples/english/notes/notes-Dan.tex
-2023/10/04 | 1448431 | macros/musixtex/doc/musixdoc.pdf
-2023/10/04 | 12700 | systems/texlive/tlnet/archive/minimalist.r68447.tar.xz
-2023/10/04 | 119 | systems/win32/miktex/setup/rpm/rockylinux-9.repo
diff --git a/biblio/ctan-bibdata/ctan.bib b/biblio/ctan-bibdata/ctan.bib
index 992e1f370a..26be2e04b0 100644
--- a/biblio/ctan-bibdata/ctan.bib
+++ b/biblio/ctan-bibdata/ctan.bib
@@ -1,7 +1,7 @@
%% bib file of all CTAN packages
%% (C) Herbert Voß
%%
-%% created at 11-10-2023, 02:01:18
+%% created at 12-10-2023, 02:05:59
%%
%% This file is provided under the terms of the LPPL v1.3 or
@@ -1018,6 +1018,17 @@
Czech dates.},
}
+@manual{ctan-advice,
+ title = {The \texttt{Advice} package},
+ subtitle = {Extend commands and environments},
+ author = {Sašo Živanović},
+ date = {2023-10-11},
+ version = {1.0.0},
+ license = {lppl1.3c},
+ mirror = {https://mirror.ctan.org/macros/generic/advice},
+ url = {https://ctan.org/pkg/advice},
+}
+
@manual{ctan-ae,
title = {The \texttt{ae} package},
subtitle = {Virtual fonts for T1 encoded CMR-fonts},
@@ -4188,7 +4199,7 @@
title = {The \texttt{autosp} package},
subtitle = {A Preprocessor that generates note-spacing commands for MusiXTeX scores},
author = {Bob Tennent},
- date = {2023-10-09},
+ date = {2023-10-11},
version = {},
license = {gpl2+},
mirror = {https://mirror.ctan.org/support/autosp},
@@ -13889,6 +13900,17 @@
url = {https://ctan.org/pkg/coffeestains},
}
+@manual{ctan-collargs,
+ title = {The \texttt{CollArgs} package},
+ subtitle = {Collect arguments of any command},
+ author = {Sašo Živanović},
+ date = {2023-10-11},
+ version = {1.0.0},
+ license = {lppl1.3c},
+ mirror = {https://mirror.ctan.org/macros/generic/collargs},
+ url = {https://ctan.org/pkg/collargs},
+}
+
@manual{ctan-collcell,
title = {The \texttt{collcell} package},
subtitle = {Collect contents of a tabular cell as argument to a macro},
@@ -20528,6 +20550,17 @@
standard document classes.},
}
+@manual{ctan-easydtx,
+ title = {The \texttt{EasyDTX} package},
+ subtitle = {A simplified DTX format},
+ author = {Sašo Živanović},
+ date = {2023-10-11},
+ version = {0.1.0},
+ license = {gpl3+},
+ mirror = {https://mirror.ctan.org/support/easydtx},
+ url = {https://ctan.org/pkg/easydtx},
+}
+
@manual{ctan-easyeqn,
title = {The \texttt{easyeqn} package},
subtitle = {A simple package for writing equations},
@@ -23233,6 +23266,22 @@
url = {https://ctan.org/pkg/etoolbox-de},
}
+@manual{ctan-etoolbox-generic,
+ title = {The \texttt{etoolbox-generic} package},
+ subtitle = {A loader for etoolbox.sty in non-\LaTeX{} formats},
+ author = {Sašo Živanović},
+ date = {2023-10-11},
+ version = {2.5k},
+ license = {lppl1.3c},
+ mirror = {https://mirror.ctan.org/macros/generic/etoolbox-generic},
+ url = {https://ctan.org/pkg/etoolbox-generic},
+ annotation = {This package implements a wrapper which allows the user
+ to load the \LaTeX{}-independent part of \LaTeX{} package
+ in other formats.
+ It was implemented as an auxiliary package of
+ .},
+}
+
@manual{ctan-etoolbox,
title = {The \texttt{etoolbox} package},
subtitle = {e-TeX tools for \LaTeX{}},
@@ -44361,6 +44410,28 @@
url = {https://ctan.org/pkg/memoirchapterstyles},
}
+@manual{ctan-memoize,
+ title = {The \texttt{Memoize} package},
+ subtitle = {Externalization of graphics and memoization of compilation results in general},
+ author = {Sašo Živanović},
+ date = {2023-10-11},
+ version = {1.0.0},
+ license = {lppl1.3c},
+ mirror = {https://mirror.ctan.org/macros/generic/memoize},
+ url = {https://ctan.org/pkg/memoize},
+ annotation = {Memoize is a package for externalization of graphics and memoization of
+ compilation results in general, allowing the author to reuse the results
+ of compilation-intensive code. Memoize (i) induces very little overhead,
+ as all externalized graphics is produced in a single compilation. It
+ features (ii) automatic recompilation upon the change of code or user-adjustable
+ context, and (iii) automatic externalization of
+ pictures and trees,
+ easily extensible to other commands and environments. Furthermore, Memoize (iv)
+ supports cross-referencing, overlays and
+ , (v) works with all major engines
+ and formats, and (vi) is adaptable to any workflow.},
+}
+
@manual{ctan-memory,
title = {The \texttt{memory} package},
subtitle = {Containers for data in \LaTeX{}},
@@ -68643,8 +68714,8 @@
title = {The \texttt{texshop} package},
subtitle = {TeX front end for use on MacOS X},
author = {Dick Koch},
- date = {2023-09-22},
- version = {5.18},
+ date = {2023-10-11},
+ version = {5.20},
license = {gpl},
mirror = {https://mirror.ctan.org/support/texshop},
url = {https://ctan.org/pkg/texshop},
diff --git a/biblio/ctan-bibdata/ctan.pdf b/biblio/ctan-bibdata/ctan.pdf
index 4c8dbdb26e..b6dd0e6449 100644
--- a/biblio/ctan-bibdata/ctan.pdf
+++ b/biblio/ctan-bibdata/ctan.pdf
Binary files differ
diff --git a/macros/generic/advice/INSTALL.md b/macros/generic/advice/INSTALL.md
new file mode 100644
index 0000000000..96844efa8f
--- /dev/null
+++ b/macros/generic/advice/INSTALL.md
@@ -0,0 +1,69 @@
+# Installation from the TDS archive
+
+If Advice is not (yet) offered by your TeX distribution, the easiest way to
+install it is by downloading the TDS archive `advice.tds.zip` from [Advice's
+CTAN page](https://ctan.org/pkg/advice), and unpacking it into your `texmf`
+directory. You will most likely also have to do the same for an auxiliary
+package Advice depends on: [CollArgs](https://ctan.org/pkg/collargs).
+
+Read on only if you have an unstoppable urge to install from source and/or
+compile the manual or the documented source code.
+
+# Installation from the source
+
+## Getting the sources
+
+There are several options:
+
+* Download and unpack the zip archive of the package from [Advice's CTAN
+ page](https://ctan.org/pkg/advice).
+
+* Download and unpack the TDS archive, or copy the files from your local
+ distribution. The sources reside in `<texmf>/source/generic/advice`.
+
+* Clone the [GitHub repository of
+ Memoize](https://github.com/sasozivanovic/memoize).
+
+## Generating the runtime files
+
+The easiest way to generate the runtime files is by running `make`. The
+following command will generate runtime files for all supported formats
+(currently: LaTeX, plain TeX and ConTeXt).
+
+```
+make advice.sty
+```
+
+Alternatively, you can generate these files manually. The source of this
+package was written using [EasyDTX](https://ctan.org/pkg/easydtx). Therefore,
+you first have to convert the `.edtx` file into a regular `.dtx`:
+
+```
+edtx2dtx advice.edtx > advice.dtx
+```
+
+The next step is standard. Produce the runtime files by compiling the
+installation file:
+
+```
+tex advice.ins
+```
+
+Finally, if you require the ConTeXt runtime, replace all instances of
+`\expanded` and `\unexpanded` in `t-advice.tex` by `\normalexpanded` and
+`\normalunexpanded`, respectively. One way to do this is:
+
+```
+sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-advice.tex
+```
+
+## Installation
+
+It is recommended to install the files into a TDS-compliant `texmf` directory,
+as usual. Inspect file `FILES` or the TDS archive `advice.tds.zip` to see what
+goes where.
+
+# Compiling the documentation
+
+The documentation of this package is integrated into the documentation of
+[Memoize](https://ctan.org/pkg/memoize), please continue there.
diff --git a/macros/generic/advice/LICENCE b/macros/generic/advice/LICENCE
new file mode 100644
index 0000000000..1b57559a83
--- /dev/null
+++ b/macros/generic/advice/LICENCE
@@ -0,0 +1,416 @@
+The LaTeX Project Public License
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+LPPL Version 1.3c 2008-05-04
+
+Copyright 1999 2002-2008 LaTeX3 Project
+ Everyone is allowed to distribute verbatim copies of this
+ license document, but modification of it is not allowed.
+
+
+PREAMBLE
+========
+
+The LaTeX Project Public License (LPPL) is the primary license under
+which the LaTeX kernel and the base LaTeX packages are distributed.
+
+You may use this license for any work of which you hold the copyright
+and which you wish to distribute. This license may be particularly
+suitable if your work is TeX-related (such as a LaTeX package), but
+it is written in such a way that you can use it even if your work is
+unrelated to TeX.
+
+The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
+below, gives instructions, examples, and recommendations for authors
+who are considering distributing their works under this license.
+
+This license gives conditions under which a work may be distributed
+and modified, as well as conditions under which modified versions of
+that work may be distributed.
+
+We, the LaTeX3 Project, believe that the conditions below give you
+the freedom to make and distribute modified versions of your work
+that conform with whatever technical specifications you wish while
+maintaining the availability, integrity, and reliability of
+that work. If you do not see how to achieve your goal while
+meeting these conditions, then read the document `cfgguide.tex'
+and `modguide.tex' in the base LaTeX distribution for suggestions.
+
+
+DEFINITIONS
+===========
+
+In this license document the following terms are used:
+
+ `Work'
+ Any work being distributed under this License.
+
+ `Derived Work'
+ Any work that under any applicable law is derived from the Work.
+
+ `Modification'
+ Any procedure that produces a Derived Work under any applicable
+ law -- for example, the production of a file containing an
+ original file associated with the Work or a significant portion of
+ such a file, either verbatim or with modifications and/or
+ translated into another language.
+
+ `Modify'
+ To apply any procedure that produces a Derived Work under any
+ applicable law.
+
+ `Distribution'
+ Making copies of the Work available from one person to another, in
+ whole or in part. Distribution includes (but is not limited to)
+ making any electronic components of the Work accessible by
+ file transfer protocols such as FTP or HTTP or by shared file
+ systems such as Sun's Network File System (NFS).
+
+ `Compiled Work'
+ A version of the Work that has been processed into a form where it
+ is directly usable on a computer system. This processing may
+ include using installation facilities provided by the Work,
+ transformations of the Work, copying of components of the Work, or
+ other activities. Note that modification of any installation
+ facilities provided by the Work constitutes modification of the Work.
+
+ `Current Maintainer'
+ A person or persons nominated as such within the Work. If there is
+ no such explicit nomination then it is the `Copyright Holder' under
+ any applicable law.
+
+ `Base Interpreter'
+ A program or process that is normally needed for running or
+ interpreting a part or the whole of the Work.
+
+ A Base Interpreter may depend on external components but these
+ are not considered part of the Base Interpreter provided that each
+ external component clearly identifies itself whenever it is used
+ interactively. Unless explicitly specified when applying the
+ license to the Work, the only applicable Base Interpreter is a
+ `LaTeX-Format' or in the case of files belonging to the
+ `LaTeX-format' a program implementing the `TeX language'.
+
+
+
+CONDITIONS ON DISTRIBUTION AND MODIFICATION
+===========================================
+
+1. Activities other than distribution and/or modification of the Work
+are not covered by this license; they are outside its scope. In
+particular, the act of running the Work is not restricted and no
+requirements are made concerning any offers of support for the Work.
+
+2. You may distribute a complete, unmodified copy of the Work as you
+received it. Distribution of only part of the Work is considered
+modification of the Work, and no right to distribute such a Derived
+Work may be assumed under the terms of this clause.
+
+3. You may distribute a Compiled Work that has been generated from a
+complete, unmodified copy of the Work as distributed under Clause 2
+above, as long as that Compiled Work is distributed in such a way that
+the recipients may install the Compiled Work on their system exactly
+as it would have been installed if they generated a Compiled Work
+directly from the Work.
+
+4. If you are the Current Maintainer of the Work, you may, without
+restriction, modify the Work, thus creating a Derived Work. You may
+also distribute the Derived Work without restriction, including
+Compiled Works generated from the Derived Work. Derived Works
+distributed in this manner by the Current Maintainer are considered to
+be updated versions of the Work.
+
+5. If you are not the Current Maintainer of the Work, you may modify
+your copy of the Work, thus creating a Derived Work based on the Work,
+and compile this Derived Work, thus creating a Compiled Work based on
+the Derived Work.
+
+6. If you are not the Current Maintainer of the Work, you may
+distribute a Derived Work provided the following conditions are met
+for every component of the Work unless that component clearly states
+in the copyright notice that it is exempt from that condition. Only
+the Current Maintainer is allowed to add such statements of exemption
+to a component of the Work.
+
+ a. If a component of this Derived Work can be a direct replacement
+ for a component of the Work when that component is used with the
+ Base Interpreter, then, wherever this component of the Work
+ identifies itself to the user when used interactively with that
+ Base Interpreter, the replacement component of this Derived Work
+ clearly and unambiguously identifies itself as a modified version
+ of this component to the user when used interactively with that
+ Base Interpreter.
+
+ b. Every component of the Derived Work contains prominent notices
+ detailing the nature of the changes to that component, or a
+ prominent reference to another file that is distributed as part
+ of the Derived Work and that contains a complete and accurate log
+ of the changes.
+
+ c. No information in the Derived Work implies that any persons,
+ including (but not limited to) the authors of the original version
+ of the Work, provide any support, including (but not limited to)
+ the reporting and handling of errors, to recipients of the
+ Derived Work unless those persons have stated explicitly that
+ they do provide such support for the Derived Work.
+
+ d. You distribute at least one of the following with the Derived Work:
+
+ 1. A complete, unmodified copy of the Work;
+ if your distribution of a modified component is made by
+ offering access to copy the modified component from a
+ designated place, then offering equivalent access to copy
+ the Work from the same or some similar place meets this
+ condition, even though third parties are not compelled to
+ copy the Work along with the modified component;
+
+ 2. Information that is sufficient to obtain a complete,
+ unmodified copy of the Work.
+
+7. If you are not the Current Maintainer of the Work, you may
+distribute a Compiled Work generated from a Derived Work, as long as
+the Derived Work is distributed to all recipients of the Compiled
+Work, and as long as the conditions of Clause 6, above, are met with
+regard to the Derived Work.
+
+8. The conditions above are not intended to prohibit, and hence do not
+apply to, the modification, by any method, of any component so that it
+becomes identical to an updated version of that component of the Work as
+it is distributed by the Current Maintainer under Clause 4, above.
+
+9. Distribution of the Work or any Derived Work in an alternative
+format, where the Work or that Derived Work (in whole or in part) is
+then produced by applying some process to that format, does not relax or
+nullify any sections of this license as they pertain to the results of
+applying that process.
+
+10. a. A Derived Work may be distributed under a different license
+ provided that license itself honors the conditions listed in
+ Clause 6 above, in regard to the Work, though it does not have
+ to honor the rest of the conditions in this license.
+
+ b. If a Derived Work is distributed under a different license, that
+ Derived Work must provide sufficient documentation as part of
+ itself to allow each recipient of that Derived Work to honor the
+ restrictions in Clause 6 above, concerning changes from the Work.
+
+11. This license places no restrictions on works that are unrelated to
+the Work, nor does this license place any restrictions on aggregating
+such works with the Work by any means.
+
+12. Nothing in this license is intended to, or may be used to, prevent
+complete compliance by all parties with all applicable laws.
+
+
+NO WARRANTY
+===========
+
+There is no warranty for the Work. Except when otherwise stated in
+writing, the Copyright Holder provides the Work `as is', without
+warranty of any kind, either expressed or implied, including, but not
+limited to, the implied warranties of merchantability and fitness for a
+particular purpose. The entire risk as to the quality and performance
+of the Work is with you. Should the Work prove defective, you assume
+the cost of all necessary servicing, repair, or correction.
+
+In no event unless required by applicable law or agreed to in writing
+will The Copyright Holder, or any author named in the components of the
+Work, or any other party who may distribute and/or modify the Work as
+permitted above, be liable to you for damages, including any general,
+special, incidental or consequential damages arising out of any use of
+the Work or out of inability to use the Work (including, but not limited
+to, loss of data, data being rendered inaccurate, or losses sustained by
+anyone as a result of any failure of the Work to operate with any other
+programs), even if the Copyright Holder or said author or said other
+party has been advised of the possibility of such damages.
+
+
+MAINTENANCE OF THE WORK
+=======================
+
+The Work has the status `author-maintained' if the Copyright Holder
+explicitly and prominently states near the primary copyright notice in
+the Work that the Work can only be maintained by the Copyright Holder
+or simply that it is `author-maintained'.
+
+The Work has the status `maintained' if there is a Current Maintainer
+who has indicated in the Work that they are willing to receive error
+reports for the Work (for example, by supplying a valid e-mail
+address). It is not required for the Current Maintainer to acknowledge
+or act upon these error reports.
+
+The Work changes from status `maintained' to `unmaintained' if there
+is no Current Maintainer, or the person stated to be Current
+Maintainer of the work cannot be reached through the indicated means
+of communication for a period of six months, and there are no other
+significant signs of active maintenance.
+
+You can become the Current Maintainer of the Work by agreement with
+any existing Current Maintainer to take over this role.
+
+If the Work is unmaintained, you can become the Current Maintainer of
+the Work through the following steps:
+
+ 1. Make a reasonable attempt to trace the Current Maintainer (and
+ the Copyright Holder, if the two differ) through the means of
+ an Internet or similar search.
+
+ 2. If this search is successful, then enquire whether the Work
+ is still maintained.
+
+ a. If it is being maintained, then ask the Current Maintainer
+ to update their communication data within one month.
+
+ b. If the search is unsuccessful or no action to resume active
+ maintenance is taken by the Current Maintainer, then announce
+ within the pertinent community your intention to take over
+ maintenance. (If the Work is a LaTeX work, this could be
+ done, for example, by posting to comp.text.tex.)
+
+ 3a. If the Current Maintainer is reachable and agrees to pass
+ maintenance of the Work to you, then this takes effect
+ immediately upon announcement.
+
+ b. If the Current Maintainer is not reachable and the Copyright
+ Holder agrees that maintenance of the Work be passed to you,
+ then this takes effect immediately upon announcement.
+
+ 4. If you make an `intention announcement' as described in 2b. above
+ and after three months your intention is challenged neither by
+ the Current Maintainer nor by the Copyright Holder nor by other
+ people, then you may arrange for the Work to be changed so as
+ to name you as the (new) Current Maintainer.
+
+ 5. If the previously unreachable Current Maintainer becomes
+ reachable once more within three months of a change completed
+ under the terms of 3b) or 4), then that Current Maintainer must
+ become or remain the Current Maintainer upon request provided
+ they then update their communication data within one month.
+
+A change in the Current Maintainer does not, of itself, alter the fact
+that the Work is distributed under the LPPL license.
+
+If you become the Current Maintainer of the Work, you should
+immediately provide, within the Work, a prominent and unambiguous
+statement of your status as Current Maintainer. You should also
+announce your new status to the same pertinent community as
+in 2b) above.
+
+
+WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
+======================================================
+
+This section contains important instructions, examples, and
+recommendations for authors who are considering distributing their
+works under this license. These authors are addressed as `you' in
+this section.
+
+Choosing This License or Another License
+----------------------------------------
+
+If for any part of your work you want or need to use *distribution*
+conditions that differ significantly from those in this license, then
+do not refer to this license anywhere in your work but, instead,
+distribute your work under a different license. You may use the text
+of this license as a model for your own license, but your license
+should not refer to the LPPL or otherwise give the impression that
+your work is distributed under the LPPL.
+
+The document `modguide.tex' in the base LaTeX distribution explains
+the motivation behind the conditions of this license. It explains,
+for example, why distributing LaTeX under the GNU General Public
+License (GPL) was considered inappropriate. Even if your work is
+unrelated to LaTeX, the discussion in `modguide.tex' may still be
+relevant, and authors intending to distribute their works under any
+license are encouraged to read it.
+
+A Recommendation on Modification Without Distribution
+-----------------------------------------------------
+
+It is wise never to modify a component of the Work, even for your own
+personal use, without also meeting the above conditions for
+distributing the modified component. While you might intend that such
+modifications will never be distributed, often this will happen by
+accident -- you may forget that you have modified that component; or
+it may not occur to you when allowing others to access the modified
+version that you are thus distributing it and violating the conditions
+of this license in ways that could have legal implications and, worse,
+cause problems for the community. It is therefore usually in your
+best interest to keep your copy of the Work identical with the public
+one. Many works provide ways to control the behavior of that work
+without altering any of its licensed components.
+
+How to Use This License
+-----------------------
+
+To use this license, place in each of the components of your work both
+an explicit copyright notice including your name and the year the work
+was authored and/or last substantially modified. Include also a
+statement that the distribution and/or modification of that
+component is constrained by the conditions in this license.
+
+Here is an example of such a notice and statement:
+
+ %% pig.dtx
+ %% Copyright 2008 M. Y. Name
+ %
+ % This work 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
+ % https://www.latex-project.org/lppl.txt
+ % and version 1.3c or later is part of all distributions of LaTeX
+ % version 2008 or later.
+ %
+ % This work has the LPPL maintenance status `maintained'.
+ %
+ % The Current Maintainer of this work is M. Y. Name.
+ %
+ % This work consists of the files pig.dtx and pig.ins
+ % and the derived file pig.sty.
+
+Given such a notice and statement in a file, the conditions
+given in this license document would apply, with the `Work' referring
+to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
+generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
+referring to any `LaTeX-Format', and both `Copyright Holder' and
+`Current Maintainer' referring to the person `M. Y. Name'.
+
+If you do not want the Maintenance section of LPPL to apply to your
+Work, change `maintained' above into `author-maintained'.
+However, we recommend that you use `maintained', as the Maintenance
+section was added in order to ensure that your Work remains useful to
+the community even when you can no longer maintain and support it
+yourself.
+
+Derived Works That Are Not Replacements
+---------------------------------------
+
+Several clauses of the LPPL specify means to provide reliability and
+stability for the user community. They therefore concern themselves
+with the case that a Derived Work is intended to be used as a
+(compatible or incompatible) replacement of the original Work. If
+this is not the case (e.g., if a few lines of code are reused for a
+completely different task), then clauses 6b and 6d shall not apply.
+
+
+Important Recommendations
+-------------------------
+
+ Defining What Constitutes the Work
+
+ The LPPL requires that distributions of the Work contain all the
+ files of the Work. It is therefore important that you provide a
+ way for the licensee to determine which files constitute the Work.
+ This could, for example, be achieved by explicitly listing all the
+ files of the Work near the copyright notice of each file or by
+ using a line such as:
+
+ % This work consists of all files listed in manifest.txt.
+
+ in that place. In the absence of an unequivocal list it might be
+ impossible for the licensee to determine what is considered by you
+ to comprise the Work and, in such a case, the licensee would be
+ entitled to make reasonable conjectures as to which files comprise
+ the Work.
+
diff --git a/macros/generic/advice/Makefile b/macros/generic/advice/Makefile
new file mode 100644
index 0000000000..421bcdbfc9
--- /dev/null
+++ b/macros/generic/advice/Makefile
@@ -0,0 +1,8 @@
+.PRECIOUS: %.dtx
+
+%.dtx: %.edtx
+ edtx2dtx $< > $@
+
+%.sty %.tex t-%.tex &: %.ins %.dtx
+ tex $<
+ sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-$*.tex
diff --git a/macros/generic/advice/README.md b/macros/generic/advice/README.md
new file mode 100644
index 0000000000..0b001d9df8
--- /dev/null
+++ b/macros/generic/advice/README.md
@@ -0,0 +1,8 @@
+Like its namesake from the Emacs world, package Advice implements a generic
+framework for extending the functionality of selected commands and
+environments.
+
+This package was developed as an auxiliary package of
+[Memoize](https://ctan.org/pkg/memoize). This is why it is, somewhat
+unconventionally, documented alongside that package. This applies to both the
+manual and the documented code listing.
diff --git a/macros/generic/advice/advice.edtx b/macros/generic/advice/advice.edtx
new file mode 100644
index 0000000000..ee9486226e
--- /dev/null
+++ b/macros/generic/advice/advice.edtx
@@ -0,0 +1,1095 @@
+% \iffalse
+%
+% advice.edtx (this is not a .dtx file; to produce a .dtx, process it with edtx2dtx)
+%
+%% This file is a part of Advice, a TeX package implementing a generic
+%% framework for extending the functionality of selected commands and
+%% environments, available at https://ctan.org/pkg/advice and
+%% https://github.com/sasozivanovic/advice.
+%%
+%% Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in `FILES`.
+%
+% \fi
+%
+% \begin{macrocode}
+%
+% \relax
+%
+%<*main>
+%<latex>\ProvidesPackage{advice}[2023/10/10 v1.0.0 Extend commands and environments]
+%<context>%D \module[
+%<context>%D file=t-advice.tex,
+%<context>%D version=1.0.0,
+%<context>%D title=Advice,
+%<context>%D subtitle=Extend commands and environments,
+%<context>%D author=Saso Zivanovic,
+%<context>%D date=2023-10-10,
+%<context>%D copyright=Saso Zivanovic,
+%<context>%D license=LPPL,
+%<context>%D ]
+%<context>\writestatus{loading}{ConTeXt User Module / advice}
+%<context>\unprotect
+%<context>\startmodule[advice]
+% \paragraph{Required packages}
+%<latex>\RequirePackage{collargs}
+%<plain>\input collargs
+%<context>\input t-collargs
+%
+% \subsubsection{Installation into a keypath}
+%
+% \begin{handlerskey}{.install advice}
+% This handler installs the advising mechanism into the handled path, which
+% we shall henceforth also call the (advice) namespace.
+\pgfkeys{
+ /handlers/.install advice/.code={%
+ \edef\auto@install@namespace{\pgfkeyscurrentpath}%
+ \def\advice@install@setupkey{advice}%
+ \def\advice@install@activation{immediate}%
+ \pgfqkeys{/advice/install}{#1}%
+ \expanded{\noexpand\advice@install
+ {\auto@install@namespace}%
+ {\advice@install@setupkey}%
+ {\advice@install@activation}%
+ }%
+ },
+% \end{handlerskey}
+%
+% \begin{adviceinstallkey}{setup key,activation}
+% These keys can be used in the argument of |.install advice| to configure
+% the installation. By default, the setup key is |advice| and |activation| is
+% |immediate|.
+ /advice/install/.cd,
+ setup key/.store in=\advice@install@setupkey,
+ activation/.is choice,
+ activation/.append code=\def\advice@install@activation{#1},
+ activation/immediate/.code={},
+ activation/deferred/.code={},
+}
+% \end{adviceinstallkey}
+%
+% |#1| is the installation keypath (in Memoize, |/mmz|); |#2| is the setup key
+% name (in Memoize, |auto|, and this is why we document it as such); |#3| is
+% the initial activation regime.
+\def\advice@install#1#2#3{%
+ % Switch to the installation keypath.
+ \pgfqkeys{#1}{%
+ % \begin{key}{auto, auto csname, auto key, auto', auto csname', auto key'}
+ % These keys submit a command or environment to advising. The
+ % namespace is hard-coded into these keys via |#1|; their arguments are
+ % the command/environment (cs)name, and setup keys belonging to path
+ % \meta{installation keypath}|/\meta{setup key name}|.
+ #2/.code 2 args={%
+ % Call the internal setup macro, wrapping the received keylist into a
+ % |pgfkeys| invocation.
+ \AdviceSetup{#1}{#2}{##1}{\pgfqkeys{#1/#2}{##2}}%
+ % Activate if not already activated (this can happen when updating the
+ % configuration). Note we don't call |\advice@activate| directly, but use
+ % the public keys; in this way, activation is automatically deferred if
+ % so requested. (We don't use |\pgfkeysalso| to allow |auto| being called
+ % from any path.)
+ \pgfqkeys{#1}{try activate, activate={##1}}%
+ },
+ % A variant without activation.
+ #2'/.code 2 args={%
+ \AdviceSetup{#1}{#2}{##1}{\pgfqkeys{#1/#2}{##2}}%
+ },
+ #2 csname/.style 2 args={
+ #2/.expand once=\expandafter{\csname ##1\endcsname}{##2},
+ },
+ #2 csname'/.style 2 args={
+ #2'/.expand once=\expandafter{\csname ##1\endcsname}{##2},
+ },
+ #2 key/.style 2 args={
+ #2/.expand once=%
+ \expandafter{\csname pgfk@##1/.@cmd\endcsname}%
+ {collector=\advice@pgfkeys@collector,##2},
+ },
+ #2 key'/.style 2 args={
+ #2'/.expand once=%
+ \expandafter{\csname pgfk@##1/.@cmd\endcsname}%
+ {collector=\advice@pgfkeys@collector,##2},
+ },
+ % \end{key}
+ %
+ % \begin{key}{activation}
+ % This key, residing in the installation keypath, forwards the request to
+ % the |/advice| path |activation| subkeys, which define |activate| and
+ % friends in the installation keypath. Initially, the activation regime
+ % is whatever the user has requested using the |.install advice| argument
+ % (here |#3|).
+ activation/.style={/advice/activation/##1={#1}},
+ activation=#3,
+ % \end{key}
+ %
+ % \begin{key}{activate deferred}
+ % The deferred activations are collected in this style, see
+ % section~ref{sec:code:advice:activation} for details.
+ activate deferred/.code={},
+ % \end{key}
+ %
+ % \begin{key}{activate csname, deactivate csname}
+ % For simplicity of implementation, the |csname| versions of |activate|
+ % and |deactivate| accept a single \meta{csname}. This way, they can be
+ % defined right away, as they don't change with the type of activation
+ % (immediate vs.\ deferred).
+ activate csname/.style={activate/.expand once={\csname##1\endcsname}},
+ deactivate csname/.style={activate/.expand once={\csname##1\endcsname}},
+ % \end{key}
+ %
+ % \begin{key}{activate key, deactivate key}
+ % (De)activation of |pgfkeys| keys. Accepts a list of key names, requires
+ % full key names.
+ activate key/.style={activate@key={#1/activate}{##1}},
+ deactivate key/.style={activate@key={#1/deactivate}{##1}},
+ activate@key/.code n args=2{%
+ \def\advice@temp{}%
+ \def\advice@do####1{%
+ \eappto\advice@temp{,\expandonce{\csname pgfk@####1/.@cmd\endcsname}}}%
+ \forcsvlist\advice@do{##2}%
+ \pgfkeysalso{##1/.expand once=\advice@temp}%
+ },
+ % \end{key}
+ %
+ % The rest of the keys defined below reside in the |auto| subfolder of the
+ % installation keypath.
+ #2/.cd,
+ %
+ % \begin{mmzautokey}{run conditions, outer handler, bailout handler, collector,
+ % args, collector options, clear collector options, raw collector options,
+ % clear raw collector options, inner handler, options, clear options}
+ % These keys are used to setup the handling of the command or
+ % environment. The storage macros (|\AdviceRunConditions| etc.) have
+ % public names as they also play a crucial role in the handler
+ % definitions, see section~\ref{sec:code:advice:handle}. \indentmacrocode
+ run conditions/.store in=\AdviceRunConditions,
+ bailout handler/.store in=\AdviceBailoutHandler,
+ outer handler/.store in=\AdviceOuterHandler,
+ collector/.store in=\AdviceCollector,
+ collector options/.code={\appto\AdviceCollectorOptions{,##1}},
+ clear collector options/.code={\def\AdviceCollectorOptions{}},
+ raw collector options/.code={\appto\AdviceRawCollectorOptions{##1}},
+ clear raw collector options/.code={\def\AdviceRawCollectorOptions{}},
+ args/.store in=\AdviceArgs,
+ inner handler/.store in=\AdviceInnerHandler,
+ options/.code={\appto\AdviceOptions{,##1}},
+ clear options/.code={\def\AdviceOptions{}},
+ % \noindentmacrocode
+ % A user-friendly way to set |options|: any unknown key is an option.
+ .unknown/.code={%
+ \eappto{\AdviceOptions}{,\pgfkeyscurrentname={\unexpanded{##1}}}%
+ },
+ % The default values of the keys, which equal the initial values for
+ % commands, as assigned by |\advice@setup@init@command|.
+ run conditions/.default=\AdviceRuntrue,
+ bailout handler/.default=\relax,
+ outer handler/.default=\advice@default@outer@handler,
+ collector/.default=\advice@CollectArgumentsRaw,
+ collector options/.value required,
+ raw collector options/.value required,
+ args/.default=\advice@noargs,
+ inner handler/.default=\advice@error@noinnerhandler,
+ options/.value required,
+ % \end{mmzautokey}
+ %
+ % \begin{mmzautokey}{reset}
+ % This key resets the advice settings to their initial values, which
+ % depend on whether we're handling a command or environment.
+ reset/.code={\csname\advice@setup@init@\AdviceType\endcsname},
+ % \end{mmzautokey}
+ %
+ % \begin{mmzautokey}
+ % The code given here will be executed once we exit the setup group.
+ % |integrated driver| of Memoize uses it to declare a conditional.
+ after setup/.code={\appto\AdviceAfterSetup{##1}},
+ % \end{mmzautokey}
+ %
+ % In \hologo{LaTeX}, we finish the installation by submitting |\begin|; the
+ % submission is funky, because the run conditions handler actually hacks
+ % the standard handling procedure. Note that if |\begin| is not
+ % activated, environments will not be handled, and that the automatic
+ % activation might be deffered.
+ %<latex>#1/#2=\begin{run conditions=\advice@begin@rc},
+ }%
+}
+%
+%
+% \subsubsection{Submitting a command or environment}
+% \label{sec:code:advice:setup}
+%
+% \begin{macro}{\AdviceSetup,\AdviceName,\AdviceType}
+% Macro |\advice@setup| is called by key |auto| to submit a command or
+% environment to advising. It receives four arguments: |#1| is the
+% installation keypath / storage namespace: |#2| is the name of the setup
+% key; |#3| is the submitted command or environment; |#4| is the setup code
+% (which is only grabbed by |\advice@setup@i|).
+%
+% Executing this macro defines macros |\AdviceName|, holding the control
+% sequence of the submitted command or the environment name, and |\AdviceType|,
+% holding |command| or |environment|; they are used to set up some initial
+% values, and may be used by user-defined keys in the |auto| path, as well
+% (see |/mmz/auto/noop| for an example). The macro then performs internal
+% initialization, and finally calls the second part, |\advice@setup@i|, with
+% the command's \emph{storage} name as the first argument.
+%
+% This macro also serves as the programmer's interface to |auto|, the idea
+% being that an advanced user may write code |#4| which defined the settings
+% macros (|\AdviceOuterHandler| etc.) without deploying |pgfkeys|. (Also note
+% that activation at the end only occurs through the |auto| interface.)
+\def\AdviceSetup#1#2#3{%
+ % Open a group, so that we allow for embedded |auto| invocations.
+ \begingroup
+ \def\AdviceName{#3}%
+ % Command, complain, or environment?
+ \collargs@cs@cases{#3}{%
+ \def\AdviceType{command}%
+ \advice@setup@init@command
+ \advice@setup@i{#3}{#1}{#3}%
+ }{%
+ \advice@error@advice@notcs{#1/#2}{#3}%
+ }{%
+ \def\AdviceType{environment}%
+ \advice@setup@init@environment
+ %<latex>\advice@setup@i{#3}%
+ %<plain>\expandafter\advice@setup@i\expandafter{\csname #3\endcsname}%
+ %<context>\expandafter\advice@setup@i\expandafter{\csname start#3\endcsname}%
+ {#1}{#3}%
+ }%
+}
+% The arguments of |\advice@setup@i| are a bit different than for
+% |\advice@setup|, because we have inserted the storage name as |#1| above, and
+% we lost the setup key name |#2|. Here, |#2| is the installation keypath /
+% storage namespace, |#3| is the submitted command or environment; and |#4| is
+% the setup code.
+%
+% What is the difference between the storage name (|#1|) and the command\slash
+% environment name (|#3|, and also the contents of |\AdviceName|), and why do we
+% need both? For commands, there is actually no difference; for example, when
+% submitting command |\foo|, we end up with |#1|=|#3|=|\foo|. And there is
+% also no difference for \hologo{LaTeX} environments; when submitting
+% environment |foo|, we get |#1|=|#3|=|foo|. But in \hologo{plainTeX},
+% |#1|=|\foo| and |#3|=|foo|, and in \hologo{ConTeXt}, |#1|=|\startfoo| and
+% |#3|=|foo| --- which should explain the guards and |\expandafter|s above.
+%
+% And why both |#1| and |#3|? When a handled command is executed, it loads its
+% configuration from a macro determined by the storage namespace and the
+% (|\string|ified) storage name, e.g.\ |/mmz| and |\foo|. In \hologo{plainTeX}
+% and \hologo{ConTeXt}, each environment is started by a dedicated command,
+% |\foo| or |\startfoo|, so these control sequences (|\string|ified) must act
+% as storage names. (Not so in \hologo{LaTeX}, where an environment
+% configuration is loaded by |\begin|'s handler, which can easily work with
+% storage name |foo|. Even more, having |\foo| as an environment storage
+% name would conflict with the storage name for the (environment-internal)
+% command |\foo| --- yes, we can submit either |foo| or |\foo|, or both, to
+% advising.)
+\def\advice@setup@i#1#2#3#4{%
+ % Load the current configuration of the handled command or environment --- if
+ % it exists.
+ \advice@setup@init@i{#2}{#1}%
+ \advice@setup@init@I{#2}{#1}%
+ \def\AdviceAfterSetup{}%
+ % Apply the setup code/keys.
+ #4%
+ % Save the resulting configuration. This closes the group, because the config
+ % is saved outside it.
+ \advice@setup@save{#2}{#1}%
+}
+% \end{macro}
+%
+% \paragraph{Initialize} the configuration of a command or environment. Note
+% that the default values of the keys equal the initial values for commands.
+% Nothing would go wrong if these were not the same, but it's nice that the
+% end-user can easily revert to the initial values.
+\def\advice@setup@init@common{%
+ \def\AdviceRunConditions{\AdviceRuntrue}%
+ \def\AdviceBailoutHandler{\relax}%
+ \def\AdviceOuterHandler{\advice@default@outer@handler}%
+ \def\AdviceCollector{\advice@CollectArgumentsRaw}%
+ \def\AdviceCollectorOptions{}%
+ \def\AdviceInnerHandler{\advice@error@noinnerhandler}%
+ \def\AdviceOptions{}%
+}
+\def\advice@setup@init@command{%
+ \advice@setup@init@common
+ \def\AdviceRawCollectorOptions{}%
+ \def\AdviceArgs{\advice@noargs}%
+}
+\def\advice@setup@init@environment{%
+ \advice@setup@init@common
+ \edef\AdviceRawCollectorOptions{%
+ \noexpand\collargsEnvironment{\AdviceName}%
+ % When grabbing an environment body, the end-tag will be included. This
+ % makes it possible to have the same inner handler for commands and
+ % environments.
+ \noexpand\collargsEndTagtrue
+ }%
+ \def\AdviceArgs{+b}%
+}
+% We need to initialize |\AdviceOuterHandler| etc.\ so that |\advice@setup@store|
+% will work.
+\advice@setup@init@command
+%
+% \paragraph.{The configuration storage}
+%
+% The remaining macros in this subsection deal with the configuration storage
+% space, which is set up in a way to facilitate fast loading during the
+% execution of handled commands and environments.
+%
+% The configuration of a command or environment is stored in two parts: the
+% first stage settings comprise the run conditions, the bailout handler and the
+% outer handler; the second stage settings contain the rest. When a handled
+% command is invoked, only the first stage settings are immediately loaded, for
+% speed; the second stage settings are only loaded if the run conditions are
+% satisfied.
+%
+% \begin{macro}{\advice@init@i,\advice@init@I}
+% The two-stage settings are stored in control sequences
+% |\advice@i|\meta{namespace}|//|\meta{storage name} and
+% |\advice@I|\meta{namespace}|//|\meta{storage name}, respectively, and
+% accessed using macros |\advice@init@i| and |\advice@init@I|.
+%
+% Each setting storage macro contains a sequence of items, where each item is
+% either of form |\def\AdviceSetting|\marg{value}. This allows us store
+% multiple settings in a single macro (rather than define each
+% control-sequence-valued setting separately, which would use more string
+% memory), and also has the consequence that we don't require the handlers to
+% be defined when submitting a command (whether that's good or bad could be
+% debated: as things stand, any typos in handler declarations will only yield
+% an error once the handled command is executed).
+\def\advice@init@i#1#2{\csname advice@i#1//\string#2\endcsname}
+\def\advice@init@I#1#2{\csname advice@I#1//\string#2\endcsname}
+% We make a copy of these for setup; the originals might be swapped for
+% tracing purposes.
+\let\advice@setup@init@i\advice@init@i
+\let\advice@setup@init@I\advice@init@I
+% \end{macro}
+%
+% \begin{macro}{\advice@setup@save}
+% To save the configuration at the end of the setup, we construct the storage
+% macros out of |\AdviceRunConditions| and friends. Stage-one contains only
+% |\AdviceRunConditions| and |\AdviceBailoutHandler|, so that
+% |\advice@handle| can bail out as quickly as possible if the run conditions
+% are not met.
+\def\advice@setup@save#1#2{%
+ \expanded{%
+ % Close the group before saving. Note that |\expanded| has already expanded
+ % the settings macros.
+ \endgroup
+ \noexpand\csdef{advice@i#1//\string#2}{%
+ \def\noexpand\AdviceRunConditions{\expandonce\AdviceRunConditions}%
+ \def\noexpand\AdviceBailoutHandler{\expandonce\AdviceBailoutHandler}%
+ }%
+ \noexpand\csdef{advice@I#1//\string#2}{%
+ \def\noexpand\AdviceOuterHandler{\expandonce\AdviceOuterHandler}%
+ \def\noexpand\AdviceCollector{\expandonce\AdviceCollector}%
+ \def\noexpand\AdviceRawCollectorOptions{\expandonce\AdviceRawCollectorOptions}%
+ \def\noexpand\AdviceCollectorOptions{\expandonce\AdviceCollectorOptions}%
+ \def\noexpand\AdviceArgs{\expandonce\AdviceArgs}%
+ \def\noexpand\AdviceInnerHandler{\expandonce\AdviceInnerHandler}%
+ \def\noexpand\AdviceOptions{\expandonce\AdviceOptions}%
+ }%
+ \expandonce{\AdviceAfterSetup}%
+ }%
+}
+% \end{macro}
+% \label{sec:code:advice:activation}
+%
+% \begin{advicekey}{activation/immediate, activation/deferred}
+% The two subkeys of |/advice/activation| install the immediate and the
+% deferred activation code into the installation keypath. They are invoked
+% by \meta{installation keypath}|/activation=|\meta{type}.
+%
+% Under the deferred activation regime, the commands are not (de)activated
+% right away. Rather, the (de)activation calls are collected in style
+% |activate deferred|, which should be executed by the installation keypath
+% owner, if and when they so desire. (Be sure to switch to
+% |activation=immediate| before executing |activate deferred|, otherwise the
+% activation will only be deferred once again.)
+\pgfkeys{
+ /advice/activation/deferred/.style={
+ #1/activate/.style={%
+ activate deferred/.append style={#1/activate={##1}}},
+ #1/deactivate/.style={%
+ activate deferred/.append style={#1/deactivate={##1}}},
+ #1/force activate/.style={%
+ activate deferred/.append style={#1/force activate={##1}}},
+ #1/try activate/.style={%
+ activate deferred/.append style={#1/try activate={##1}}},
+ },
+% \end{advicekey}
+%
+% \begin{key}{activate, deactivate, force activate, try activate}
+% The ``real,'' immediate |activate| and |deactivate| take a comma-separated
+% list of commands or environments and (de)activate them. If |try activate|
+% is in effect, no error is thrown upon failure. If |force activate| is in
+% effect, activation proceeds even if we already had the original definition;
+% it does not apply to deactivation. These conditionals are set to false
+% after every invocation of key |(de)activate|, so that they only apply to
+% the immediately following |(de)activate|. (|#1| below is the
+% \meta{namespace}; |##1| is the list of commands to be (de)activated.)
+ /advice/activation/immediate/.style={
+ #1/activate/.code={%
+ \forcsvlist{\advice@activate{#1}}{##1}%
+ \advice@activate@forcefalse
+ \advice@activate@tryfalse
+ },
+ #1/deactivate/.code={%
+ \forcsvlist{\advice@deactivate{#1}}{##1}%
+ \advice@activate@forcefalse
+ \advice@activate@tryfalse
+ },
+ #1/force activate/.is if=advice@activate@force,
+ #1/try activate/.is if=advice@activate@try,
+ },
+}
+\newif\ifadvice@activate@force
+\newif\ifadvice@activate@try
+% \end{key}
+%
+% \begin{macro}{\advice@original@csname,\advice@original@cs,\AdviceGetOriginal}
+% Activation replaces the original meaning of the handled command with our
+% definition. We store the original definition into control sequence
+% |\advice@o|\meta{namespace}|//|\meta{storage name} (with a |\string|ified
+% \meta{storage name}). Internally, during (de)activation and handling, we
+% access it using |\advice@original@csname| and |\advice@original@cs|. Publicly
+% it should always be accessed by |\AdviceGetOriginal|, which returns the
+% argument control sequence if that control sequence is not handled.
+%
+% Using the internal command outside the handling context, we could fall
+% victim to scenario such as the following. When we memoize something
+% containing a |\label|, the produced cc-memo contains code eventually
+% executing the original |\label|. If we called the original |\label| via
+% the internal macro there, and the user |deactivate|d |\label| on a
+% subsequent compilation, the cc-memo would not call |\label| anymore, but
+% |\relax|, resulting in a silent error. Using |\AdviceGetOriginal|, the
+% original |\label| will be executed even when not activated.
+%
+% However, not all is bright with |\AdviceGetOriginal|. Given an activated
+% control sequence (|#2|), a typo in the namespace argument (|#1|) will lead
+% to an infinite loop upon the execution of |\AdviceGetOriginal|. In the
+% manual, we recommend defining a namespace-specific macro to avoid such
+% typos.
+\def\advice@original@csname#1#2{advice@o#1//\string#2}
+\def\advice@original@cs#1#2{\csname advice@o#1//\string#2\endcsname}
+\def\AdviceGetOriginal#1#2{%
+ \ifcsname advice@o#1//\string#2\endcsname
+ \csname advice@o#1//\string#2\expandafter\endcsname
+ \else
+ \expandafter#2%
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@activate,\advice@deactivate}
+% These macros execute either the command, or the environment (de)activator.
+\def\advice@activate#1#2{%
+ \collargs@cs@cases{#2}%
+ {\advice@activate@cmd{#1}{#2}}%
+ {\advice@error@activate@notcsorenv{}{#1}}%
+ {\advice@activate@env{#1}{#2}}%
+}
+\def\advice@deactivate#1#2{%
+ \collargs@cs@cases{#2}%
+ {\advice@deactivate@cmd{#1}{#2}}%
+ {\advice@error@activate@notcsorenv{de}{#1}}%
+ {\advice@deactivate@env{#1}{#2}}%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@activate@cmd}
+% We are very careful when we're activating a command, because activating
+% means rewriting its original definition. Configuration by |auto| did not
+% touch the original command; activation will. So, the leitmotif of this
+% macro: safety first. (|#1| is the namespace, and |#2| is the command to be
+% activated.)
+\def\advice@activate@cmd#1#2{%
+ % Is the command defined?
+ \ifdef{#2}{%
+ % Yes, the command is defined. Let's see if it's safe to activate it.
+ % We'll do this by checking whether we have its original definition in our
+ % storage. If we do, this means that we have already activated the
+ % command. Activating it twice would lead to the loss of the original
+ % definition (because the second activation would store our own
+ % redefinition as the original definition) and consequently an infinite
+ % loop (because once --- well, if --- the handler tries to invoke the
+ % original command, it will execute itself all over).
+ \ifcsdef{\advice@original@csname{#1}{#2}}{%
+ % Yes, we have the original definition, so the safety check failed, and
+ % we shouldn't activate again. Unless \dots\ how does its current
+ % definition look like?
+ \advice@if@our@definition{#1}{#2}{%
+ % Well, the current definition of the command matches what we would put
+ % there ourselves. The command is definitely activated, and we refuse
+ % to activate again, as that would destroy the original definition.
+ \advice@activate@error@activated{#1}{#2}{Command}{already}%
+ }{%
+ % We don't recognize the current definition as our own code (despite
+ % the fact that we have surely activated the commmand before, given the
+ % result of the first safety check). It appears that someone else was
+ % playing fast and loose with the same command, and redefined it after
+ % our activation. (In fact, if that someone else was another instance
+ % of Advice, from another namespace, forcing the activation will result
+ % in the loss of the original definition and the infinite loop.) So it
+ % \emph{should} be safe to activate it (again) \dots\ but we won't do
+ % it unless the user specifically requested this using |force
+ % activate|. Note that without |force activate|, we would be stuck in
+ % this branch, as we could neither activate (again) nor deactivate the
+ % command.
+ \ifadvice@activate@force
+ \advice@activate@cmd@do{#1}{#2}%
+ \else
+ \advice@activate@error@activated{#1}{#2}{Command}{already}%
+ \fi
+ }%
+ }{%
+ % No, we don't have the command's original definition, so it was not yet
+ % activated, and we may activate it.
+ \advice@activate@cmd@do{#1}{#2}%
+ }%
+ }{%
+ \advice@activate@error@undefined{#1}{#2}{Command}{}%
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@deactivate@cmd}
+% The deactivation of a command follows the same template as activation, but
+% with a different logic, and of course a different effect. In order to
+% deactivate a command, both safety checks discussed above must be satisfied:
+% we must have the command's original definition, \emph{and} our redefinition
+% must still reside in the command's control sequence --- the latter
+% condition prevents overwriting someone else's redefinition with the
+% original command. As both conditions must be unavoidably fulfilled, |force
+% activate| has no effect in deactivation (but |try activate| has).
+\def\advice@deactivate@cmd#1#2{%
+ \ifdef{#2}{%
+ \ifcsdef{\advice@original@csname{#1}{#2}}{%
+ \advice@if@our@definition{#1}{#2}{%
+ \advice@deactivate@cmd@do{#1}{#2}%
+ }{%
+ \advice@deactivate@error@changed{#1}{#2}%
+ }%
+ }{%
+ \advice@activate@error@activated{#1}{#2}{Command}{not yet}%
+ }%
+ }{%
+ \advice@activate@error@undefined{#1}{#2}{Command}{de}%
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@if@our@definition}
+% This macro checks whether control sequence |#2| was already activated (in
+% namespace |#1|) in the sense that its current definition contains the code
+% our activation would put there: |\advice@handle{#1}{#2}| (protected).
+\def\advice@if@our@definition#1#2{%
+ \protected\def\advice@temp{\advice@handle{#1}{#2}}%
+ \ifx#2\advice@temp
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@activate@cmd@do}
+% This macro saves the original command, and redefines its control sequence.
+% Our redefinition must be |\protected| --- even if the original command
+% wasn't fragile, our replacement certainly is. (Note that as we require
+% \hologo{eTeX} anyway, we don't have to pay attention to \hologo{LaTeX}'s
+% robust commands by redefining their ``inner'' command. Protecting our
+% replacement suffices.)
+\def\advice@activate@cmd@do#1#2{%
+ \cslet{\advice@original@csname{#1}{#2}}#2%
+ \protected\def#2{\advice@handle{#1}{#2}}%
+ \PackageInfo{advice (#1)}{Activated command "\string#2"}%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@deactivate@cmd@do}
+% This macro restores the original command, and removes its definition from
+% our storage --- this also serves as a signal that the command is not
+% activated anymore.
+\def\advice@deactivate@cmd@do#1#2{%
+ \letcs#2{\advice@original@csname{#1}{#2}}%
+ \csundef{\advice@original@csname{#1}{#2}}%
+ \PackageInfo{advice (#1)}{Deactivated command "\string#2"}%
+}
+% \end{macro}
+%
+%
+% \subsubsection{Executing a handled command}
+% \label{sec:code:advice:handle}
+%
+% \begin{macro}{\advice@handle}
+% An invocation of this macro is what replaces the original command and runs
+% the whole shebang. The system is designed to bail out as quickly as
+% necessary if the run conditions are not met (plus \hologo{LaTeX}'s |\begin|
+% will receive a very special treatment for this reason).
+%
+% We first check the run conditions, and bail out if they are not satisfied.
+% Note that only the stage-one config is loaded at this point. It sets up
+% the following macros (while they are public, neither the end user not the
+% installation keypath owner should ever have to use them):
+%
+% \begin{itemize}
+% \item \PrintMainMacro{\AdviceRunConditions} executes |\AdviceRuntrue| if the
+% command should be handled; set by |run conditions|.
+% \item \PrintMainMacro{\AdviceBailoutHandler} will be executed if the
+% command will not be handled, after all; set by |bailout handler|.
+% \end{itemize}
+\def\advice@handle#1#2{%
+ \advice@init@i{#1}{#2}%
+ \AdviceRunfalse
+ \AdviceRunConditions
+ \advice@handle@rc{#1}{#2}%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@handle@rc}
+% We continue the handling in a new macro, because this is the point where
+% the handler for |\begin| will hack into the regular flow of events.
+\def\advice@handle@rc#1#2{%
+ \ifAdviceRun
+ \expandafter\advice@handle@outer
+ \else
+ % Bailout is simple: we first execute the handler, and then the original command.
+ \AdviceBailoutHandler
+ \expandafter\advice@original@cs
+ \fi
+ {#1}{#2}%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@handle@outer}
+% To actually handle the command, we first setup some macros:
+%
+% \begin{itemize}
+% \item \PrintMainMacro{\AdviceNamespace} holds the installation keypath /
+% storage name space.
+% \item \PrintMainMacro{\AdviceName} holds the control sequence of the handled
+% command, or the environment name.
+% \item \PrintMainMacro{\AdviceReplaced} holds the ``substituted'' code. For
+% commands, this is the same as |\AdviceName|. For environment |foo|, it
+% equals |\begin{foo}| in \hologo{LaTeX}, |\foo| in \hologo{plainTeX} and
+% |\startfoo| in \hologo{ConTeXt}.
+% \item \PrintMainMacro{\AdviceOriginal} executes the original definition of
+% the handled command or environment.
+% \end{itemize}
+\def\advice@handle@outer#1#2{%
+ \def\AdviceNamespace{#1}%
+ \def\AdviceName{#2}%
+ \let\AdviceReplaced\AdviceName
+ \def\AdviceOriginal{\AdviceGetOriginal{#1}{#2}}%
+ % We then load the stage-two settings. This defines the following macros:
+ % \begin{itemize}
+ % \item \PrintMainMacro{\AdviceOuterHandler} will effectively replace the
+ % command, if it will be handled; set by |outer handler|.
+ % \item \PrintMainMacro{\AdviceCollector} collects the arguments of the handled
+ % command, perhaps consulting |\AdviceArgs| to learn about its argument
+ % structure.
+ % \item \PrintMainMacro{\AdviceRawCollectorOptions} contains the options which
+ % will be passed to the argument collector, in the ``raw'' format.
+ % \item \PrintMainMacro{\AdviceCollectorOptions} contains the additional,
+ % user-specified options which will be passed to the argument collector.
+ % \item \PrintMainMacro{\AdviceArgs} contains the |xparse|-style argument
+ % specification of the command, or equals |\advice@noargs| to signal that
+ % command was defined using |xparse| and that the argument specification
+ % should be retrieved automatically.
+ % \item \PrintMainMacro{\AdviceInnerHandler} is called by the argument
+ % collector once it finishes its work. It receives all the collected
+ % arguments as a single (braced) argument.
+ % \item \PrintMainMacro{\AdviceOptions} holds options which may be used by the
+ % outer or the inner handler; Advice does not need or touch
+ % them.
+ % \end{itemize}
+ \advice@init@I{#1}{#2}%
+ % All prepared, we execute the outer handler.
+ \AdviceOuterHandler
+}
+% \end{macro}
+%
+% \begin{macro}{\ifAdviceRun}
+% This conditional is set by the run conditions macro to signal whether we
+% should run the outer (true) or the bailout (false) handler.
+\newif\ifAdviceRun
+% \end{macro}
+%
+% \begin{macro}{\advice@default@outer@handler}
+% The default outer handler merely executes the argument collector. Note
+% that it works for both commands and environments.
+\def\advice@default@outer@handler{%
+ \AdviceCollector
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@CollectArgumentsRaw}
+% This is the default collector, which will collect the argument using
+% CollArgs' command |\CollectArgumentsRaw|. It will provide that command
+% with:
+% \begin{itemize}
+% \item the collector options, given in the raw format: the caller
+% (|\collargsCaller|), the raw options (|\AdviceRawCollectorOptions|) and the
+% user options (|\AdviceRawCollectorOptions|, wrapped in |\collargsSet|;
+% \item the argument specification |\AdviceArgs| of the handled command; and
+% \item the inner handler |\AdviceInnerHandler| to execute after collecting the
+% arguments; the inner handler receives the collected arguments as a single
+% braced argument.
+% \end{itemize}
+% If the argument specification is not defined (either the user did not set
+% it, or has reset it by writing |args| without a value), it is assumed that
+% the handled command was defined by |xparse| and |\AdviceArgs| will be
+% retrieved by |\GetDocumentCommandArgSpec|.
+% \begin{listingregion}{_advice-CollectArgumentsRaw.tex}
+\def\advice@CollectArgumentsRaw{%
+ \AdviceIfArgs{}{%
+ \expandafter\GetDocumentCommandArgSpec\expandafter{\AdviceName}%
+ \let\AdviceArgs\ArgumentSpecification
+ }%
+ \expanded{%
+ \noexpand\CollectArgumentsRaw{%
+ \noexpand\collargsCaller{\expandonce\AdviceName}%
+ \expandonce\AdviceRawCollectorOptions
+ \ifdefempty\AdviceCollectorOptions{}{%
+ \noexpand\collargsSet{\expandonce\AdviceCollectorOptions}%
+ }%
+ }%
+ {\expandonce\AdviceArgs}%
+ {\expandonce\AdviceInnerHandler}%
+ }%
+}
+% \end{listingregion}
+% \end{macro}
+%
+% \begin{macro}{\AdviceIfArgs}
+% If the value of |args| is ``real'', i.e.\ an |xparse| argument
+% specification, execute the first argument. If |args| was set to the
+% special value |\advice@noargs|, signaling a command defined by
+% |\NewDocumentCommand| or friends, execute the second argument. (Ok, in
+% reality anything other than |\advice@noargs| counts as real ``real''.)
+\def\advice@noargs@text{\advice@noargs}
+\def\AdviceIfArgs{%
+ \ifx\AdviceArgs\advice@noargs@text
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@pgfkeys@collector}
+% A |pgfkeys| collector is very simple: the sole argument of the any key
+% macro, regardless of the argument structure of the key, is everything up to
+% |\pgfeov|.
+\def\advice@pgfkeys@collector#1\pgfeov{%
+ \AdviceInnerHandler{#1}%
+}
+% \end{macro}
+%
+% \subsubsection{Environments}
+% \label{sec:code:advice:environments}
+%
+% \begin{macro}{\advice@activate@env,\advice@deactivate@env}
+% Things are simple in \hologo{TeX} and \hologo{ConTeXt}, as their environments
+% are really commands. So rather than activating environment name |#2|, we
+% (de)activate command |\#2| or |\start#2|, depending on the format.
+%<*plain,context>
+\def\advice@activate@env#1#2{%
+ \expanded{%
+ \noexpand\advice@activate@cmd{#1}{\expandonce{\csname
+ %<context>start%
+ #2\endcsname}}%
+ }%
+}
+\def\advice@deactivate@env#1#2{%
+ \expanded{%
+ \noexpand\advice@deactivate@cmd{#1}{\expandonce{\csname
+ %<context>start%
+ #2\endcsname}}%
+ }%
+}
+%</plain,context>
+%
+% We activate commands by redefining them; that's the only way to do it. But
+% we won't activate a \hologo{LaTeX} environment |foo| by redefining command
+% |\foo|, where the user's definition for the start of the environment actually
+% resides, as such a redefinition would be executed too late, deep within the
+% group opened by |\begin|, following many internal operations and public
+% hooks. We handle \hologo{LaTeX} environments by defining an outer handler
+% for |\begin| (consequently, \hologo{LaTeX} environment support can be
+% (de)activated by the user by saying (|de|)|activate=\begin|), and
+% activating an environment will be nothing but setting a mark, by
+% defining a dummy control sequence |\advice@original@csname{#1}{#2}|,
+% which that handler will inspect. Note that |force activate| has no
+% effect here.
+%<*latex>
+\def\advice@activate@env#1#2{%
+ \ifcsdef{\advice@original@csname{#1}{#2}}{%
+ \advice@activate@error@activated{#1}{#2}{Environment}{already}%
+ }{%
+ \csdef{\advice@original@csname{#1}{#2}}{}%
+ }%
+}
+\def\advice@deactivate@env#1#2{%
+ \ifcsdef{\advice@original@csname{#1}{#2}}{%
+ \csundef{\advice@original@csname{#1}{#2}}{}%
+ }{%
+ \advice@activate@error@activated{#1}{#2}{Environment}{not yet}%
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@begin@rc}
+% This is the handler for |\begin|. It is very special, for speed. It is
+% meant to be declared as the run conditions component, and it hacks into
+% the normal flow of handling. It knows that after executing the run
+% conditions macro, |\advice@handle| eventually (the tracing info may
+% interrupt here as |#1|) continues by
+% |\advice@handle@rc|\marg{namespace}\marg{handled control sequence}, so it
+% grabs all these (|#2| is the \meta{namespace} and |#3| is the
+% \meta{handled control sequence}, i.e.\ |\begin|) plus the environment
+% name (|#4|).
+\def\advice@begin@rc#1\advice@handle@rc#2#3#4{%
+ % We check whether environment |#4| is activated (in namespace |#2|) by
+ % inspecting whether activation dummy is defined. If it is not, we execute
+ % the original |\begin| (|\advice@original@cs{#2}{#3}|), followed by the
+ % environment name (|#4|). Note that we \emph{don't} execute the
+ % environment's bailout handler here: we haven't checked its run conditions
+ % yet, as the environment is simply not activated.
+ \ifcsname\advice@original@csname{#2}{#4}\endcsname
+ \expandafter\advice@begin@env@rc
+ \else
+ \expandafter\advice@original@cs
+ \fi
+ {#2}{#3}{#4}%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@begin@env@rc}
+% Starting from this point, we essentially replicate the workings of
+% |\advice@handle|, adapted to \hologo{LaTeX} environments.
+\def\advice@begin@env@rc#1#2#3{%
+ % We first load the stage-one configuration for environment |#3| in namespace
+ % |#1|.
+ \advice@init@i{#1}{#3}%
+ % This defined |\AdviceRunConditions| for the environment. We can now check its
+ % run conditions. If they are not satisfied, we bail out by executing the
+ % environment's bailout handler followed by the original |\begin|
+ % (|\advice@original@cs{#1}{#2}|) plus the environment name (|#3|).
+ \AdviceRunConditions
+ \ifAdviceRun
+ \expandafter\advice@begin@env@outer
+ \else
+ \AdviceBailoutHandler
+ \expandafter\advice@original@cs
+ \fi
+ {#1}{#2}{#3}%
+}
+% \end{macro}
+%
+% \begin{macro}{\advice@begin@env@outer}
+% We define the macros expected by the outer handler, see
+% |\advice@handle@outer|, load the second-stage configuration, and execute the
+% environment's outer handler.
+\def\advice@begin@env@outer#1#2#3{%
+ \def\AdviceNamespace{#1}%
+ \def\AdviceName{#3}%
+ \def\AdviceReplaced{#2{#3}}%
+ \def\AdviceOriginal{\AdviceGetOriginal{#1}{#2}{#3}}%
+ \advice@init@I{#1}{#3}%
+ \AdviceOuterHandler
+}
+%</latex>
+% \end{macro}
+%
+%
+% \subsubsection{Error messages}
+%
+% Define error messages for the entire package. Note that
+% |\advice@(de)activate@error@...| implement |try activate|.
+%
+\def\advice@activate@error@activated#1#2#3#4{%
+ \ifadvice@activate@try
+ \else
+ \PackageError{advice (#1)}{#3 "\string#2" is #4 activated}{}%
+ \fi
+}
+\def\advice@activate@error@undefined#1#2#3#4{%
+ \ifadvice@activate@try
+ \else
+ \PackageError{advice (#1)}{%
+ #3 "\string#2" you are trying to #4activate is not defined}{}%
+ \fi
+}
+\def\advice@deactivate@error@changed#1#2{%
+ \ifadvice@activate@try
+ \else
+ \PackageError{advice (#1)}{The definition of "\string#2" has changed since we
+ have activated it. Has somebody overridden our command?}{If you have tried
+ to deactivate so that you could immediately reactivate, you may want to try
+ "force activate".}%
+ \fi
+}
+\def\advice@error@advice@notcs#1#2{%
+ \PackageError{advice}{The first argument of key "#1" should be either a single
+ control sequence or an environment name, not "#2"}{}%
+}
+\def\advice@error@activate@notcsorenv#1#2{%
+ \PackageError{advice}{Each item in the value of key "#1activate" should be
+ either a control sequence or an environment name, not "#2".}{}%
+}
+\def\advice@error@storecs@notcs#1#2{%
+ \PackageError{advice}{The value of key "#1" should be a single control sequence,
+ not "\string#2"}{}%
+}
+\def\advice@error@noinnerhandler#1{%
+ \PackageError{advice (\AdviceNamespace)}{The inner handler for
+ "\expandafter\string\AdviceName" is not defined}{}%
+}
+% \subsubsection{Tracing}
+%
+% \begin{macro}{\AdviceTracingOn,\AdviceTracingOff}
+% We implement tracing by adding the tracing information to the handlers
+% after we load them. So it is the handlers themselves which, if and when
+% they are executed, will print out that this is happening.
+\def\AdviceTracingOn{%
+ \let\advice@init@i\advice@trace@init@i
+ \let\advice@init@I\advice@trace@init@I
+}
+\def\AdviceTracingOff{%
+ \let\advice@init@i\advice@setup@init@i
+ \let\advice@init@I\advice@setup@init@I
+}
+% \end{macro}
+\def\advice@trace#1{\immediate\write16{[tracing advice] #1}}
+\def\advice@trace@init@i#1#2{%
+ \advice@trace{Advising \detokenize\expandafter{\string#2} (\detokenize{#1})}%
+ \advice@setup@init@i{#1}{#2}%
+ \edef\AdviceRunConditions{%
+ % We first execute the original run conditions, so that we can show the
+ % result.
+ \expandonce\AdviceRunConditions
+ \noexpand\advice@trace{\space\space
+ Executing run conditions:
+ \detokenize\expandafter{\AdviceRunConditions}
+ -->
+ \noexpand\ifAdviceRun true\noexpand\else false\noexpand\fi
+ }%
+ }%
+ \edef\AdviceBailoutHandler{%
+ \noexpand\advice@trace{\space\space
+ Executing bailout handler:
+ \detokenize\expandafter{\AdviceBailoutHandler}}%
+ \expandonce\AdviceBailoutHandler
+ }%
+}
+\def\advice@trace@init@I#1#2{%
+ \advice@setup@init@I{#1}{#2}%
+ \edef\AdviceOuterHandler{%
+ \noexpand\advice@trace{\space\space
+ Executing outer handler:
+ \detokenize\expandafter{\AdviceOuterHandler}}%
+ \expandonce\AdviceOuterHandler
+ }%
+ \edef\AdviceCollector{%
+ \noexpand\advice@trace{\space\space
+ Executing collector:
+ \detokenize\expandafter{\AdviceCollector}}%
+ \noexpand\advice@trace{\space\space\space\space
+ argument specification:
+ \detokenize\expandafter{\AdviceArgs}}%
+ \noexpand\advice@trace{\space\space\space\space
+ options:
+ \detokenize\expandafter{\AdviceCollectorOptions}}%
+ \noexpand\advice@trace{\space\space\space\space
+ raw options:
+ \detokenize\expandafter{\AdviceRawCollectorOptions}}%
+ \expandonce\AdviceCollector
+ }%
+ % The tracing inner handler must grab the provided argument, if it's to show
+ % what it is.
+ \edef\advice@inner@handler@trace##1{%
+ \noexpand\advice@trace{\space\space
+ Executing inner handler:
+ \detokenize\expandafter{\AdviceInnerHandler}}%
+ \noexpand\advice@trace{\space\space\space\space
+ Received arguments:
+ \noexpand\detokenize{##1}}%
+ \noexpand\advice@trace{\space\space\space\space
+ options:
+ \detokenize\expandafter{\AdviceOptions}}%
+ \expandonce{\AdviceInnerHandler}{##1}%
+ }%
+ \def\AdviceInnerHandler{\advice@inner@handler@trace}%
+}
+%<plain>\resetatcatcode
+%<context>\stopmodule
+%<context>\protect
+%</main>
+%
+% \subsubsection{The \TikZ; collector}
+% \label{sec:code:advice:tikz}
+%
+% In this section, we implement the argument collector for command |\tikz|,
+% which has idiosyncratic syntax, see \PGFmanual{12.2.2}:
+% \begin{itemize}
+% \item |\tikz|\meta{animation spec}|[|\meta{options}|]{|\meta{picture code}|}|
+% \item |\tikz|\meta{animation spec}|[|\meta{options}|]|\meta{picture command}|;|
+% \end{itemize}
+% where \meta{animation spec} =
+% (|:|\meta{key}|={|\meta{value}|}|)*.
+%
+% The \TikZ; code resides in a special file. It is meant to be |\input| at any
+% time, so we need to temporarily assign |@| category code 11.
+%<*tikz>
+\edef\mmzresetatcatcode{\catcode`\noexpand\@\the\catcode`\@\relax}%
+\catcode`\@=11
+\def\AdviceCollectTikZArguments{%
+% We initialize the token register which will hold the collected arguments, and
+% start the collection. Nothing of note happens until \dots
+ \mmz@temptoks={}%
+ \mmz@tikz@anim
+}
+\def\mmz@tikz@anim{%
+ \pgfutil@ifnextchar[{\mmz@tikz@opt}{%
+ \pgfutil@ifnextchar:{\mmz@tikz@anim@a}{%
+ \mmz@tikz@code}}%]
+}
+\def\mmz@tikz@anim@a#1=#2{%
+ \toksapp\mmz@temptoks{#1={#2}}%
+ \mmz@tikz@anim
+}
+\def\mmz@tikz@opt[#1]{%
+ \toksapp\mmz@temptoks{[#1]}%
+ \mmz@tikz@code
+}
+\def\mmz@tikz@code{%
+ \pgfutil@ifnextchar\bgroup\mmz@tikz@braced\mmz@tikz@single
+}
+\long\def\mmz@tikz@braced#1{\toksapp\mmz@temptoks{{#1}}\mmz@tikz@done}
+\def\mmz@tikz@single#1;{\toksapp\mmz@temptoks{#1;}\mmz@tikz@done}
+% \dots\ we finish collecting the arguments, when we execute the inner handler,
+% with the (braced) collected arguments is its sole argument.
+\def\mmz@tikz@done{%
+ \expandafter\AdviceInnerHandler\expandafter{\the\mmz@temptoks}%
+}
+\mmzresetatcatcode
+%</tikz>
+% \end{macrocode}
+%
+% Local Variables:
+% TeX-engine: luatex
+% TeX-master: "doc/memoize-code.tex"
+% TeX-auto-save: nil
+% End: \ No newline at end of file
diff --git a/macros/generic/advice/advice.ins b/macros/generic/advice/advice.ins
new file mode 100644
index 0000000000..b1b1df68ce
--- /dev/null
+++ b/macros/generic/advice/advice.ins
@@ -0,0 +1,33 @@
+%% advice.ins
+%%
+%% This file is a part of Advice, a TeX package implementing a generic
+%% framework for extending the functionality of selected commands and
+%% environments, available at https://ctan.org/pkg/advice and
+%% https://github.com/sasozivanovic/advice.
+%%
+%% Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in `FILES`.
+%%
+\input docstrip.tex
+\keepsilent
+\preamble
+\endpreamble
+\askforoverwritefalse
+\generate{%
+ \file{advice.sty}{\from{advice.dtx}{main,latex}}%
+ \file{advice.tex}{\from{advice.dtx}{main,plain}}%
+ \file{t-advice.tex}{\from{advice.dtx}{main,context}}%
+ \file{advice-tikz.code.tex}{\from{advice.dtx}{tikz}}%
+}
+\endbatchfile
diff --git a/macros/generic/collargs/INSTALL.md b/macros/generic/collargs/INSTALL.md
new file mode 100644
index 0000000000..df93bc8214
--- /dev/null
+++ b/macros/generic/collargs/INSTALL.md
@@ -0,0 +1,68 @@
+# Installation from the TDS archive
+
+If CollArgs is not (yet) offered by your TeX distribution, the easiest way to
+install it is by downloading the TDS archive `collargs.tds.zip` from
+[CollArgs's CTAN page](https://ctan.org/pkg/collargs), and unpacking it into
+your `texmf` directory.
+
+Read on only if you have an unstoppable urge to install from source and/or
+compile the manual or the documented source code.
+
+# Installation from the source
+
+## Getting the sources
+
+There are several options:
+
+* Download and unpack the zip archive of the package from [CollArgs's CTAN
+ page](https://ctan.org/pkg/collargs).
+
+* Download and unpack the TDS archive, or copy the files from your local
+ distribution. The sources reside in `<texmf>/source/generic/collargs`.
+
+* Clone the [GitHub repository of
+ Memoize](https://github.com/sasozivanovic/memoize).
+
+## Generating the runtime files
+
+The easiest way to generate the runtime files is by running `make`. The
+following command will generate runtime files for all supported formats
+(currently: LaTeX, plain TeX and ConTeXt).
+
+```
+make collargs.sty
+```
+
+Alternatively, you can generate these files manually. The source of this
+package was written using [EasyDTX](https://ctan.org/pkg/easydtx). Therefore,
+you first have to convert the `.edtx` file into a regular `.dtx`:
+
+```
+edtx2dtx collargs.edtx > collargs.dtx
+```
+
+The next step is standard. Produce the runtime files by compiling the
+installation file:
+
+```
+tex collargs.ins
+```
+
+Finally, if you require the ConTeXt runtime, replace all instances of
+`\expanded` and `\unexpanded` in `t-collargs.tex` by `\normalexpanded` and
+`\normalunexpanded`, respectively. One way to do this is:
+
+```
+sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-collargs.tex
+```
+
+## Installation
+
+It is recommended to install the files into a TDS-compliant `texmf` directory,
+as usual. Inspect file `FILES` or the TDS archive `collargs.tds.zip` to see
+what goes where.
+
+# Compiling the documentation
+
+The documentation of this package is integrated into the documentation of
+[Memoize](https://ctan.org/pkg/memoize), please continue there.
diff --git a/macros/generic/collargs/LICENCE b/macros/generic/collargs/LICENCE
new file mode 100644
index 0000000000..1b57559a83
--- /dev/null
+++ b/macros/generic/collargs/LICENCE
@@ -0,0 +1,416 @@
+The LaTeX Project Public License
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+LPPL Version 1.3c 2008-05-04
+
+Copyright 1999 2002-2008 LaTeX3 Project
+ Everyone is allowed to distribute verbatim copies of this
+ license document, but modification of it is not allowed.
+
+
+PREAMBLE
+========
+
+The LaTeX Project Public License (LPPL) is the primary license under
+which the LaTeX kernel and the base LaTeX packages are distributed.
+
+You may use this license for any work of which you hold the copyright
+and which you wish to distribute. This license may be particularly
+suitable if your work is TeX-related (such as a LaTeX package), but
+it is written in such a way that you can use it even if your work is
+unrelated to TeX.
+
+The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
+below, gives instructions, examples, and recommendations for authors
+who are considering distributing their works under this license.
+
+This license gives conditions under which a work may be distributed
+and modified, as well as conditions under which modified versions of
+that work may be distributed.
+
+We, the LaTeX3 Project, believe that the conditions below give you
+the freedom to make and distribute modified versions of your work
+that conform with whatever technical specifications you wish while
+maintaining the availability, integrity, and reliability of
+that work. If you do not see how to achieve your goal while
+meeting these conditions, then read the document `cfgguide.tex'
+and `modguide.tex' in the base LaTeX distribution for suggestions.
+
+
+DEFINITIONS
+===========
+
+In this license document the following terms are used:
+
+ `Work'
+ Any work being distributed under this License.
+
+ `Derived Work'
+ Any work that under any applicable law is derived from the Work.
+
+ `Modification'
+ Any procedure that produces a Derived Work under any applicable
+ law -- for example, the production of a file containing an
+ original file associated with the Work or a significant portion of
+ such a file, either verbatim or with modifications and/or
+ translated into another language.
+
+ `Modify'
+ To apply any procedure that produces a Derived Work under any
+ applicable law.
+
+ `Distribution'
+ Making copies of the Work available from one person to another, in
+ whole or in part. Distribution includes (but is not limited to)
+ making any electronic components of the Work accessible by
+ file transfer protocols such as FTP or HTTP or by shared file
+ systems such as Sun's Network File System (NFS).
+
+ `Compiled Work'
+ A version of the Work that has been processed into a form where it
+ is directly usable on a computer system. This processing may
+ include using installation facilities provided by the Work,
+ transformations of the Work, copying of components of the Work, or
+ other activities. Note that modification of any installation
+ facilities provided by the Work constitutes modification of the Work.
+
+ `Current Maintainer'
+ A person or persons nominated as such within the Work. If there is
+ no such explicit nomination then it is the `Copyright Holder' under
+ any applicable law.
+
+ `Base Interpreter'
+ A program or process that is normally needed for running or
+ interpreting a part or the whole of the Work.
+
+ A Base Interpreter may depend on external components but these
+ are not considered part of the Base Interpreter provided that each
+ external component clearly identifies itself whenever it is used
+ interactively. Unless explicitly specified when applying the
+ license to the Work, the only applicable Base Interpreter is a
+ `LaTeX-Format' or in the case of files belonging to the
+ `LaTeX-format' a program implementing the `TeX language'.
+
+
+
+CONDITIONS ON DISTRIBUTION AND MODIFICATION
+===========================================
+
+1. Activities other than distribution and/or modification of the Work
+are not covered by this license; they are outside its scope. In
+particular, the act of running the Work is not restricted and no
+requirements are made concerning any offers of support for the Work.
+
+2. You may distribute a complete, unmodified copy of the Work as you
+received it. Distribution of only part of the Work is considered
+modification of the Work, and no right to distribute such a Derived
+Work may be assumed under the terms of this clause.
+
+3. You may distribute a Compiled Work that has been generated from a
+complete, unmodified copy of the Work as distributed under Clause 2
+above, as long as that Compiled Work is distributed in such a way that
+the recipients may install the Compiled Work on their system exactly
+as it would have been installed if they generated a Compiled Work
+directly from the Work.
+
+4. If you are the Current Maintainer of the Work, you may, without
+restriction, modify the Work, thus creating a Derived Work. You may
+also distribute the Derived Work without restriction, including
+Compiled Works generated from the Derived Work. Derived Works
+distributed in this manner by the Current Maintainer are considered to
+be updated versions of the Work.
+
+5. If you are not the Current Maintainer of the Work, you may modify
+your copy of the Work, thus creating a Derived Work based on the Work,
+and compile this Derived Work, thus creating a Compiled Work based on
+the Derived Work.
+
+6. If you are not the Current Maintainer of the Work, you may
+distribute a Derived Work provided the following conditions are met
+for every component of the Work unless that component clearly states
+in the copyright notice that it is exempt from that condition. Only
+the Current Maintainer is allowed to add such statements of exemption
+to a component of the Work.
+
+ a. If a component of this Derived Work can be a direct replacement
+ for a component of the Work when that component is used with the
+ Base Interpreter, then, wherever this component of the Work
+ identifies itself to the user when used interactively with that
+ Base Interpreter, the replacement component of this Derived Work
+ clearly and unambiguously identifies itself as a modified version
+ of this component to the user when used interactively with that
+ Base Interpreter.
+
+ b. Every component of the Derived Work contains prominent notices
+ detailing the nature of the changes to that component, or a
+ prominent reference to another file that is distributed as part
+ of the Derived Work and that contains a complete and accurate log
+ of the changes.
+
+ c. No information in the Derived Work implies that any persons,
+ including (but not limited to) the authors of the original version
+ of the Work, provide any support, including (but not limited to)
+ the reporting and handling of errors, to recipients of the
+ Derived Work unless those persons have stated explicitly that
+ they do provide such support for the Derived Work.
+
+ d. You distribute at least one of the following with the Derived Work:
+
+ 1. A complete, unmodified copy of the Work;
+ if your distribution of a modified component is made by
+ offering access to copy the modified component from a
+ designated place, then offering equivalent access to copy
+ the Work from the same or some similar place meets this
+ condition, even though third parties are not compelled to
+ copy the Work along with the modified component;
+
+ 2. Information that is sufficient to obtain a complete,
+ unmodified copy of the Work.
+
+7. If you are not the Current Maintainer of the Work, you may
+distribute a Compiled Work generated from a Derived Work, as long as
+the Derived Work is distributed to all recipients of the Compiled
+Work, and as long as the conditions of Clause 6, above, are met with
+regard to the Derived Work.
+
+8. The conditions above are not intended to prohibit, and hence do not
+apply to, the modification, by any method, of any component so that it
+becomes identical to an updated version of that component of the Work as
+it is distributed by the Current Maintainer under Clause 4, above.
+
+9. Distribution of the Work or any Derived Work in an alternative
+format, where the Work or that Derived Work (in whole or in part) is
+then produced by applying some process to that format, does not relax or
+nullify any sections of this license as they pertain to the results of
+applying that process.
+
+10. a. A Derived Work may be distributed under a different license
+ provided that license itself honors the conditions listed in
+ Clause 6 above, in regard to the Work, though it does not have
+ to honor the rest of the conditions in this license.
+
+ b. If a Derived Work is distributed under a different license, that
+ Derived Work must provide sufficient documentation as part of
+ itself to allow each recipient of that Derived Work to honor the
+ restrictions in Clause 6 above, concerning changes from the Work.
+
+11. This license places no restrictions on works that are unrelated to
+the Work, nor does this license place any restrictions on aggregating
+such works with the Work by any means.
+
+12. Nothing in this license is intended to, or may be used to, prevent
+complete compliance by all parties with all applicable laws.
+
+
+NO WARRANTY
+===========
+
+There is no warranty for the Work. Except when otherwise stated in
+writing, the Copyright Holder provides the Work `as is', without
+warranty of any kind, either expressed or implied, including, but not
+limited to, the implied warranties of merchantability and fitness for a
+particular purpose. The entire risk as to the quality and performance
+of the Work is with you. Should the Work prove defective, you assume
+the cost of all necessary servicing, repair, or correction.
+
+In no event unless required by applicable law or agreed to in writing
+will The Copyright Holder, or any author named in the components of the
+Work, or any other party who may distribute and/or modify the Work as
+permitted above, be liable to you for damages, including any general,
+special, incidental or consequential damages arising out of any use of
+the Work or out of inability to use the Work (including, but not limited
+to, loss of data, data being rendered inaccurate, or losses sustained by
+anyone as a result of any failure of the Work to operate with any other
+programs), even if the Copyright Holder or said author or said other
+party has been advised of the possibility of such damages.
+
+
+MAINTENANCE OF THE WORK
+=======================
+
+The Work has the status `author-maintained' if the Copyright Holder
+explicitly and prominently states near the primary copyright notice in
+the Work that the Work can only be maintained by the Copyright Holder
+or simply that it is `author-maintained'.
+
+The Work has the status `maintained' if there is a Current Maintainer
+who has indicated in the Work that they are willing to receive error
+reports for the Work (for example, by supplying a valid e-mail
+address). It is not required for the Current Maintainer to acknowledge
+or act upon these error reports.
+
+The Work changes from status `maintained' to `unmaintained' if there
+is no Current Maintainer, or the person stated to be Current
+Maintainer of the work cannot be reached through the indicated means
+of communication for a period of six months, and there are no other
+significant signs of active maintenance.
+
+You can become the Current Maintainer of the Work by agreement with
+any existing Current Maintainer to take over this role.
+
+If the Work is unmaintained, you can become the Current Maintainer of
+the Work through the following steps:
+
+ 1. Make a reasonable attempt to trace the Current Maintainer (and
+ the Copyright Holder, if the two differ) through the means of
+ an Internet or similar search.
+
+ 2. If this search is successful, then enquire whether the Work
+ is still maintained.
+
+ a. If it is being maintained, then ask the Current Maintainer
+ to update their communication data within one month.
+
+ b. If the search is unsuccessful or no action to resume active
+ maintenance is taken by the Current Maintainer, then announce
+ within the pertinent community your intention to take over
+ maintenance. (If the Work is a LaTeX work, this could be
+ done, for example, by posting to comp.text.tex.)
+
+ 3a. If the Current Maintainer is reachable and agrees to pass
+ maintenance of the Work to you, then this takes effect
+ immediately upon announcement.
+
+ b. If the Current Maintainer is not reachable and the Copyright
+ Holder agrees that maintenance of the Work be passed to you,
+ then this takes effect immediately upon announcement.
+
+ 4. If you make an `intention announcement' as described in 2b. above
+ and after three months your intention is challenged neither by
+ the Current Maintainer nor by the Copyright Holder nor by other
+ people, then you may arrange for the Work to be changed so as
+ to name you as the (new) Current Maintainer.
+
+ 5. If the previously unreachable Current Maintainer becomes
+ reachable once more within three months of a change completed
+ under the terms of 3b) or 4), then that Current Maintainer must
+ become or remain the Current Maintainer upon request provided
+ they then update their communication data within one month.
+
+A change in the Current Maintainer does not, of itself, alter the fact
+that the Work is distributed under the LPPL license.
+
+If you become the Current Maintainer of the Work, you should
+immediately provide, within the Work, a prominent and unambiguous
+statement of your status as Current Maintainer. You should also
+announce your new status to the same pertinent community as
+in 2b) above.
+
+
+WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
+======================================================
+
+This section contains important instructions, examples, and
+recommendations for authors who are considering distributing their
+works under this license. These authors are addressed as `you' in
+this section.
+
+Choosing This License or Another License
+----------------------------------------
+
+If for any part of your work you want or need to use *distribution*
+conditions that differ significantly from those in this license, then
+do not refer to this license anywhere in your work but, instead,
+distribute your work under a different license. You may use the text
+of this license as a model for your own license, but your license
+should not refer to the LPPL or otherwise give the impression that
+your work is distributed under the LPPL.
+
+The document `modguide.tex' in the base LaTeX distribution explains
+the motivation behind the conditions of this license. It explains,
+for example, why distributing LaTeX under the GNU General Public
+License (GPL) was considered inappropriate. Even if your work is
+unrelated to LaTeX, the discussion in `modguide.tex' may still be
+relevant, and authors intending to distribute their works under any
+license are encouraged to read it.
+
+A Recommendation on Modification Without Distribution
+-----------------------------------------------------
+
+It is wise never to modify a component of the Work, even for your own
+personal use, without also meeting the above conditions for
+distributing the modified component. While you might intend that such
+modifications will never be distributed, often this will happen by
+accident -- you may forget that you have modified that component; or
+it may not occur to you when allowing others to access the modified
+version that you are thus distributing it and violating the conditions
+of this license in ways that could have legal implications and, worse,
+cause problems for the community. It is therefore usually in your
+best interest to keep your copy of the Work identical with the public
+one. Many works provide ways to control the behavior of that work
+without altering any of its licensed components.
+
+How to Use This License
+-----------------------
+
+To use this license, place in each of the components of your work both
+an explicit copyright notice including your name and the year the work
+was authored and/or last substantially modified. Include also a
+statement that the distribution and/or modification of that
+component is constrained by the conditions in this license.
+
+Here is an example of such a notice and statement:
+
+ %% pig.dtx
+ %% Copyright 2008 M. Y. Name
+ %
+ % This work 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
+ % https://www.latex-project.org/lppl.txt
+ % and version 1.3c or later is part of all distributions of LaTeX
+ % version 2008 or later.
+ %
+ % This work has the LPPL maintenance status `maintained'.
+ %
+ % The Current Maintainer of this work is M. Y. Name.
+ %
+ % This work consists of the files pig.dtx and pig.ins
+ % and the derived file pig.sty.
+
+Given such a notice and statement in a file, the conditions
+given in this license document would apply, with the `Work' referring
+to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
+generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
+referring to any `LaTeX-Format', and both `Copyright Holder' and
+`Current Maintainer' referring to the person `M. Y. Name'.
+
+If you do not want the Maintenance section of LPPL to apply to your
+Work, change `maintained' above into `author-maintained'.
+However, we recommend that you use `maintained', as the Maintenance
+section was added in order to ensure that your Work remains useful to
+the community even when you can no longer maintain and support it
+yourself.
+
+Derived Works That Are Not Replacements
+---------------------------------------
+
+Several clauses of the LPPL specify means to provide reliability and
+stability for the user community. They therefore concern themselves
+with the case that a Derived Work is intended to be used as a
+(compatible or incompatible) replacement of the original Work. If
+this is not the case (e.g., if a few lines of code are reused for a
+completely different task), then clauses 6b and 6d shall not apply.
+
+
+Important Recommendations
+-------------------------
+
+ Defining What Constitutes the Work
+
+ The LPPL requires that distributions of the Work contain all the
+ files of the Work. It is therefore important that you provide a
+ way for the licensee to determine which files constitute the Work.
+ This could, for example, be achieved by explicitly listing all the
+ files of the Work near the copyright notice of each file or by
+ using a line such as:
+
+ % This work consists of all files listed in manifest.txt.
+
+ in that place. In the absence of an unequivocal list it might be
+ impossible for the licensee to determine what is considered by you
+ to comprise the Work and, in such a case, the licensee would be
+ entitled to make reasonable conjectures as to which files comprise
+ the Work.
+
diff --git a/macros/generic/collargs/Makefile b/macros/generic/collargs/Makefile
new file mode 100644
index 0000000000..421bcdbfc9
--- /dev/null
+++ b/macros/generic/collargs/Makefile
@@ -0,0 +1,8 @@
+.PRECIOUS: %.dtx
+
+%.dtx: %.edtx
+ edtx2dtx $< > $@
+
+%.sty %.tex t-%.tex &: %.ins %.dtx
+ tex $<
+ sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-$*.tex
diff --git a/macros/generic/collargs/README.md b/macros/generic/collargs/README.md
new file mode 100644
index 0000000000..f36abea78a
--- /dev/null
+++ b/macros/generic/collargs/README.md
@@ -0,0 +1,8 @@
+Package CollArgs provides a command which can determine the argument scope of
+any command whose argument structure conforms to
+[xparse](https://ctan.org/pkg/xparse)'s argument specification.
+
+This package was developed as an auxiliary package of
+[Memoize](https://ctan.org/pkg/memoize). This is why it is, somewhat
+unconventionally, documented alongside that package. This applies to both the
+manual and the documented code listing.
diff --git a/macros/generic/collargs/collargs.edtx b/macros/generic/collargs/collargs.edtx
new file mode 100644
index 0000000000..40a102c1a8
--- /dev/null
+++ b/macros/generic/collargs/collargs.edtx
@@ -0,0 +1,2938 @@
+% \iffalse
+% collargs.edtx (this is not a .dtx file; to produce a .dtx, process it with edtx2dtx)
+%%
+%% This file is a part of CollArgs, a TeX package providing a command which can
+%% determine the argument scope of any command whose argument structure
+%% conforms to xparse's argument specification, available at
+%% https://ctan.org/pkg/advice and https://github.com/sasozivanovic/advice.
+%%
+%% Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work 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.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/collargs/)FILES.
+%
+% \fi
+%
+% \begin{macrocode}
+%
+% Package CollArgs provides commands |\CollectArguments| and
+% |\CollectArgumentsRaw|, which (what a surprise!) collect the arguments
+% conforming to the given (slightly extended) |xparse| argument specification.
+% The package was developed to help out with automemoization (see
+% section~\ref{sec:code:automemoization}). It started out as a few lines of
+% code, but had grown once I realized I want automemoization to work for
+% verbatim environments as well --- the environment-collecting code is based on
+% Bruno Le Floch's package |cprotect| --- and had then grown some more once I
+% decided to support the |xparse| argument specification in full detail, and to
+% make the verbatim mode flexible enough to deal with a variety of situations.
+%
+% The implementation of this package does not depend on |xparse|. Perhaps this
+% is a mistake, especially as the |xparse| code is now included in the base
+% \hologo{LaTeX}, but the idea was to have a light-weight package (not sure
+% this is the case anymore, given all the bells and whistles), to have its
+% functionality available in plain \hologo{TeX} and \hologo{ConTeXt} as well
+% (same as Memoize), and, perhaps most importantly, to have the ability to
+% collect the arguments verbatim.
+%
+%
+% \paragraph{Identification}
+%<latex>\ProvidesPackage{collargs}[2023/10/10 v1.0.0 Collect arguments of any command]
+%<context>%D \module[
+%<context>%D file=t-collargs.tex,
+%<context>%D version=1.0.0,
+%<context>%D title=CollArgs,
+%<context>%D subtitle=Collect arguments of any command,
+%<context>%D author=Saso Zivanovic,
+%<context>%D date=2023-10-10,
+%<context>%D copyright=Saso Zivanovic,
+%<context>%D license=LPPL,
+%<context>%D ]
+%<context>\writestatus{loading}{ConTeXt User Module / collargs}
+%<context>\unprotect
+%<context>\startmodule[collargs]
+% \paragraph{Required packages}
+%<latex>\RequirePackage{pgfkeys}
+%<plain>\input pgfkeys
+%<context>\input t-pgfkey
+%<latex>\RequirePackage{etoolbox}
+%<plain,context>\input etoolbox-generic
+%<plain>\edef\resetatcatcode{\catcode`\noexpand\@\the\catcode`\@\relax}
+%<plain>\catcode`\@11\relax
+%
+% \begin{macro}{\toksapp,\gtoksapp,\etoksapp,\xtoksapp}
+% Our macros for appending to a token register only accept a control sequence
+% defined by |\toksdef| (like |\mytoks|) but not an explicit register
+% designation like |\toks0|, so we only define them if noone else did; the
+% names of the macros match the \hologo{LuaTeX} primitives, so they surely
+% won't be defined there.
+\ifdefined\toksapp\else
+ \long\def\toksapp#1#2{#1\expandafter{\the#1#2}}%
+\fi
+\ifdefined\etoksapp\else
+ \long\def\etoksapp#1#2{#1\expandafter{\expanded{\the#1#2}}}%
+\fi
+\ifdefined\gtoksapp\else
+ \long\def\gtoksapp#1#2{\global#1\expandafter{\the#1#2}}%
+\fi
+\ifdefined\xtoksapp\else
+ \long\def\xtoksapp#1#2{\global#1\expandafter{\expanded{\the#1#2}}}%
+\fi
+\ifdefined\toks@\else\toksdef\toks@=0 \fi
+% \end{macro}
+%
+% \begin{macro}{\CollectArguments,\CollectArgumentsRaw}
+% These are the only public commands provided by the
+% package. |\CollectArguments| takes three arguments: the optional |#1| is
+% the option list, processed by |pgfkeys| (given the grouping structure,
+% these options will apply to all arguments); the mandatory |#2| is the
+% |xparse|-style argument specification; the mandatory |#3| is the ``next''
+% command (or a sequence of commands). The argument list is expected to
+% start immediately after the final argument; |\CollectArguments| parses it,
+% effectively figuring out its extent, and then passes the entire argument
+% list to the ``next'' command (as a single argument).
+%
+% |\CollectArgumentsRaw| differs only in how it takes and processes the
+% options. For one, these should be given as a mandatory argument.
+% Furthermore, they do not take the form of a keylist, but should deploy the
+% ``programmer's interface.'' |#1| should thus be a sequence of invocations
+% of the macro counterparts of the keys defined in
+% section~\ref{sec:code:collargs:keys}, which can be recognized as starting
+% with |\collargs| followed by a capital letter, e.g.\ |\collargsCaller|.
+% Note that |\collargsSet| may also be used in |#1|. (The ``optional,''
+% i.e.\ bracketed, argument of |\CollectArgumentsRaw| is in fact mandatory.)
+\protected\def\CollectArguments{%
+ \pgf@keys@utilifnextchar[\CollectArguments@i{\CollectArgumentsRaw{}}%]
+}
+\def\CollectArguments@i[#1]{\CollectArgumentsRaw{\collargsSet{#1}}}
+\protected\def\CollectArgumentsRaw#1#2#3{%
+ % This group will be closed by |\collargs@.| once we grinded through the
+ % argument specification.
+ \begingroup
+ % Initialize category code fixing; see section~\ref{sec:code:collargs:fix}
+ % for details. We have to do this before applying the settings, so that
+ % |\collargsFixFromNoVerbatim| et al can take effect.
+ \global\let\ifcollargs@last@verbatim\ifcollargs@verbatim
+ \global\let\ifcollargs@last@verbatimbraces\ifcollargs@verbatimbraces
+ \global\collargs@double@fixfalse
+ % Apply the settings.
+ \collargs@verbatim@wrap{#1}%
+ % Initialize the space-grabber.
+ \collargs@init@grabspaces
+ % Remember the code to execute after collection.
+ \def\collargs@next{#3}%
+ % Initialize the token register holding the collected arguments.
+ \global\collargs@toks{}%
+ % Execute the central loop macro, which expects the argument specification
+ % |#2| to be delimited from the following argument tokens by a dot.
+ \collargs@#2.%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargsSet}
+% This macro processes the given keys in the |/collargs| keypath. When it is
+% used to process options given by the end user (the optional argument to
+% |\CollectArguments|, and the options given within the argument
+% specification, using the new modifier |&|), its invocation should be
+% wrapped in |\collargs@verbatim@wrap| to correctly deal with the changes of
+% the verbatim mode.
+\def\collargsSet#1{\pgfqkeys{/collargs}{#1}}
+% \end{macro}
+%
+%
+% \subsubsection{The keys}
+% \label{sec:code:collargs:keys}
+%
+% \begin{macro}{\collargs@cs@cases}
+% If the first argument of this auxiliary macro is a single control sequence,
+% then the second argument is executed. If the first argument starts with a
+% control sequence but this control sequence does not form the entire
+% argument, the third argument is executed. Otherwise, the fourth argument
+% is executed.
+%
+% This macro is defined in package CollArgs because we use it in key |caller|
+% below, but it is really useful in package Auto, where having it we don't
+% have to bother the end-user with a separate keys for commands and
+% environments, but automatically detect whether the argument of |auto| and
+% (|de|)|activate| is a command or an environment.
+\def\collargs@cs@cases#1{\collargs@cs@cases@i#1\collargs@cs@cases@end}
+\let\collargs@cs@cases@end\relax
+\def\collargs@cs@cases@i{\futurelet\collargs@temp\collargs@cs@cases@ii}
+\def\collargs@cs@cases@ii#1#2\collargs@cs@cases@end{%
+ \ifcat\noexpand\collargs@temp\relax
+ \ifx\relax#2\relax
+ \expandafter\expandafter\expandafter\@firstofthree
+ \else
+ \expandafter\expandafter\expandafter\@secondofthree
+ \fi
+ \else
+ \expandafter\@thirdofthree
+ \fi
+}
+\def\@firstofthree#1#2#3{#1}
+\def\@secondofthree#1#2#3{#2}
+\def\@thirdofthree#1#2#3{#3}
+% \end{macro}
+%
+% \begin{collargskey}{caller}
+% \begin{macro}{\collargsCaller}
+% Every macro which grabs a part of the argument list will be accessed
+% through the ``caller'' control sequence, so that \hologo{TeX}'s reports
+% of any errors in the argument structure can contain a command name
+% familiar to the author.\footnote{The idea is borrowed from package
+% |environ|, which is in turn based on code from |amsmath|.} For example,
+% if the argument list ``originally'' belonged to command |\foo| with
+% argument structure |r()|, but no parentheses follow in the input, we want
+% \hologo{TeX} to complain that |Use of \foo doesn't match its definition|.
+% This can be achieved by setting |caller=\foo|; the default is
+% |caller=\CollectArguments|, which is still better than seeing an error
+% involving some random internal control sequence. It is also ok to set an
+% environment name as the caller, see below.
+%
+% The key and macro defined below store the caller control sequence into
+% |\collargs@caller|, e.g.\ when we say |caller=\foo|, we effectively
+% execute |\def\collargs@caller{\foo}|.
+\collargsSet{
+ caller/.code={\collargsCaller{#1}},
+}
+\def\collargsCaller#1{%
+ \collargs@cs@cases{#1}{%
+ \let\collargs@temp\collargs@caller@cs
+ }{%
+ \let\collargs@temp\collargs@caller@csandmore
+ }{%
+ \let\collargs@temp\collargs@caller@env
+ }%
+ \collargs@temp{#1}%
+}
+\def\collargs@caller@cs#1{%
+ % If |#1| is a single control sequence, just use that as the caller.
+ \def\collargs@caller{#1}%
+}
+\def\collargs@caller@csandmore#1{%
+ % If |#1| starts with a control sequence, we don't complain, but convert the
+ % entire |#1| into a control sequence.
+ \begingroup
+ \escapechar -1
+ \expandafter\endgroup
+ \expandafter\def\expandafter\collargs@caller\expandafter{%
+ \csname\string#1\endcsname
+ }%
+}
+\def\collargs@caller@env#1{%
+ % If |#1| does not start with a control sequence, we assume that is an
+ % environment name, so we prepend |start| in \hologo{ConTeXt}, and dress it
+ % up into |\begin{#1}| in \hologo{LaTeX}.
+ \expandafter\def\expandafter\collargs@caller\expandafter{%
+ \csname
+ %<context>start%
+ %<latex>begin{%
+ #1%
+ %<latex>}%
+ \endcsname
+ }%
+}
+\collargsCaller\CollectArguments
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{macro}{\ifcollargs@verbatim,\ifcollargs@verbatimbraces}
+% The first of these conditional
+% signals that we're collecting the arguments in one of the verbatim
+% modes; the second one signals the |verb| mode in particular.
+\newif\ifcollargs@verbatim
+\newif\ifcollargs@verbatimbraces
+% \end{macro}
+%
+% \begin{collargskey}{verbatim, verb, no verbatim}
+% \begin{macro}{\collargs@verbatim@wrap}
+% These keys set the verbatim mode macro which will be executed by
+% |\collargsSet| after processing all keys.
+% The verbatim mode macros |\collargsVerbatim|, |\collargsVerb| and
+% |\collargsNoVerbatim| are somewhat complex; we postpone their definition
+% until section~\ref{sec:code:collargs:verbatim}. Their main effect is to
+% set conditionals |\ifcollargs@verbatim| and |\ifcollargs@verbatimbraces|,
+% which are be inspected by the argument type handlers --- and to make
+% the requested category code changes, of course.
+%
+% Here, note that the verbatim-selection code is not executed while the
+% keylist is being processed. Rather, the verbatim keys simply set the macro
+% which will be executed \emph{after} the keylist is processed, and this is
+% why processing of a keylist given by the user must be always wrapped in
+% |\collargs@verbatim@wrap|.
+\collargsSet{
+ verbatim/.code={\let\collargs@apply@verbatim\collargsVerbatim},
+ verb/.code={\let\collargs@apply@verbatim\collargsVerb},
+ no verbatim/.code={\let\collargs@apply@verbatim\collargsNoVerbatim},
+}
+\def\collargs@verbatim@wrap#1{%
+ \let\collargs@apply@verbatim\relax
+ #1%
+ \collargs@apply@verbatim
+}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}{fix from verbatim, fix from verb, fix from no verbatim}
+% \begin{macro}{\collargsFixFromVerbatim,\collargsFixFromVerb,\collargsFixFromNoVerbatim}
+% These keys and macros should be used to request a category code fix, when
+% the offending tokenization took place prior to invoking
+% |\CollectArguments|; see section~\ref{sec:code:collargs:fix} for details.
+% While I assume that only |\collargsFixFromNoVerbatim| will ever be used
+% (and it is used by |\mmz|), we provide macros for all three transitions,
+% for completeness.\indentmacrocode
+\collargsSet{
+ fix from verbatim/.code={\collargsFixFromVerbatim},
+ fix from verb/.code={\collargsFixFromVerb},
+ fix from no verbatim/.code={\collargsFixFromNoVerbatim},
+}
+% \noindentmacrocode
+\def\collargsFixFromNoVerbatim{%
+ \global\collargs@fix@requestedtrue
+ \global\let\ifcollargs@last@verbatim\iffalse
+}
+\def\collargsFixFromVerbatim{%
+ \global\collargs@fix@requestedtrue
+ \global\let\ifcollargs@last@verbatim\iftrue
+ \global\let\ifcollargs@last@verbatimbraces\iftrue
+}
+\def\collargsFixFromVerb{%
+ \global\collargs@fix@requestedtrue
+ \global\let\ifcollargs@last@verbatim\iftrue
+ \global\let\ifcollargs@last@verbatimbraces\iffalse
+}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}{braces}
+% Set the characters which are used as the grouping characters in the full
+% verbatim mode. The user is only required to do this when multiple
+% character pairs serve as the grouping characters. The underlying macro,
+% |\collargsBraces|, will be defined in
+% section~\ref{sec:code:collargs:verbatim}.
+\collargsSet{
+ braces/.code={\collargsBraces{#1}}%
+}
+% \end{collargskey}
+%
+% \begin{collargskey}{environment}
+% \begin{macro}{\collargsEnvironment}
+% Set the environment name.
+% \indentmacrocode
+\collargsSet{
+ environment/.estore in=\collargs@b@envname
+}
+\def\collargsEnvironment#1{\edef\collargs@b@envname{#1}}
+\collargsEnvironment{}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}{begin tag, end tag, tags}
+% \begin{macro}{\ifcollargsBeginTag,\ifcollargsEndTag,\ifcollargsAddTags}
+% When |begin tag|\slash|end tag| is in effect, the begin\slash end-tag will
+% be will be prepended/appended to the environment body. |tags| is a
+% shortcut for setting |begin tag| and |end tag| simultaneously.
+% \indentmacrocode
+\collargsSet{
+ begin tag/.is if=collargsBeginTag,
+ end tag/.is if=collargsEndTag,
+ tags/.style={begin tag=#1, end tag=#1},
+ tags/.default=true,
+}
+\newif\ifcollargsBeginTag
+\newif\ifcollargsEndTag
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}{ignore nesting}
+% \begin{macro}{\ifcollargsIgnoreNesting}
+% When this key is in effect, we will
+% ignore any \cs{begin}\marg{name}s and simply grab everything up to
+% the first \cs{end}\marg{name} (again, the markers are automatically
+% adapted to the format).
+\collargsSet{
+ ignore nesting/.is if=collargsIgnoreNesting,
+}
+\newif\ifcollargsIgnoreNesting
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}{ignore other tags}
+% \begin{macro}{\ifcollargsIgnoreOtherTags}
+% This key is only relevant in the
+% non-verbatim and partial verbatim modes in \hologo{LaTeX}. When it
+% is in effect, CollArgs checks the environment name following each
+% |\begin| and |\end|, ignoring the tags with an environment name other
+% than |\collargs@b@envname|.
+\collargsSet{
+ ignore other tags/.is if=collargsIgnoreOtherTags,
+}
+\newif\ifcollargsIgnoreOtherTags
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}[noindex]{(append/prepend) (pre/post)processor}
+% \begin{macro}[noindex]{\collargs(Append/Prepend)(Pre/Post)processor}
+% \begin{collargskey}[noprint]{append preprocessor, prepend preprocessor,
+% append postprocessor, prepend postprocessor}
+% \begin{macro}[noprint]{\collargsAppendPreprocessor,\collargsPrependPreprocessor,\collargsAppendPostprocessor,\collargsPrependPostprocessor}
+% These keys and
+% macros populate the list of preprocessors,
+% |\collargs@preprocess@arg|, and the list of post-processors,
+% |\collargs@postprocess@arg|, executed in |\collargs@appendarg|.
+\collargsSet{
+ append preprocessor/.code={\collargsAppendPreprocessor{#1}},
+ prepend preprocessor/.code={\collargsPrependPreprocessor{#1}},
+ append postprocessor/.code={\collargsAppendPostprocessor{#1}},
+ prepend postprocessor/.code={\collargsPrependPostprocessor{#1}},
+}
+\def\collargsAppendPreprocessor{%
+ \collargs@addprocessor\appto\collargs@preprocess@arg}
+\def\collargsPrependPreprocessor{%
+ \collargs@addprocessor\preto\collargs@preprocess@arg}
+\def\collargsAppendPostprocessor{%
+ \collargs@addprocessor\appto\collargs@postprocess@arg}
+\def\collargsPrependPostprocessor{%
+ \collargs@addprocessor\preto\collargs@postprocess@arg}
+% Here, |#1| will be either |\appto| or |\preto|, and |#2| will be either
+% |\collargs@preprocess@arg| or |\collargs@postprocess@arg|. |#3| is the
+% processor code.
+\def\collargs@addprocessor#1#2#3{%
+ #1#2{%
+ \expanded{%
+ \unexpanded{#3}{\the\collargsArg}%
+ }%
+ }%
+}
+% \end{macro}
+% \end{collargskey}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}[noindex]{clear (pre/post)processors}
+% \begin{macro}[noindex]{\collargsClear(Pre/Post)processors}
+% \begin{collargskey}[noprint]{clear preprocessors, clear postprocessors}
+% \begin{macro}[noprint]{\collargsClearPreprocessors,\collargsClearPostprocessors}
+% These keys and macros
+% clear the pre- and post-processor lists, which are initially empty as
+% well.
+\def\collargs@preprocess@arg{}
+\def\collargs@postprocess@arg{}
+\collargsSet{
+ clear preprocessors/.code={\collargsClearPreprocessors},
+ clear postprocessors/.code={\collargsClearPostprocessors},
+}
+\def\collargsClearPreprocessors{\def\collargs@preprocess@arg{}}%
+\def\collargsClearPostprocessors{\def\collargs@postprocess@arg{}}%
+% \end{macro}
+% \end{collargskey}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}[noindex]{(append/prepend) expandable (pre/post)processor}
+% \begin{macro}[noindex]{\collargs(Append/Prepend)Expandable(Pre/Post)processor}
+% \begin{collargskey}[noprint]{append expandable preprocessor, prepend expandable preprocessor, append expandable postprocessor, prepend expandable postprocessor}
+% \begin{macro}[noprint]{\collargsAppendExpandablePreprocessor,\collargsPrependExpandablePreprocessor,\collargsAppendExpandablePostprocessor,\collargsPrependExpandablePostprocessor}
+% These keys
+% and macros simplify the definition of fully expandable processors. Note
+% that expandable processors are added to the same list as non-expandable
+% processors.
+\collargsSet{
+ append expandable preprocessor/.code={%
+ \collargsAppendExpandablePreprocessor{#1}},
+ prepend expandable preprocessor/.code={%
+ \collargsPrependExpandablePreprocessor{#1}},
+ append expandable postprocessor/.code={%
+ \collargsAppendExpandablePostprocessor{#1}},
+ prepend expandable postprocessor/.code={%
+ \collargsPrependExpandablePostprocessor{#1}},
+}
+\def\collargsAppendExpandablePreprocessor{%
+ \collargs@addeprocessor\appto\collargs@preprocess@arg}
+\def\collargsPrependExpandablePreprocessor{%
+ \collargs@addeprocessor\preto\collargs@preprocess@arg}
+\def\collargsAppendExpandablePostprocessor{%
+ \collargs@addeprocessor\appto\collargs@postprocess@arg}
+\def\collargsPrependExpandablePostprocessor{%
+ \collargs@addeprocessor\preto\collargs@postprocess@arg}
+\def\collargs@addeprocessor#1#2#3{%
+ #1#2{%
+ \expanded{%
+ \edef\noexpand\collargs@temp{\unexpanded{#3}{\the\collargsArg}}%
+ \unexpanded{\expandafter\collargsArg\expandafter{\collargs@temp}}%
+ }%
+ }%
+}
+% \end{macro}
+% \end{collargskey}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{collargskey}[noindex]{(append/prepend) (pre/post)wrap}
+% \begin{macro}[noindex]{\collargs(Append/Prepend)(Pre/Post)wrap}
+% \begin{collargskey}[noprint]{append prewrap, prepend prewrap, append postwrap, prepend postwrap}
+% \begin{macro}[noprint]{\collargsAppendPrewrap,\collargsPrependPrewrap,\collargsAppendPostwrap,\collargsPrependPostwrap}
+% These keys and macros
+% simplify the definition of processors which yield the result after a
+% single expansion. Again, they are added to the same list as other
+% processors.
+\collargsSet{
+ append prewrap/.code={\collargsAppendPrewrap{#1}},
+ prepend prewrap/.code={\collargsPrependPrewrap{#1}},
+ append postwrap/.code={\collargsAppendPostwrap{#1}},
+ prepend postwrap/.code={\collargsPrependPostwrap{#1}},
+}
+\def\collargsAppendPrewrap{\collargs@addwrap\appto\collargs@preprocess@arg}
+\def\collargsPrependPrewrap{\collargs@addwrap\preto\collargs@preprocess@arg}
+\def\collargsAppendPostwrap{\collargs@addwrap\appto\collargs@postprocess@arg}
+\def\collargsPrependPostwrap{\collargs@addwrap\preto\collargs@postprocess@arg}
+\def\collargs@addwrap#1#2#3{%
+ #1#2{%
+ \long\def\collargs@temp##1{#3}%
+ \expandafter\expandafter\expandafter\collargsArg
+ \expandafter\expandafter\expandafter{%
+ \expandafter\collargs@temp\expandafter{\the\collargsArg}%
+ }%
+ }%
+}
+% \end{macro}
+% \end{collargskey}
+% \end{macro}
+% \end{collargskey}
+%
+%
+% \begin{collargskey}{no delimiters}
+% \begin{macro}{\ifcollargsNoDelimiters}
+% When this conditional is in effect, the
+% delimiter wrappers set by |\collargs@wrap| are ignored by
+% |\collargs@appendarg|.
+\collargsSet{%
+ no delimiters/.is if=collargsNoDelimiters,
+}
+\newif\ifcollargsNoDelimiters
+% \end{macro}
+% \end{collargskey}
+%
+% \subsubsection{The central loop}
+% \label{sec:code:collargs:central-loop}
+%
+% The central loop is where we grab the next \meta{token} from the argument
+% specification and execute the corresponding argument type or modifier
+% handler, |\collargs@|\meta{token}. The central loop consumes the argument
+% type \meta{token}; the handler will see the remainder of the argument
+% specification (which starts with the arguments to the argument type, if any,
+% e.g.\ by |()| of |d()|), followed by a dot, and then the tokens list from
+% which the arguments are to be collected. It is the responsibility of handler
+% to preserve the rest of the argument specification and reexecute the central
+% loop once it is finished.
+%
+% \begin{macro}{\collargs@}
+% Each argument is processed in a group to allow for local settings. This
+% group is closed by |\collargs@appendarg|.
+\def\collargs@{%
+ \begingroup
+ \collargs@@@
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@@@}
+% This macro is where modifier handlers reenter the central loop --- we don't
+% want modifers to open a group, because their settings should remain in
+% effect until the next argument. Furthermore, modifiers do not trigger
+% category code fixes.
+\def\collargs@@@#1{%
+ \collargs@in@{#1}{&+!>.}%
+ \ifcollargs@in@
+ \expandafter\collargs@@@iii
+ \else
+ \expandafter\collargs@@@i
+ \fi
+ #1%
+}
+\def\collargs@@@i#1.{%
+ % Fix the category code of the next argument token, if necessary, and then
+ % proceed with the main loop.
+ \collargs@fix{\collargs@@@ii#1.}%
+}
+% Reset the fix request and set the last verbatim conditionals to the current
+% state.
+\def\collargs@@@ii{%
+ \global\collargs@fix@requestedfalse
+ \global\let\ifcollargs@last@verbatim\ifcollargs@verbatim
+ \global\let\ifcollargs@last@verbatimbraces\ifcollargs@verbatimbraces
+ \collargs@@@iii
+}
+% Call the modifier or argument type handler denoted by the first token of the
+% remainder of the argument specification.
+\def\collargs@@@iii#1{%
+ \ifcsname collargs@#1\endcsname
+ \csname collargs@#1\expandafter\endcsname
+ \else
+ % We throw an error if the token refers to no argument type or modifier.
+ \collargs@error@badtype{#1}%
+ \fi
+}
+% Throwing an error stops the processing of the argument specification, and
+% closes the group opened in |\collargs@i|.
+\def\collargs@error@badtype#1#2.{%
+ \PackageError{collargs}{Unknown xparse argument type or modifier "#1"
+ for "\expandafter\string\collargs@caller\space"}{}%
+ \endgroup
+}
+% \end{macro}
+%
+% {\catcode`\&=11
+% \begin{macro}{\collargs@&}
+% We extend the |xparse| syntax with modifier |&|, which applies the given
+% options to the following (and only the following) argument. If |&| is
+% followed by another |&|, the options are expected to occur in the raw
+% format, like the options given to |\CollectArgumentsRaw|. Otherwise, the
+% options should take the form of a keylist, which will be processed by
+% |\collargsSet|. In any case, the options should be given within the
+% argument specification, immediately following the (single or double) |&|.
+\csdef{collargs@&}{%
+ \futurelet\collargs@temp\collargs@amp@i
+}
+\def\collargs@amp@i{%
+ % In \hologo{ConTeXt}, |&| has character code ``other'' in the text.
+ %<!context>\ifx\collargs@temp&%
+ %<context>\expandafter\ifx\detokenize{&}\collargs@temp
+ \expandafter\collargs@amp@raw
+ \else
+ \expandafter\collargs@amp@set
+ \fi
+}
+\def\collargs@amp@raw#1#2{%
+ \collargs@verbatim@wrap{#2}%
+ \collargs@@@
+}
+\def\collargs@amp@set#1{%
+ \collargs@verbatim@wrap{\collargsSet{#1}}%
+ \collargs@@@
+}
+% \end{macro}}
+%
+% \begin{macro}[noindex]{\collargs@+}
+% \MyIndex{collargs@&plus;}{\texttt{\textbackslash collargs@+}}{main}
+% This modifier makes the next argument long, i.e.\ accept paragraph tokens.
+\csdef{collargs@+}{%
+ \collargs@longtrue
+ \collargs@@@
+}
+\newif\ifcollargs@long
+% \end{macro}
+%
+% \begin{macro}{\collargs@>}
+% We can simply ignore the processor modifier. (This, |xparse|'s processor,
+% should not be confused with CollArgs's processors, which are set using
+% keys |append preprocessor| etc.)
+\csdef{collargs@>}#1{\collargs@@@}
+% \end{macro}
+%
+% \begin{macro}[noindex]{\collargs@!}
+% \MyIndex{collargs@&excl;}{\texttt{\textbackslash collargs@\exclamationmark}}{main}
+% Should we accept spaces before an optional argument following a mandatory
+% argument (\pkg{xparse} manual, \S1.1)? By default, yes. This modifier is
+% only applicable to types |d| and |t|, and derived types, but, unlike
+% |xparse|, we don't bother to enforce this; when used with other types, |!|
+% simply has no effect.
+\csdef{collargs@!}{%
+ \collargs@grabspacesfalse
+ \collargs@@@
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@toks}
+% This token register is where we store the collected argument tokens. All
+% assignments to this register are global, because it needs to survive the
+% groups opened for individual arguments.
+\newtoks\collargs@toks
+% \end{macro}
+%
+% \begin{macro}{\collargsArg}
+% An auxiliary, but publicly available token register, used for processing
+% the argument, and by some argument type handlers.
+\newtoks\collargsArg
+% \end{macro}
+%
+% \begin{macro}{\collargs@.}
+% This fake argument type is used to signal the end of the argument list.
+% Note that this really counts as an extension of the |xparse| argument
+% specification.
+\csdef{collargs@.}{%
+ % Close the group opened in |\collargs@|.
+ \endgroup
+ % Close the main |\CollectArguments| group, fix the category code of the next
+ % token if necessary, and execute the next-code, followed by the collected
+ % arguments in braces. Any over-grabbed spaces are reinserted into the input
+ % stream, non-verbatim.
+ \expanded{%
+ \endgroup
+ \noexpand\collargs@fix{%
+ \expandonce\collargs@next{\the\collargs@toks}%
+ \collargs@spaces
+ }%
+ }%
+}
+% \end{macro}
+%
+% \subsubsection{Auxiliary macros}
+% \label{sec:code:collargs:aux}
+%
+% \begin{macro}{\collargs@appendarg}
+% This macro is used by the argument type
+% handlers to append the collected argument to the storage
+% (|\collargs@toks|).
+\long\def\collargs@appendarg#1{%
+ % Temporarily store the collected argument into a token register. The
+ % processors will manipulate the contents of this register.
+ \collargsArg={#1}%
+ % This will clear the double-fix conditional, and potentially request a
+ % normal, single fix. We can do this here because this macro is only called
+ % when something is actually collected. For details, see
+ % section~\ref{sec:code:collargs:fix}.
+ \ifcollargs@double@fix
+ \collargs@cancel@double@fix
+ \fi
+ % Process the argument with user-definable preprocessors, the wrapper defined
+ % by the argument type, and user-definable postprocessors.
+ \collargs@preprocess@arg
+ \ifcollargsNoDelimiters
+ \else
+ \collargs@process@arg
+ \fi
+ \collargs@postprocess@arg
+ % Append the processed argument, preceded by any grabbed spaces (in the
+ % correct mode), to the storage.
+ \xtoksapp\collargs@toks{\collargs@grabbed@spaces\the\collargsArg}%
+ % Initialize the space-grabber.
+ \collargs@init@grabspaces
+ % Once the argument was appended to the list, we can close its group, opened
+ % by |\collargs@|.
+ \endgroup
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@wrap}
+% This macro is used by argument type handlers to declare their delimiter
+% wrap, like square brackets around the optional argument of type |o|. It
+% uses |\collargs@addwrap|, defined in section~\ref{sec:code:collargs:keys},
+% but adds to |\collargs@process@arg|, which holds the delimiter wrapper
+% defined by the argument type handler. Note that this macro \emph{appends}
+% a wrapper, so multiple wrappers are allowed --- this is used by type |e|
+% handler.
+\def\collargs@wrap{\collargs@addwrap\appto\collargs@process@arg}
+\def\collargs@process@arg{}
+% \end{macro}
+%
+% \begin{macro}{\collargs@defcollector,\collargs@defusecollector,\collargs@letusecollector}
+% These macros streamline the usage of
+% the ``caller'' control sequence. They are like a |\def|, but should not
+% be given the control sequence to define, as they will automatically
+% define the control sequence residing in |\collargs@caller|; the usage is
+% thus |\collargs@defcollector<parameters>{<definition>}|. For example, if
+% |\collargs@caller| holds |\foo|, |\collargs@defcollector#1{(#1)}| is
+% equivalent to |\def\foo#1{(#1)}|. Macro |\collargs@defcollector| will
+% only define the caller control sequence to be the collector, while
+% |\collargs@defusecollector| will also immediately execute it.
+\def\collargs@defcollector#1#{%
+ \ifcollargs@long\long\fi
+ \expandafter\def\collargs@caller#1%
+}
+\def\collargs@defusecollector#1#{%
+ \afterassignment\collargs@caller
+ \ifcollargs@long\long\fi
+ \expandafter\def\collargs@caller#1%
+}
+\def\collargs@letusecollector#1{%
+ \expandafter\let\collargs@caller#1%
+ \collargs@caller
+}
+\newif\ifcollargs@grabspaces
+\collargs@grabspacestrue
+% \end{macro}
+%
+% \begin{macro}{\collargs@init@grabspaces}
+% The space-grabber macro
+% |\collargs@grabspaces| should be initialized by executing this macro. If
+% |\collargs@grabspaces| is called twice without an intermediate
+% initialization, it will assume it is in the same position in the input
+% stream and simply bail out.
+\def\collargs@init@grabspaces{%
+ \gdef\collargs@gs@state{0}%
+ \gdef\collargs@spaces{}%
+ \gdef\collargs@otherspaces{}%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@grabspaces}
+% This auxiliary macro grabs any following
+% spaces, and then executes the next-code given as the sole argument. The
+% spaces will be stored into two macros, |\collargs@spaces| and
+% |\collargs@otherspaces|, which store the spaces in the non-verbatim and the
+% verbatim form. With the double storage, we can grab the spaces in the
+% verbatim mode and use them non-verbatim, or vice versa. The macro takes a
+% single argument, the code to execute after maybe grabbing the spaces.
+%
+\def\collargs@grabspaces#1{%
+ \edef\collargs@gs@next{\unexpanded{#1}}%
+ \ifnum\collargs@gs@state=0
+ \gdef\collargs@gs@state{1}%
+ \expandafter\collargs@gs@i
+ \else
+ \expandafter\collargs@gs@next
+ \fi
+}
+\def\collargs@gs@i{%
+ \futurelet\collargs@temp\collargs@gs@g
+}
+% We check for grouping characters even in the verbatim mode, because we might
+% be in the partial verbatim.
+\def\collargs@gs@g{%
+ \ifcat\noexpand\collargs@temp\bgroup
+ \expandafter\collargs@gs@next
+ \else
+ \ifcat\noexpand\collargs@temp\egroup
+ \expandafter\expandafter\expandafter\collargs@gs@next
+ \else
+ \expandafter\expandafter\expandafter\collargs@gs@ii
+ \fi
+ \fi
+}
+\def\collargs@gs@ii{%
+ \ifcollargs@verbatim
+ \expandafter\collargs@gos@iii
+ \else
+ \expandafter\collargs@gs@iii
+ \fi
+}
+% This works because the character code of a space token is always 32.
+\def\collargs@gs@iii{%
+ \expandafter\ifx\space\collargs@temp
+ \expandafter\collargs@gs@iv
+ \else
+ \expandafter\collargs@gs@next
+ \fi
+}
+\expandafter\def\expandafter\collargs@gs@iv\space{%
+ \gappto\collargs@spaces{ }%
+ \xappto\collargs@otherspaces{\collargs@otherspace}%
+ \collargs@gs@i
+}
+% We need the space of category 12 above.
+\begingroup\catcode`\ =12\relax\gdef\collargs@otherspace{ }\endgroup
+\def\collargs@gos@iii#1{%
+ % Macro |\collargs@cc| recalls the ``outside'' category code of character
+ % |#1|; see section~\ref{sec:code:collargs:verbatim}.
+ \ifnum\collargs@cc{#1}=10
+ % We have a space.
+ \expandafter\collargs@gos@iv
+ \else
+ \ifnum\collargs@cc{#1}=5
+ % We have a newline.
+ \expandafter\expandafter\expandafter\collargs@gos@v
+ \else
+ \expandafter\expandafter\expandafter\collargs@gs@next
+ \fi
+ \fi
+ #1%
+}
+\def\collargs@gos@iv#1{%
+ \gappto\collargs@otherspaces{#1}%
+ % No matter how many verbatim spaces we collect, they equal a single
+ % non-verbatim space.
+ \gdef\collargs@spaces{ }%
+ \collargs@gs@i
+}
+\def\collargs@gos@v{%
+ % Only add the first newline.
+ \ifnum\collargs@gs@state=2
+ \expandafter\collargs@gs@next
+ \else
+ \expandafter\collargs@gs@vi
+ \fi
+}
+\def\collargs@gs@vi#1{%
+ \gdef\collargs@gs@state{2}%
+ \gappto\collargs@otherspaces{#1}%
+ \gdef\collargs@spaces{ }%
+ \collargs@gs@i
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@maybegrabspaces}
+% This macro grabs any following spaces, but it will do so only when
+% conditional |\ifcollargs@grabspaces|, which can be \emph{un}set by modifier
+% |!|, is in effect. The macro is used by handlers for types |d| and |t|.
+\def\collargs@maybegrabspaces{%
+ \ifcollargs@grabspaces
+ \expandafter\collargs@grabspaces
+ \else
+ \expandafter\@firstofone
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@grabbed@spaces}
+% This macro expands to either the verbatim
+% or the non-verbatim variant of the grabbed spaces, depending on the
+% verbatim mode in effect at the time of expansion.
+\def\collargs@grabbed@spaces{%
+ \ifcollargs@verbatim
+ \collargs@otherspaces
+ \else
+ \collargs@spaces
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@reinsert@spaces}
+% Inserts the grabbed spaces back into the
+% input stream, but with the category code appropriate for the verbatim mode
+% then in effect. After the insertion, the space-grabber is initialized and
+% the given next-code is executed in front of the inserted spaces.
+\def\collargs@reinsert@spaces#1{%
+ \expanded{%
+ \unexpanded{%
+ \collargs@init@grabspaces
+ #1%
+ }%
+ \collargs@grabbed@spaces
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@ifnextcat}
+% An adaptation of |\pgf@keys@utilifnextchar|
+% which checks whether the \emph{category} code of the next non-space
+% character matches the category code of |#1|.
+\long\def\collargs@ifnextcat#1#2#3{%
+ \let\pgf@keys@utilreserved@d=#1%
+ \def\pgf@keys@utilreserved@a{#2}%
+ \def\pgf@keys@utilreserved@b{#3}%
+ \futurelet\pgf@keys@utillet@token\collargs@ifncat}
+\def\collargs@ifncat{%
+ \ifx\pgf@keys@utillet@token\pgf@keys@utilsptoken
+ \let\pgf@keys@utilreserved@c\collargsxifnch
+ \else
+ \ifcat\noexpand\pgf@keys@utillet@token\pgf@keys@utilreserved@d
+ \let\pgf@keys@utilreserved@c\pgf@keys@utilreserved@a
+ \else
+ \let\pgf@keys@utilreserved@c\pgf@keys@utilreserved@b
+ \fi
+ \fi
+ \pgf@keys@utilreserved@c}
+{%
+ \def\:{\collargs@xifncat}
+ \expandafter\gdef\: {\futurelet\pgf@keys@utillet@token\collargs@ifncat}
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@forrange}
+% This macro executes macro |\collargs@do| for every integer from |#1| and
+% |#2|, both inclusive. |\collargs@do| should take a single parameter, the
+% current number.
+\def\collargs@forrange#1#2{%
+ \expanded{%
+ \noexpand\collargs@forrange@i{\number#1}{\number#2}%
+ }%
+ }
+\def\collargs@forrange@i#1#2{%
+ \ifnum#1>#2 %
+ \expandafter\@gobble
+ \else
+ \expandafter\@firstofone
+ \fi
+ {%
+ \collargs@do{#1}%
+ \expandafter\collargs@forrange@i\expandafter{\number\numexpr#1+1\relax}{#2}%
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@forranges}
+% This macro executes macro |\collargs@do| for every integer falling into the
+% ranges specified in |#1|. The ranges should be given as a comma-separated
+% list of |from-to| items, e.g.\ |1-5,10-11|.
+\def\collargs@forranges{\forcsvlist\collarg@forrange@i}
+\def\collarg@forrange@i#1{\collarg@forrange@ii#1-}
+\def\collarg@forrange@ii#1-#2-{\collargs@forrange{#1}{#2}}
+% \end{macro}
+%
+% \begin{macro}{\collargs@percentchar}
+% This macro holds the percent character of category 12.
+\begingroup
+\catcode`\%=12
+\gdef\collargs@percentchar{%}
+\endgroup
+% \end{macro}
+%
+%
+% \subsubsection{The handlers}
+% \label{sec:code:collargs:handlers}
+%
+% \begin{macro}{\collargs@l}
+% We will first define the handler for the very funky argument type |l|,
+% which corresponds to \hologo{TeX}'s |\def\foo#1#{...}|, which grabs (into
+% |#1|) everything up to the first opening brace --- not because this type is
+% important or even recommended to use, but because the definition of the
+% handler is very simple, at least for the non-verbatim case.
+%
+\def\collargs@l#1.{%
+ % Any pre-grabbed spaces in fact belong into the argument.
+ \collargs@reinsert@spaces{\collargs@l@i#1.}%
+}
+\def\collargs@l@i{%
+ % We request a correction of the category code of the delimiting brace if the
+ % verbatim mode changes for the next argument; for details, see
+ % section~\ref{sec:code:collargs:fix}.
+ \global\collargs@fix@requestedtrue
+ % Most handlers will branch into the verbatim and the non-verbatim part using
+ % conditional |\ifcollargs@verbatim|. This handler is a bit special, because
+ % it needs to distinguish verbatim and non-verbatim \emph{braces}, and
+ % braces are verbatim only in the full verbatim mode, i.e.\ when
+ % |\ifcollargs@verbatimbraces| is true.
+ \ifcollargs@verbatimbraces
+ \expandafter\collargs@l@verb
+ \else
+ \expandafter\collargs@l@ii
+ \fi
+}
+% We grab the rest of the argument specification (|#1|), to be reinserted into
+% the token stream when we reexecute the central loop.
+\def\collargs@l@ii#1.{%
+ % In the non-verbatim mode, we merely have to define and execute the
+ % collector macro. The parameter text |##1##| (note the doubled hashes),
+ % which will put everything up to the first opening brace into the first
+ % argument, looks funky, but that's all.
+ \collargs@defusecollector##1##{%
+ % We append the collected argument, |##1|, to |\collargs@toks|, the token
+ % register holding the collected argument tokens.
+ \collargs@appendarg{##1}%
+ % Back to the central loop, with the rest of the argument specification
+ % reinserted.
+ \collargs@#1.%
+ }%
+}
+\def\collargs@l@verb#1.{%
+ % In the verbatim branch, we need to grab everything up to the first opening
+ % brace of category code 12, so we want to define the collector with
+ % parameter text |##1{|, with the opening brace of category 12. We have
+ % stored this token in macro |\collargs@other@bgroup|, which we now need to
+ % expand.
+ \expandafter\collargs@defusecollector
+ \expandafter##\expandafter1\collargs@other@bgroup{%
+ % Appending the argument works the same as in the non-verbatim case.
+ \collargs@appendarg{##1}%
+ % Reexecuting the central loop macro is a bit more involved, as we need to
+ % reinsert the verbatim opening brace (contrary to the regular brace above,
+ % the verbatim brace is consumed by the collector macro) back into the
+ % token stream, behind the reinserted argument specification.
+ \expanded{%
+ \noexpand\collargs@\unexpanded{#1.}%
+ \collargs@other@bgroup
+ }%
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@u}
+% Another weird type --- |u|\meta{tokens} reads everything up to the given
+% \meta{tokens}, i.e.\ this is \hologo{TeX}'s
+% |\def\foo#1|\meta{tokens}|{...}| --- but again, simple enough to allow us
+% to showcase solutions to two recurring problems.
+%
+% We start by branching into the verbatim mode (full or partial) or the
+% non-verbatim mode.
+\def\collargs@u{%
+ \ifcollargs@verbatim
+ \expandafter\collargs@u@verb
+ \else
+ \expandafter\collargs@u@i
+ \fi
+}
+% To deal with the verbatim mode, we only need to convert the above
+% \meta{tokens} (i.e.\ the argument of |u| in the argument specification) to
+% category 12, i.e.\ we have to |\detokenize| them. Then, we may proceed as in
+% the non-verbatim branch, |\collargs@u@ii|.
+\def\collargs@u@verb#1{%
+ % The |\string| here is a temporary solution to a problem with spaces. Our
+ % verbatim mode has them of category ``other'', but |\detokenize| produces a
+ % space of category ``space'' behind control words. ^^A todo
+ \expandafter\collargs@u@i\expandafter{\detokenize\expandafter{\string#1}}%
+}
+% We then reinsert any pre-grabbed spaces into the stream, but we take care not
+% to destroy the braces around our delimiter in the argument specification.
+\def\collargs@u@i#1#2.{%
+ \collargs@reinsert@spaces{\collargs@u@ii{#1}#2.}%
+}
+\def\collargs@u@ii#1#2.{%
+ % |#1| contains the delimiter tokens, so |##1| below will receive everything
+ % in the token stream up to these. But we have a problem: if we defined the
+ % collector as for the non-verbatim |l|, and the delimiter happened to be
+ % preceded by a single brace group, we would lose the braces. For example,
+ % if the delimiter was |-| and we received |{foo}-|, we would collect |foo-|.
+ % We solve this problem by inserting |\collargs@empty| (with an empty
+ % definition) into the input stream (at the end of this macro) --- this way,
+ % the delimiter can never be preceded by a single brace group --- and then
+ % expanding it away before appending to storage (within the argument of
+ % |\collargs@defusecollector|).
+ \collargs@defusecollector##1#1{%
+ % Define the wrapper which will add the delimiter tokens (|#1|) after the
+ % collected argument. The wrapper will be applied during argument
+ % processing in |\collargs@appendarg| (sandwiched between used-definable
+ % pre- and post-processors).
+ \collargs@wrap{####1#1}%
+ % Expand the first token in |##1|, which we know to be |\collargs@empty|,
+ % with empty expansion.
+ \expandafter\collargs@appendarg\expandafter{##1}%
+ \collargs@#2.%
+ }%
+ % Insert |\collargs@empty| into the input stream, in front of the ``real''
+ % argument tokens.
+ \collargs@empty
+}
+\def\collargs@empty{}
+% \end{macro}
+%
+% \begin{macro}{\collargs@r}
+% Finally, a real argument type: required delimited argument.
+\def\collargs@r{%
+ \ifcollargs@verbatim
+ \expandafter\collargs@r@verb
+ \else
+ \expandafter\collargs@r@i
+ \fi
+}
+\def\collargs@r@verb#1#2{%
+ \expandafter\collargs@r@i\detokenize{#1#2}%
+}
+\def\collargs@r@i#1#2#3.{%
+ % We will need to use the |\collargs@empty| trick from type |u|, but with an
+ % additional twist: we need to insert it \emph{after} the opening delimiter
+ % |#1|. To do this, we consume the opening delimiter by the ``outer''
+ % collector below --- we need to use the collector so that we get a nice
+ % error message when the opening delimiter is not present --- and have this
+ % collector define the ``inner'' collector in the spirit of type |u|.
+ %
+ % The outer collector has no parameters, it just requires the presence of the
+ % opening delimiter.
+ \collargs@defcollector#1{%
+ % The inner collector will grab everything up to the closing delimiter.
+ \collargs@defusecollector####1#2{%
+ % Append the collected argument |####1| to the list, wrapping it into the
+ % delimiters (|#1| and |#2|), but not before expanding its first token,
+ % which we know to be |\collargs@empty|.
+ \collargs@wrap{#1########1#2}%
+ \expandafter\collargs@appendarg\expandafter{####1}%
+ \collargs@#3.%
+ }%
+ \collargs@empty
+ }%
+ % Another complication: our delimited argument may be preceded by spaces. To
+ % replicate the argument tokens faithfully, we need to collect them before
+ % trying to grab the argument itself.
+ \collargs@grabspaces\collargs@caller
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@R}
+% Discard the default and execute |r|.
+\def\collargs@R#1#2#3{\collargs@r#1#2}
+% \end{macro}
+%
+% \begin{macro}{\collargs@d}
+% Optional delimited argument. Very similar to |r|.
+\def\collargs@d{%
+ \ifcollargs@verbatim
+ \expandafter\collargs@d@verb
+ \else
+ \expandafter\collargs@d@i
+ \fi
+}
+\def\collargs@d@verb#1#2{%
+ \expandafter\collargs@d@i\detokenize{#1#2}%
+}
+\def\collargs@d@i#1#2#3.{%
+ % This macro will be executed when the optional argument is not present. It
+ % simply closes the argument's group and reexecutes the central loop.
+ \def\collargs@d@noopt{%
+ \global\collargs@fix@requestedtrue
+ \endgroup
+ \collargs@#3.%
+ }%
+ % The collector(s) are exactly as for |r|.
+ \collargs@defcollector#1{%
+ \collargs@defusecollector####1#2{%
+ \collargs@wrap{#1########1#2}%
+ \expandafter\collargs@appendarg\expandafter{####1}%
+ \collargs@#3.%
+ }%
+ \collargs@empty
+ }%
+ % This macro will check, in conjunction with |\futurelet| below, whether the
+ % optional argument is present or not.
+ \def\collargs@d@ii{%
+ \ifx#1\collargs@temp
+ \expandafter\collargs@caller
+ \else
+ \expandafter\collargs@d@noopt
+ \fi
+ }%
+ % Whether spaces are allowed in front of this type of argument depends on the
+ % presence of modifier |!|.
+ \collargs@maybegrabspaces{\futurelet\collargs@temp\collargs@d@ii}%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@D}
+% Discard the default and execute |d|.
+\def\collargs@D#1#2#3{\collargs@d#1#2}
+% \end{macro}
+%
+% \begin{macro}{\collargs@o}
+% |o| is just |d| with delimiters |[| and |]|.
+\def\collargs@o{\collargs@d[]}
+% \end{macro}
+%
+% \begin{macro}{\collargs@O}
+% |O| is just |d| with delimiters |[| and |]| and the discarded default.
+\def\collargs@O#1{\collargs@d[]}
+% \end{macro}
+%
+% \begin{macro}{\collargs@t}
+% An optional token. Similar to |d|.
+\def\collargs@t{%
+ \ifcollargs@verbatim
+ \expandafter\collargs@t@verb
+ \else
+ \expandafter\collargs@t@i
+ \fi
+}
+\def\collargs@t@space{ }
+\def\collargs@t@verb#1{%
+ \let\collargs@t@space\collargs@otherspace
+ \expandafter\collargs@t@i\expandafter{\detokenize{#1}}%
+}
+\def\collargs@t@i#1{%
+ \expandafter\ifx\space#1%
+ \expandafter\collargs@t@s
+ \else
+ \expandafter\collargs@t@I\expandafter#1%
+ \fi
+}
+\def\collargs@t@s#1.{%
+ \collargs@grabspaces{%
+ \ifcollargs@grabspaces
+ \collargs@appendarg{}%
+ \else
+ \expanded{%
+ \noexpand\collargs@init@grabspaces
+ \noexpand\collargs@appendarg{\collargs@grabbed@spaces}%
+ }%
+ \fi
+ \collargs@#1.%
+ }%
+}
+\def\collargs@t@I#1#2.{%
+ \def\collargs@t@noopt{%
+ \global\collargs@fix@requestedtrue
+ \endgroup
+ \collargs@#2.%
+ }%
+ \def\collargs@t@opt##1{%
+ \collargs@appendarg{#1}%
+ \collargs@#2.%
+ }%
+ \def\collargs@t@ii{%
+ \ifx#1\collargs@temp
+ \expandafter\collargs@t@opt
+ \else
+ \expandafter\collargs@t@noopt
+ \fi
+ }%
+ \collargs@maybegrabspaces{\futurelet\collargs@temp\collargs@t@ii}%
+}
+\def\collargs@t@opt@space{%
+ \expanded{\noexpand\collargs@t@opt{\space}\expandafter}\romannumeral-0%
+}%
+% \end{macro}
+%
+% \begin{macro}{\collargs@s}
+% The optional star is just a special case of |t|.
+\def\collargs@s{\collargs@t*}
+% \end{macro}
+%
+% \begin{macro}{\collargs@m}
+% Mandatory argument. Interestingly, here's where things get complicated,
+% because we have to take care of several \hologo{TeX} quirks.
+\def\collargs@m{%
+ \ifcollargs@verbatim
+ \expandafter\collargs@m@verb
+ \else
+ \expandafter\collargs@m@i
+ \fi
+}
+% The non-verbatim mode. First, collect any spaces in front of the argument.
+\def\collargs@m@i#1.{%
+ \collargs@grabspaces{\collargs@m@checkforgroup#1.}%
+}
+% Is the argument in braces or not?
+\def\collargs@m@checkforgroup#1.{%
+ \edef\collargs@action{\unexpanded{\collargs@m@checkforgroup@i#1.}}%
+ \futurelet\collargs@token\collargs@action
+}
+\def\collargs@m@checkforgroup@i{%
+ \ifcat\noexpand\collargs@token\bgroup
+ \expandafter\collargs@m@group
+ \else
+ \expandafter\collargs@m@token
+ \fi
+}
+% The argument is given in braces, so we put them back around it
+% (|\collargs@wrap|) when appending to the storage.
+\def\collargs@m@group#1.{%
+ \collargs@defusecollector##1{%
+ \collargs@wrap{{####1}}%
+ \collargs@appendarg{##1}%
+ \collargs@#1.%
+ }%
+}
+% The argument is a single token, we append it to the storage as is.
+\def\collargs@m@token#1.{%
+ \collargs@defusecollector##1{%
+ \collargs@appendarg{##1}%
+ \collargs@#1.%
+ }%
+}
+% The verbatim mode. Again, we first collect any spaces in front of the
+% argument.
+\def\collargs@m@verb#1.{%
+ \collargs@grabspaces{\collargs@m@verb@checkforgroup#1.}%
+}
+% We want to check whether we're dealing with a braced argument. We're in the
+% verbatim mode, but are braces verbatim as well? In other words, are we in
+% |verbatim| or |verb| mode? In the latter case, braces are regular, so we
+% redirect to the regular mode.
+\def\collargs@m@verb@checkforgroup{%
+ \ifcollargs@verbatimbraces
+ \expandafter\collargs@m@verb@checkforgroup@i
+ \else
+ \expandafter\collargs@m@checkforgroup
+ \fi
+}
+% Is the argument in verbatim braces?
+\def\collargs@m@verb@checkforgroup@i#1.{%
+ \def\collargs@m@verb@checkforgroup@ii{\collargs@m@verb@checkforgroup@iii#1.}%
+ \futurelet\collargs@temp\collargs@m@verb@checkforgroup@ii
+}
+\def\collargs@m@verb@checkforgroup@iii#1.{%
+ \expandafter\ifx\collargs@other@bgroup\collargs@temp
+ % Yes, the argument is in (verbatim) braces.
+ \expandafter\collargs@m@verb@group
+ \else
+ % We need to manually check whether the following token is a (verbatim)
+ % closing brace, and throw an error if it is.
+ \expandafter\ifx\collargs@other@egroup\collargs@temp
+ \expandafter\expandafter\expandafter\collargs@m@verb@egrouperror
+ \else
+ % The argument is a single token.
+ \expandafter\expandafter\expandafter\collargs@m@v@token
+ \fi
+ \fi
+ #1.%
+}
+\def\collargs@m@verb@egrouperror#1.{%
+ \PackageError{collargs}{%
+ Argument of \expandafter\string\collargs@caller\space has an extra
+ \iffalse{\else\string}}{}%
+}
+% A single-token verbatim argument.
+\def\collargs@m@v@token#1.#2{%
+ % Is it a control sequence? (Macro |\collargs@cc| recalls the ``outside''
+ % category code of character |#1|; see
+ % section~\ref{sec:code:collargs:verbatim}.)
+ \ifnum\collargs@cc{#2}=0
+ \expandafter\collargs@m@v@token@cs
+ \else
+ \expandafter\collargs@m@token
+ \fi
+ #1.#2%
+}
+% Is it a one-character control sequence?
+\def\collargs@m@v@token@cs#1.#2#3{%
+ \ifnum\collargs@cc{#3}=11
+ \expandafter\collargs@m@v@token@cs@letter
+ \else
+ \expandafter\collargs@m@v@token@cs@nonletter
+ \fi
+ #1.#2#3%
+}
+% Store |\<token>|.
+\def\collargs@m@v@token@cs@nonletter#1.#2#3{%
+ \collargs@appendarg{#2#3}%
+ \collargs@#1.%
+}
+% Store |\| to a temporary register, we'll parse the control sequence name now.
+\def\collargs@m@v@token@cs@letter#1.#2{%
+ \collargsArg{#2}%
+ \def\collargs@tempa{#1}%
+ \collargs@m@v@token@cs@letter@i
+}
+% Append a letter to the control sequence.
+\def\collargs@m@v@token@cs@letter@i#1{%
+ \ifnum\collargs@cc{#1}=11
+ \toksapp\collargsArg{#1}%
+ \expandafter\collargs@m@v@token@cs@letter@i
+ \else
+ % Finish, returning the non-letter to the input stream.
+ \expandafter\collargs@m@v@token@cs@letter@ii\expandafter#1%
+ \fi
+}
+% Store the verbatim control sequence.
+\def\collargs@m@v@token@cs@letter@ii{%
+ \expanded{%
+ \unexpanded{%
+ \expandafter\collargs@appendarg\expandafter{\the\collargsArg}%
+ }%
+ \noexpand\collargs@\expandonce\collargs@tempa.%
+ }%
+}
+% The verbatim mandatory argument is delimited by verbatim braces. We have to
+% use the heavy machinery adapted from |cprotect|.
+\def\collargs@m@verb@group#1.#2{%
+ \let\collargs@begintag\collargs@other@bgroup
+ \let\collargs@endtag\collargs@other@egroup
+ \def\collargs@tagarg{}%
+ \def\collargs@commandatend{\collargs@m@verb@group@i#1.}%
+ \collargs@readContent
+}
+% This macro appends the result given by the heavy machinery, waiting for us in
+% macro |\collargsArg|, to |\collargs@toks|, but not before dressing
+% it up (via |\collargs@wrap|) in a pair of verbatim braces.
+\def\collargs@m@verb@group@i{%
+ \edef\collargs@temp{%
+ \collargs@other@bgroup\unexpanded{##1}\collargs@other@egroup}%
+ \expandafter\collargs@wrap\expandafter{\collargs@temp}%
+ \expandafter\collargs@appendarg\expandafter{\the\collargsArg}%
+ \collargs@
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@g}
+% An optional group: same as |m|, but we simply bail out if we don't find the
+% group character.
+\def\collargs@g{%
+ \def\collargs@m@token{%
+ \global\collargs@fix@requestedtrue
+ \endgroup
+ \collargs@
+ }%
+ \let\collargs@m@v@token\collargs@m@token
+ \collargs@m
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@G}
+% Discard the default and execute |g|.
+\def\collargs@G#1{\collargs@g}
+% \end{macro}
+%
+% \begin{macro}{\collargs@v}
+% Verbatim argument. The code is executed in the group, deploying
+% |\collargsVerbatim|. The grouping characters are always set to braces, to
+% mimick |xparse| perfectly.
+\def\collargs@v#1.{%
+ \begingroup
+ \collargsBraces{{}}%
+ \collargsVerbatim
+ \collargs@grabspaces{\collargs@v@i#1.}%
+}
+\def\collargs@v@i#1.#2{%
+ \expandafter\ifx\collargs@other@bgroup#2%
+ % If the first token we see is an opening brace, use the |cprotect|
+ % adaptation to grab the group.
+ \let\collargs@begintag\collargs@other@bgroup
+ \let\collargs@endtag\collargs@other@egroup
+ \def\collargs@tagarg{}%
+ \def\collargs@commandatend{%
+ \edef\collargs@temp{%
+ \collargs@other@bgroup\unexpanded{####1}\collargs@other@egroup}%
+ \expandafter\collargs@wrap\expandafter{\collargs@temp}%
+ \expandafter\collargs@appendarg\expandafter{\the\collargsArg}%
+ \endgroup
+ \collargs@#1.%
+ }%
+ \expandafter\collargs@readContent
+ \else
+ % Otherwise, the verbatim argument is delimited by two identical characters
+ % (|#2|).
+ \collargs@defcollector##1#2{%
+ \collargs@wrap{#2####1#2}%
+ \collargs@appendarg{##1}%
+ \endgroup
+ \collargs@#1.%
+ }%
+ \expandafter\collargs@caller
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@b}
+% Environments. Here's where all hell breaks loose. We survive by adapting
+% some code from Bruno Le Floch's |cprotect|. We first define the
+% environment-related keys, then provide the handler code, and finish with
+% the adaptation of |cprotect|'s environment-grabbing code.
+%
+% The argument type |b| token may be followed by a braced environment name
+% (in the argument specification).
+\def\collargs@b{%
+ \collargs@ifnextcat\bgroup\collargs@bg\collargs@bi
+}
+\def\collargs@bg#1{%
+ \edef\collargs@b@envname{#1}%
+ \collargs@bi
+}
+\def\collargs@bi#1.{%
+ % Convert the environment name to verbatim if necessary.
+ \ifcollargs@verbatim
+ \edef\collargs@b@envname{\detokenize\expandafter{\collargs@b@envname}}%
+ \fi
+ % This is a format-specific macro which sets up |\collargs@begintag| and
+ % |\collargs@endtag|.
+ \collargs@bi@defCPTbeginend
+ \edef\collargs@tagarg{%
+ \ifcollargs@verbatimbraces
+ \else
+ \ifcollargsIgnoreOtherTags
+ \collargs@b@envname
+ \fi
+ \fi
+ }%
+ % Run this after collecting the body.
+ \def\collargs@commandatend{%
+ % In \hologo{LaTeX}, we might, depending on the verbatim mode, need to
+ % check whether the environment name is correct.
+ %<latex>\collargs@bii
+ % In \hologo{plainTeX} and \hologo{ConTeXt}, we can skip directly to
+ % |\collargs@biii|.
+ %<plain,context>\collargs@biii
+ #1.%
+ }%
+ % Collect the environment body, but first, put any grabbed spaces back into
+ % the input stream.
+ \collargs@reinsert@spaces\collargs@readContent
+}
+%<*latex>
+% In \hologo{LaTeX} in the regular and the partial verbatim mode, we search for
+% |\begin|\slash|\end| --- as we cannot search for braces --- either as control
+% sequences in the regular mode, or as strings in the partial verbatim
+% mode. (After search, we will have to check whether the argument of
+% |\begin|\slash|\end| matches our environment name.) In the full verbatim
+% mode, we can search for the entire string |\begin|\slash|\end|\marg{name}.
+\def\collargs@bi@defCPTbeginend{%
+ \edef\collargs@begintag{%
+ \ifcollargs@verbatim
+ \expandafter\string
+ \else
+ \expandafter\noexpand
+ \fi
+ \begin
+ \ifcollargs@verbatimbraces
+ \collargs@other@bgroup\collargs@b@envname\collargs@other@egroup
+ \fi
+ }%
+ \edef\collargs@endtag{%
+ \ifcollargs@verbatim
+ \expandafter\string
+ \else
+ \expandafter\noexpand
+ \fi
+ \end
+ \ifcollargs@verbatimbraces
+ \collargs@other@bgroup\collargs@b@envname\collargs@other@egroup
+ \fi
+ }%
+}
+%</latex>
+%<*plain,context>
+% We can search for the entire |\|\meta{name}\slash|\end|\meta{name} (in
+% \hologo{TeX}) or |\start|\meta{name}\slash|\stop|\meta{name} (in
+% \hologo{ConTeXt}), either as a control sequence (in the regular mode), or as
+% a string (in the verbatim modes).
+\def\collargs@bi@defCPTbeginend{%
+ \edef\collargs@begintag{%
+ \ifcollargs@verbatim
+ \expandafter\expandafter\expandafter\string
+ \else
+ \expandafter\expandafter\expandafter\noexpand
+ \fi
+ \csname
+ %<context>start%
+ \collargs@b@envname
+ \endcsname
+ }%
+ \edef\collargs@endtag{%
+ \ifcollargs@verbatim
+ \expandafter\expandafter\expandafter\string
+ \else
+ \expandafter\expandafter\expandafter\noexpand
+ \fi
+ \csname
+ %<plain>end%
+ %<context>stop%
+ \collargs@b@envname
+ \endcsname
+ }%
+}
+%</plain,context>
+%<*latex>
+% Check whether we're in front of the (braced) environment name (in
+% \hologo{LaTeX}), and consume it.
+\def\collargs@bii{%
+ \ifcollargs@verbatimbraces
+ \expandafter\collargs@biii
+ \else
+ \ifcollargsIgnoreOtherTags
+ % We shouldn't check the name in this case, because it was already
+ % checked, and consumed.
+ \expandafter\expandafter\expandafter\collargs@biii
+ \else
+ \expandafter\expandafter\expandafter\collargs@b@checkend
+ \fi
+ \fi
+}
+\def\collargs@b@checkend#1.{%
+ \collargs@grabspaces{\collargs@b@checkend@i#1.}%
+}
+\def\collargs@b@checkend@i#1.#2{%
+ \def\collargs@temp{#2}%
+ \ifx\collargs@temp\collargs@b@envname
+ \else
+ \collargs@b@checkend@error
+ \fi
+ \collargs@biii#1.%
+}
+\def\collargs@b@checkend@error{%
+ \PackageError{collargs}{Environment "\collargs@b@envname" ended as
+ "\collargs@temp"}{}%
+}
+%</latex>
+% This macro stores the collected body.
+\def\collargs@biii{%
+ % Define the wrapper macro (|\collargs@temp|).
+ \collargs@b@def@wrapper
+ % Execute |\collargs@appendarg| to append the body to the list. Expand the
+ % wrapper in |\collargs@temp| first and the body in |\collargsArg| next.
+ \expandafter\collargs@appendarg\expandafter{\the\collargsArg}%
+ % Reexecute the central loop.
+ \collargs@
+}
+\def\collargs@b@def@wrapper{%
+ %<latex>\edef\collargs@temp{{\collargs@b@envname}}%
+ \edef\collargs@temp{%
+ % Was the begin-tag requested?
+ \ifcollargsBeginTag
+ % |\collargs@begintag| is already adapted to the format and the verbatim mode.
+ \expandonce\collargs@begintag
+ % Add the braced environment name in \hologo{LaTeX} in the regular and
+ % partial verbatim mode.
+ %
+ %<*latex>
+ \ifcollargs@verbatimbraces\else\collargs@temp\fi
+ %</latex>
+ \fi
+ % This is the body.
+ ####1%
+ % Rinse and repeat for the end-tag.
+ \ifcollargsEndTag
+ \expandonce\collargs@endtag
+ %<*latex>
+ \ifcollargs@verbatimbraces\else\collargs@temp\fi
+ %</latex>
+ \fi
+ }%
+ \expandafter\collargs@wrap\expandafter{\collargs@temp}%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@readContent}
+% This macro, which is an adaptation of
+% \texttt{cprotect}'s environment-grabbing code, collects some delimited
+% text, leaving the result in |\collargsArg|. Before calling it, one must
+% define the following macros: |\collargs@begintag| and |\collargs@endtag|
+% are the content delimiters; |\collargs@tagarg|, if non-empty, is the token
+% or grouped text which must follow a delimiter to be taken into account;
+% |\collargs@commandatend| is the command that will be executed once the
+% content is collected.
+\def\collargs@readContent{%
+ % Define macro which will search for the first begin-tag.
+ \ifcollargs@long\long\fi
+ \collargs@CPT@def\collargs@gobbleOneB\collargs@begintag{%
+ % Assign the collected tokens into a register. The first token in |##1|
+ % will be |\collargs@empty|, so we expand to get rid of it.
+ \expandafter\toks@\expandafter{##1}%
+ % |cprotect| simply grabs the token following the |\collargs@begintag| with
+ % a parameter. We can't do this, because we need the code to work in the
+ % non-verbatim mode, as well, and we might stumble upon a brace there. So
+ % we take a peek.
+ \futurelet\collargs@temp\collargs@gobbleOneB@i
+ }%
+ % Define macro which will search for the first end-tag. We make it long if
+ % so required (by |+|).
+ \ifcollargs@long\long\fi
+ \collargs@CPT@def\collargs@gobbleUntilE\collargs@endtag{%
+ % Expand |\collargs@empty| at the start of |##1|.
+ \expandafter\toksapp\expandafter\toks@\expandafter{##1}%
+ \collargs@gobbleUntilE@i
+ }%
+ % Initialize.
+ \collargs@begins=0\relax
+ \collargsArg{}%
+ \toks@{}%
+ % We will call |\collargs@gobbleUntilE| via the caller control sequence.
+ \collargs@letusecollector\collargs@gobbleUntilE
+ % We insert |\collargs@empty| to avoid the potential debracing problem.
+ \collargs@empty
+}
+% How many begin-tags do we have opened?
+\newcount\collargs@begins
+% An auxiliary macro which |\def|s |#1| so that it will grab everything up
+% until |#2|. Additional parameters may be present before the definition.
+\def\collargs@CPT@def#1#2{%
+ \expandafter\def\expandafter#1%
+ \expandafter##\expandafter1#2%
+}
+% A quark quard.
+\def\collargs@qend{\collargs@qend}
+% This macro will collect the ``environment'', leaving the result in
+% |\collargsArg|. It expects |\collargs@begintag|, |\collargs@endtag| and
+% |\collargs@commandatend| to be set.
+\def\collargs@gobbleOneB@i{%
+ \def\collargs@begins@increment{1}%
+ \ifx\collargs@qend\collargs@temp
+ % We have reached the fake begin-tag. Note that we found the end-tag.
+ \def\collargs@begins@increment{-1}%
+ % Gobble the quark guard.
+ \expandafter\collargs@gobbleOneB@v
+ \else
+ % Append the real begin-tag to the temporary tokens.
+ \etoksapp\toks@{\expandonce\collargs@begintag}%
+ \expandafter\collargs@gobbleOneB@ii
+ \fi
+}%
+% Do we have to check the tag argument (i.e.\ the environment name after |\begin|)?
+\def\collargs@gobbleOneB@ii{%
+ \expandafter\ifx\expandafter\relax\collargs@tagarg\relax
+ \expandafter\collargs@gobbleOneB@vi
+ \else
+ % Yup, so let's (carefully) collect the tag argument.
+ \expandafter\collargs@gobbleOneB@iii
+ \fi
+}
+\def\collargs@gobbleOneB@iii{%
+ \collargs@grabspaces{%
+ \collargs@letusecollector\collargs@gobbleOneB@iv
+ }%
+}
+\def\collargs@gobbleOneB@iv#1{%
+ \def\collargs@temp{#1}%
+ \ifx\collargs@temp\collargs@tagarg
+ % This is the tag argument we've been waiting for!
+ \else
+ % Nope, this |\begin| belongs to someone else.
+ \def\collargs@begins@increment{0}%
+ \fi
+ % Whatever the result was, we have to append the gobbled group to the
+ % temporary toks.
+ \etoksapp\toks@{\collargs@grabbed@spaces\unexpanded{{#1}}}%
+ \collargs@init@grabspaces
+ \collargs@gobbleOneB@vi
+}
+\def\collargs@gobbleOneB@v#1{\collargs@gobbleOneB@vi}
+\def\collargs@gobbleOneB@vi{%
+ % Store.
+ \etoksapp\collargsArg{\the\toks@}%
+ % Advance the begin-tag counter.
+ \advance\collargs@begins\collargs@begins@increment\relax
+ % Find more begin-tags, unless this was the final one.
+ \ifnum\collargs@begins@increment=-1
+ \else
+ \expandafter\collargs@gobbleOneB\expandafter\collargs@empty
+ \fi
+}
+\def\collargs@gobbleUntilE@i{%
+ % Do we have to check the tag argument (i.e.\ the environment name after |\end|)?
+ \expandafter\ifx\expandafter\relax\collargs@tagarg\relax
+ \expandafter\collargs@gobbleUntilE@iv
+ \else
+ % Yup, so let's (carefully) collect the tag argument.
+ \expandafter\collargs@gobbleUntilE@ii
+ \fi
+}
+\def\collargs@gobbleUntilE@ii{%
+ \collargs@grabspaces{%
+ \collargs@letusecollector\collargs@gobbleUntilE@iii
+ }%
+}
+\def\collargs@gobbleUntilE@iii#1{%
+ \etoksapp\toks@{\collargs@grabbed@spaces}%
+ \collargs@init@grabspaces
+ \def\collargs@tempa{#1}%
+ \ifx\collargs@tempa\collargs@tagarg
+ % This is the tag argument we've been waiting for!
+ \expandafter\collargs@gobbleUntilE@iv
+ \else
+ % Nope, this |\end| belongs to someone else. Insert the end tag plus the
+ % tag argument, and collect until the next |\end|.
+ \expandafter\toksapp\expandafter\toks@\expandafter{\collargs@endtag{#1}}%
+ \expandafter\collargs@letusecollector\expandafter\collargs@gobbleUntilE
+ \fi
+}
+\def\collargs@gobbleUntilE@iv{%
+ % Invoke |\collargs@gobbleOneB| with the collected material, plus a fake
+ % begin-tag and a quark guard.
+ \ifcollargsIgnoreNesting
+ \expandafter\collargsArg\expandafter{\the\toks@}%
+ \expandafter\collargs@commandatend
+ \else
+ \expandafter\collargs@gobbleUntilE@v
+ \fi
+}
+\def\collargs@gobbleUntilE@v{%
+ \expanded{%
+ \noexpand\collargs@letusecollector\noexpand\collargs@gobbleOneB
+ \noexpand\collargs@empty
+ \the\toks@
+ % Add a fake begin-tag and a quark guard.
+ \expandonce\collargs@begintag
+ \noexpand\collargs@qend
+ }%
+ \ifnum\collargs@begins<0
+ \expandafter\collargs@commandatend
+ \else
+ \etoksapp\collargsArg{%
+ \expandonce\collargs@endtag
+ \expandafter\ifx\expandafter\relax\collargs@tagarg\relax\else{%
+ \expandonce\collargs@tagarg}\fi
+ }%
+ \toks@={}%
+ \expandafter\collargs@letusecollector\expandafter\collargs@gobbleUntilE
+ \expandafter\collargs@empty
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@e}
+% Embellishments. Each embellishment counts as an argument, in the sense
+% that we will execute |\collargs@appendarg|, with all the processors, for
+% each embellishment separately.
+\def\collargs@e{%
+ % We open an extra group, because |\collargs@appendarg| will close a group
+ % for each embellishment.
+ \global\collargs@fix@requestedtrue
+ \begingroup
+ \ifcollargs@verbatim
+ \expandafter\collargs@e@verbatim
+ \else
+ \expandafter\collargs@e@i
+ \fi
+}
+% Detokenize the embellishment tokens in the verbatim mode.
+\def\collargs@e@verbatim#1{%
+ \expandafter\collargs@e@i\expandafter{\detokenize{#1}}%
+}
+% Ungroup the embellishment tokens, separating them from the rest of the
+% argument specification by a dot.
+\def\collargs@e@i#1{\collargs@e@ii#1.}
+% We now have embellishment tokens in |#1| and the rest of the argument
+% specification in |#2|. Let's grab spaces first.
+\def\collargs@e@ii#1.#2.{%
+ \collargs@grabspaces{\collargs@e@iii#1.#2.}%
+}
+% What's the argument token?
+\def\collargs@e@iii#1.#2.{%
+ \def\collargs@e@iv{\collargs@e@v#1.#2.}%
+ \futurelet\collargs@temp\collargs@e@iv
+}
+% If it is a open or close group character, we surely don't have an
+% embellishment.
+\def\collargs@e@v{%
+ \ifcat\noexpand\collargs@temp\bgroup\relax
+ \let\collargs@marshal\collargs@e@z
+ \else
+ \ifcat\noexpand\collargs@temp\egroup\relax
+ \let\collargs@marshal\collargs@e@z
+ \else
+ \let\collargs@marshal\collargs@e@vi
+ \fi
+ \fi
+ \collargs@marshal
+}
+% We borrow the ``Does |#1| occur within |#2|?'' macro from |pgfutil-common|,
+% but we fix it by executing |\collargs@in@@| in a braced group. This will
+% prevent an |&| in an argument to function as an alignment character; the
+% minor price to pay is that we assign the conditional globally.
+\newif\ifcollargs@in@
+\def\collargs@in@#1#2{%
+ \def\collargs@in@@##1#1##2##3\collargs@in@@{%
+ \ifx\collargs@in@##2\global\collargs@in@false\else\global\collargs@in@true\fi
+ }%
+ {\collargs@in@@#2#1\collargs@in@\collargs@in@@}%
+}
+% Let' see whether the following token, now |#3|, is an embellishment token.
+\def\collargs@e@vi#1.#2.#3{%
+ \collargs@in@{#3}{#1}%
+ \ifcollargs@in@
+ \expandafter\collargs@e@vii
+ \else
+ \expandafter\collargs@e@z
+ \fi
+ #1.#2.#3%
+}
+% |#3| is the current embellishment token. We'll collect its argument using
+% |\collargs@m|, but to do that, we have to (locally) redefine
+% |\collargs@appendarg| and |\collargs@|, which get called by |\collargs@m|.
+\def\collargs@e@vii#1.#2.#3{%
+ % We'll have to execute the original |\collargs@appendarg| later, so let's
+ % remember it. The temporary |\collargs@appendarg| simply stores the
+ % collected argument into |\collargsArg| --- we'll do the processing etc.\
+ % later.
+ \let\collargs@real@appendarg\collargs@appendarg
+ \def\collargs@appendarg##1{\collargsArg{##1}}%
+ % Once |\collargs@m| is done, it will call the redefined |\collargs@| and
+ % thereby get us back into this handler.
+ \def\collargs@{\collargs@e@viii#1.#3}%
+ \collargs@m#2.%
+}
+% The parameters here are as follows. |#1| are the embellishment tokens, and
+% |#2| is the current embellishment token; these get here via our local
+% redefinition of |\collargs@| in |\collargs@e@vii|. |#3| are the rest of the
+% argument specification, which is put behind control sequence |\collargs@| by
+% the |m| handler.
+\def\collargs@e@viii#1.#2#3.{%
+ % Our wrapper puts the current embellishment token in front of the collected
+ % embellishment argument. Note that if the embellishment argument was in
+ % braces, |\collargs@m| has already set one wrapper (which will apply first).
+ \collargs@wrap{#2##1}%
+ % We need to get rid of the current embellishment from embellishments, not to
+ % catch the same embellishment twice.
+ \def\collargs@e@ix##1#2{\collargs@e@x##1}%
+ \collargs@e@ix#1.#3.%
+}
+% When this is executed, the input stream starts with the (remaining)
+% embellishment tokens, followed by a dot, then the rest of the argument
+% specification, also followed by a dot.
+\def\collargs@e@x{%
+ % Process the argument and append it to the storage.
+ \expandafter\collargs@real@appendarg\expandafter{\the\collargsArg}%
+ % |\collargs@real@appendarg| has closed a group, so we open it again, and
+ % start looking for another embellishment token in the input stream.
+ \begingroup
+ \collargs@e@ii
+}
+% The first argument token in not an embellishment token. We finish by
+% consuming the list of embellishment tokens, closing the two groups opened by
+% this handler, and reexecuting the central loop.
+\def\collargs@e@z#1.{\endgroup\endgroup\collargs@}
+% \end{macro}
+%
+% \begin{macro}{\collargs@E}
+% Discard the defaults and execute |e|.
+\def\collargs@E#1#2{\collargs@e{#1}}
+% \end{macro}
+%
+%
+% \subsubsection{The verbatim modes}
+% \label{sec:code:collargs:verbatim}
+%
+% \begin{macro}{\collargsVerbatim,\collargsVerb,\collargsNoVerbatim}
+% These macros set the two verbatim-related
+% conditionals, |\ifcollargs@verbatim| and |\ifcollargs@verbatimbraces|,
+% and then call |\collargs@make@verbatim| to effect the requested
+% category code changes (among other things). A group should be opened
+% prior to executing either of them. After execution, they are
+% redefined to minimize the effort needed to enter into another mode in
+% an embedded group. Below, we first define all the possible transitions.
+\let\collargs@NoVerbatimAfterNoVerbatim\relax
+\def\collargs@VerbAfterNoVerbatim{%
+ \collargs@verbatimtrue
+ \collargs@verbatimbracesfalse
+ \collargs@make@verbatim
+ \collargs@after{Verb}%
+}
+\def\collargs@VerbatimAfterNoVerbatim{%
+ \collargs@verbatimtrue
+ \collargs@verbatimbracestrue
+ \collargs@make@verbatim
+ \collargs@after{Verbatim}%
+}
+\def\collargs@NoVerbatimAfterVerb{%
+ \collargs@verbatimfalse
+ \collargs@verbatimbracesfalse
+ \collargs@make@other@groups
+ \collargs@make@no@verbatim
+ \collargs@after{NoVerbatim}%
+}
+\def\collargs@VerbAfterVerb{%
+ \collargs@make@other@groups
+}
+\def\collargs@VerbatimAfterVerb{%
+ \collargs@verbatimbracestrue
+ \collargs@make@other@groups
+ % Process the lists of grouping characters, created by
+ % |\collargs@make@verbatim|, making these characters of category ``other''.
+ \def\collargs@do##1{\catcode##1=12 }%
+ \collargs@bgroups
+ \collargs@egroups
+ \collargs@after{Verbatim}%
+}%
+\let\collargs@NoVerbatimAfterVerbatim\collargs@NoVerbatimAfterVerb
+\def\collargs@VerbAfterVerbatim{%
+ \collargs@verbatimbracesfalse
+ \collargs@make@other@groups
+ % Process the lists of grouping characters, created by
+ % |\collargs@make@verbatim|, making these characters be of their normal
+ % category.
+ \def\collargs@do##1{\catcode##1=1 }%
+ \collargs@bgroups
+ \def\collargs@do##1{\catcode##1=2 }%
+ \collargs@egroups
+ \collargs@after{Verb}%
+}%
+\let\collargs@VerbatimAfterVerbatim\collargs@VerbAfterVerb
+% This macro expects |#1| to be the mode just entered (|Verbatim|, |Verb| or
+% |NoVerbatim|), and points macros |\collargsVerbatim|, |\collargsVerb| and
+% |\collargsNoVerbatim| to the appropriate transition macro.
+\def\collargs@after#1{%
+ \letcs\collargsVerbatim{collargs@VerbatimAfter#1}%
+ \letcs\collargsVerb{collargs@VerbAfter#1}%
+ \letcs\collargsNoVerbatim{collargs@NoVerbatimAfter#1}%
+}
+% The first transition is always from the non-verbatim mode.
+\collargs@after{NoVerbatim}
+% \end{macro}
+%
+% \begin{macro}{\collargs@bgroups,\collargs@egroups}
+% Initialize the lists of the current grouping characters used in the
+% redefinitions of macros |\collargsVerbatim| and |\collargsVerb| above.
+% Each entry is of form |\collargs@do|\marg{character code}. These lists
+% will be populated by |\collargs@make@verbatim|. They may be local, as they
+% only used within the group opened for a verbatim environment.
+\def\collargs@bgroups{}%
+\def\collargs@egroups{}%
+% \end{macro}
+%
+% \begin{macro}{\collargs@cc}
+% This macro recalls the category code of character |#1|. In
+% \hologo{LuaTeX}, we simply look up the category code in the original
+% category code table; in other engines, we have stored the original category
+% code into |\collargs@cc@|\meta{character code} by
+% |\collargs@make@verbatim|. (Note that |#1| is a character, not a number.)
+\ifdefined\luatexversion
+ \def\collargs@cc#1{%
+ \directlua{tex.sprint(tex.getcatcode(\collargs@catcodetable@original,
+ \the\numexpr\expandafter`\csname#1\endcsname\relax))}%
+ }
+\else
+ \def\collargs@cc#1{%
+ \ifcsname collargs@cc@\the\numexpr\expandafter`\csname#1\endcsname\endcsname
+ \csname collargs@cc@\the\numexpr\expandafter`\csname#1\endcsname\endcsname
+ \else
+ 12%
+ \fi
+ }
+\fi
+% \end{macro}
+%
+%
+% \begin{macro}{\collargs@other@bgroup,\collargs@other@egroup,\collargsBraces}
+% Macros |\collargs@other@bgroup| and
+% |\collargs@other@egroup| hold the characters of category code ``other''
+% which will play the role of grouping characters in the full verbatim mode.
+% They are usually defined when entering a verbatim mode in
+% |\collargs@make@verbatim|, but may be also set by the user via
+% |\collargsBraces| (it is not even necessary to select characters which
+% indeed have the grouping function in the outside category code regime).
+% The setting process is indirect: executing |\collargsBraces| merely sets
+% |\collargs@make@other@groups|, which gets executed by the subsequent
+% |\collargsVerbatim|, |\collargsVerb| or |\collargsNoVerbatim| (either
+% directly or via |\collargs@make@verbatim|).
+\def\collargsBraces#1{%
+ \expandafter\collargs@braces@i\detokenize{#1}\relax
+}
+\def\collargs@braces@i#1#2#3\relax{%
+ \def\collargs@make@other@groups{%
+ \def\collargs@other@bgroup{#1}%
+ \def\collargs@other@egroup{#2}%
+ }%
+}
+\def\collargs@make@other@groups{}
+% \end{macro}
+%
+% \begin{macro}{\collargs@catcodetable@verbatim,\catcodetable@atletter,\collargs@catcodetable@initex}
+% We declare several new catcode tables in \hologo{LuaTeX}, the most
+% important one being |\collargs@catcodetable@verbatim|, where all characters
+% have category code 12. We only need the other two tables in some formats:
+% |\collargs@catcodetable@atletter| holds the catcode in effect at the time
+% of loading the package, and |\collargs@catcodetable@initex| is the
+% \hologo{iniTeX} table.
+\ifdefined\luatexversion
+ %<*latex,context>
+ \newcatcodetable\collargs@catcodetable@verbatim
+ %<latex>\let\collargs@catcodetable@atletter\catcodetable@atletter
+ %<context>\newcatcodetable\collargs@catcodetable@atletter
+ %</latex,context>
+ %<*plain>
+ \ifdefined\collargs@catcodetable@verbatim\else
+ \chardef\collargs@catcodetable@verbatim=4242
+ \fi
+ \chardef\collargs@catcodetable@atletter=%
+ \number\numexpr\collargs@catcodetable@verbatim+1\relax
+ \chardef\collargs@catcodetable@initex=%
+ \number\numexpr\collargs@catcodetable@verbatim+2\relax
+ \initcatcodetable\collargs@catcodetable@initex
+ %</plain>
+ %<plain,context>\savecatcodetable\collargs@catcodetable@atletter
+ \begingroup
+ \@firstofone{%
+ %<latex>\catcodetable\catcodetable@initex
+ %<plain>\catcodetable\collargs@catcodetable@initex
+ %<context>\catcodetable\inicatcodes
+ \catcode`\\=12
+ \catcode13=12
+ \catcode0=12
+ \catcode32=12
+ \catcode`\%=12
+ \catcode127=12
+ \def\collargs@do#1{\catcode#1=12 }%
+ \collargs@forrange{`\a}{`\z}%
+ \collargs@forrange{`\A}{`\Z}%
+ \savecatcodetable\collargs@catcodetable@verbatim
+ \endgroup
+ }%
+\fi
+% \end{macro}
+%
+% \begin{collargskey}{verbatim ranges}
+% \begin{macro}{\collargsVerbatimRanges,\collargs@verbatim@ranges}
+% This key and macro set the character ranges to which the verbatim mode
+% will apply (in \hologo{pdfTeX} and \hologo{XeTeX}), or which will be
+% inspected for grouping and comment characters (in \hologo{LuaTeX}). In
+% \hologo{pdfTeX}, the default value |0-255| should really remain
+% unchanged.
+\collargsSet{
+ verbatim ranges/.store in=\collargs@verbatim@ranges,
+}
+\def\collargsVerbatimRanges#1{\def\collargs@verbatim@ranges{#1}}
+\def\collargs@verbatim@ranges{0-255}
+% \end{macro}
+% \end{collargskey}
+%
+% \begin{macro}{\collargs@make@verbatim}
+% This macro changes the category code of all characters to ``other'' ---
+% except the grouping characters in the partial verbatim mode. While doing
+% that, it also stores (unless we're in \hologo{LuaTeX}) the current category
+% codes into |\collargs@cc@|\meta{character code} (easily recallable by
+% |\collargs@cc|), redefines the ``primary'' grouping characters
+% |\collargs@make@other@bgroup| and |\collargs@make@other@egroup| if
+% necessary, and ``remembers'' the grouping characters (storing them into
+% |\collargs@bgroups| and |\collargs@egroups|) and the comment characters
+% (storing them into |\collargs@comments|).
+%
+% In \hologo{LuaTeX}, we can use catcode tables, so we change the category
+% codes by switching to category code table
+% |\collargs@catcodetable@verbatim|. In other engines, we have to change the
+% codes manually. In order to offer some flexibility in \hologo{XeTeX}, we
+% perform the change for characters in |verbatim ranges|.
+\ifdefined\luatexversion
+ \def\collargs@make@verbatim{%
+ \directlua{%
+ for from, to in string.gmatch(
+ "\luaescapestring{\collargs@verbatim@ranges}",
+ "(\collargs@percentchar d+)-(\collargs@percentchar d+)"
+ ) do
+ for char = tex.round(from), tex.round(to) do
+ catcode = tex.catcode[char]
+ % For category codes 1, 2 and 14, we have to call macros
+ % |\collargs@make@verbatim@bgroup|, |\collargs@make@verbatim@egroup|
+ % and |\collargs@make@verbatim@comment|, same as for engines other
+ % than \hologo{LuaTeX}.
+ if catcode == 1 then
+ tex.sprint(
+ \number\collargs@catcodetable@atletter,
+ "\noexpand\\collargs@make@verbatim@bgroup{" .. char .. "}")
+ elseif catcode == 2 then
+ tex.sprint(
+ \number\collargs@catcodetable@atletter,
+ "\noexpand\\collargs@make@verbatim@egroup{" .. char .. "}")
+ elseif catcode == 14 then
+ tex.sprint(
+ \number\collargs@catcodetable@atletter,
+ "\noexpand\\collargs@make@verbatim@comment{" .. char .. "}")
+ end
+ end
+ end
+ }%
+ \edef\collargs@catcodetable@original{\the\catcodetable}%
+ \catcodetable\collargs@catcodetable@verbatim
+ % Even in \hologo{LuaTeX}, we switch between the verbatim braces regimes by
+ % hand.
+ \ifcollargs@verbatimbraces
+ \else
+ \def\collargs@do##1{\catcode##1=1\relax}%
+ \collargs@bgroups
+ \def\collargs@do##1{\catcode##1=2\relax}%
+ \collargs@egroups
+ \fi
+ }
+\else
+ % The non-\hologo{LuaTeX} version:
+ \def\collargs@make@verbatim{%
+ \ifdefempty\collargs@make@other@groups{}{%
+ % The user has executed |\collargsBraces|. We first apply that setting
+ % by executing macro |\collargs@make@other@groups|, and then disable our
+ % automatic setting of the primary grouping characters.
+ \collargs@make@other@groups
+ \def\collargs@make@other@groups{}%
+ \let\collargs@make@other@bgroup\@gobble
+ \let\collargs@make@other@egroup\@gobble
+ }%
+ % Initialize the list of current comment characters. Each entry is of
+ % form |\collargs@do|\marg{character code}. The definition must be global,
+ % because the macro will be used only once we exit the current group (by
+ % |\collargs@fix@cc@from@other@comment|, if at all).
+ \gdef\collargs@comments{}%
+ \let\collargs@do\collargs@make@verbatim@char
+ \expandafter\collargs@forranges\expandafter{\collargs@verbatim@ranges}%
+ }
+ \def\collargs@make@verbatim@char#1{%
+ % Store the current category code of the current character.
+ \ifnum\catcode#1=12
+ \else
+ \csedef{collargs@cc@#1}{\the\catcode#1}%
+ \fi
+ \ifnum\catcode#1=1
+ \collargs@make@verbatim@bgroup{#1}%
+ \else
+ \ifnum\catcode#1=2
+ \collargs@make@verbatim@egroup{#1}%
+ \else
+ \ifnum\catcode#1=14
+ \collargs@make@verbatim@comment{#1}%
+ \fi
+ % Change the category code of the current character (including the
+ % comment characters).
+ \ifnum\catcode#1=12
+ \else
+ \catcode#1=12\relax
+ \fi
+ \fi
+ \fi
+ }
+\fi
+% \end{macro}
+%
+% \begin{macro}{\collargs@make@verbatim@bgroup}
+% This macro changes the category of
+% the opening group character to ``other'', but only in the full verbatim
+% mode. Next, it populates |\collargs@bgroups|, to facilitate the potential
+% transition into the other verbatim mode. Finally, it executes
+% |\collargs@make@other@bgroup|, which stores the ``other'' variant of the
+% current character into |\collargs@other@bgroup|, and automatically disables
+% itself, so that it is only executed for the first encountered opening group
+% character --- unless it was already |\relax|ed at the top of
+% |\collargs@make@verbatim| as a consequence of the user executing
+% |\collargsBraces|.
+\def\collargs@make@verbatim@bgroup#1{%
+ \ifcollargs@verbatimbraces
+ \catcode#1=12\relax
+ \fi
+ \appto\collargs@bgroups{\collargs@do{#1}}%
+ \collargs@make@other@bgroup{#1}%
+}
+\def\collargs@make@other@bgroup#1{%
+ \collargs@make@char\collargs@other@bgroup{#1}{12}%
+ \let\collargs@make@other@bgroup\@gobble
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@make@verbatim@egroup}
+% Ditto for the closing group character.
+\def\collargs@make@verbatim@egroup#1{%
+ \ifcollargs@verbatimbraces
+ \catcode#1=12\relax
+ \fi
+ \appto\collargs@egroups{\collargs@do{#1}}%
+ \collargs@make@other@egroup{#1}%
+}
+\def\collargs@make@other@egroup#1{%
+ \collargs@make@char\collargs@other@egroup{#1}{12}%
+ \let\collargs@make@other@egroup\@gobble
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@make@verbatim@comment}
+% This macro populates
+% |\collargs@make@comments@other|.
+\def\collargs@make@verbatim@comment#1{%
+ \gappto\collargs@comments{\collargs@do{#1}}%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@make@no@verbatim}
+% This macro switches back to the non-verbatim mode: in \hologo{LuaTeX}, by
+% switching to the original catcode table; in other engines, by recalling the
+% stored category codes.
+\ifdefined\luatexversion
+ \def\collargs@make@no@verbatim{%
+ \catcodetable\collargs@catcodetable@original\relax
+ }%
+\else
+\def\collargs@make@no@verbatim{%
+ \let\collargs@do\collargs@make@no@verbatim@char
+ \expandafter\collargs@forranges\expandafter{\collargs@verbatim@ranges}%
+}
+\fi
+\def\collargs@make@no@verbatim@char#1{%
+ % The original category code of a characted was stored into
+ % |\collargs@cc@|\meta{character code} by |\collargs@make@verbatim|. (We don't
+ % use |\collargs@cc|, because we have a number.)
+ \ifcsname collargs@cc@#1\endcsname
+ \catcode#1=\csname collargs@cc@#1\endcsname\relax
+ % We don't have to restore category code 12.
+ \fi
+}
+% \end{macro}
+%
+%
+% \subsubsection{Transition between the verbatim and the non-verbatim mode}
+% \label{sec:code:collargs:fix}
+%
+% At the transition from verbatim to non-verbatim mode, and vice versa, we
+% sometimes have to fix the category code of the next argument token. This
+% happens when we have an optional argument type in one mode followed by an
+% argument type in another mode, but the optional argument is absent, or when
+% an optional, but absent, verbatim argument is the last argument in the
+% specification. The problem arises because the presence of optional arguments
+% is determined by looking ahead in the input stream; when the argument is
+% absent, this means that we have fixed the category code of the next token.
+% CollArgs addresses this issue by noting the situations where a token receives
+% the wrong category code, and then does its best to replace that token with
+% the same character of the appropriate category code.
+%
+% \begin{macro}{\ifcollargs@fix@requested}
+% This conditional is set, globally,
+% by the optional argument handlers when the argument is in fact absent,
+% and reset in the central loop after applying the fix if necessary.
+\newif\ifcollargs@fix@requested
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix}
+% This macro selects the fixer appropriate to the transition between the
+% previous verbatim mode (determined by |\ifcollargs@last@verbatim| and
+% |\ifcollargs@last@verbatimbraces|) and the current verbatim mode (which
+% is determined by macros |\ifcollargs@verbatim| and
+% |\ifcollargs@verbatimbraces|); if the category code fix was not
+% requested (for this, we check |\ifcollargs@fix@requested|), the
+% macro simply executes the next-code given as the sole argument.
+% The name of the fixer macro has the form
+% |\collargs@fix@|\meta{last mode}|to|\meta{current mode}, where
+% the modes are given by mnemonic codes: |V| = full verbatim, |v| =
+% partial verbatim, and |N| = non-verbatim.
+\long\def\collargs@fix#1{%
+ % Going through |\edef| + |\unexpanded| avoids doubling the hashes.
+ \edef\collargs@fix@next{\unexpanded{#1}}%
+ \ifcollargs@fix@requested
+ \letcs\collargs@action{collargs@fix@%
+ \ifcollargs@last@verbatim
+ \ifcollargs@last@verbatimbraces V\else v\fi
+ \else
+ N%
+ \fi
+ to%
+ \ifcollargs@verbatim
+ \ifcollargs@verbatimbraces V\else v\fi
+ \else
+ N%
+ \fi
+ }%
+ \else
+ \let\collargs@action\collargs@fix@next
+ \fi
+ \collargs@action
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@NtoN,\collargs@fix@vtov,\collargs@fix@VtoV}
+% \indentmacrocode
+% Nothing to do, continue with the next-code.
+\def\collargs@fix@NtoN{\collargs@fix@next}
+\let\collargs@fix@vtov\collargs@fix@NtoN
+\let\collargs@fix@VtoV\collargs@fix@NtoN
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@Ntov}
+% We do nothing for the group tokens; for other tokens, we redirect to
+% |\collargs@fix@NtoV|.
+\def\collargs@fix@Ntov{%
+ \futurelet\collargs@temp\collargs@fix@cc@to@other@ii
+}
+\def\collargs@fix@cc@to@other@ii{%
+ \ifcat\noexpand\collargs@temp\bgroup
+ \let\collargs@action\collargs@fix@next
+ \else
+ \ifcat\noexpand\collargs@temp\egroup
+ \let\collargs@action\collargs@fix@next
+ \else
+ \let\collargs@action\collargs@fix@NtoV
+ \fi
+ \fi
+ \collargs@action
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@NtoV}
+% The only complication here is that we might be in front of a control
+% sequence that was a result of a previous fix in the other direction.
+\def\collargs@fix@NtoV{%
+ \ifcollargs@double@fix
+ \ifcollargs@in@second@fix
+ \expandafter\expandafter\expandafter\collargs@fix@NtoV@secondfix
+ \else
+ \expandafter\expandafter\expandafter\collargs@fix@NtoV@onemore
+ \fi
+ \else
+ \expandafter\collargs@fix@NtoV@singlefix
+ \fi
+}
+% This is the usual situation of a single fix. We just use |\string| on
+% the next token here (but note that some situations can't be saved: noone
+% can bring a comment back to life, or distinguish a newline and a space)
+\def\collargs@fix@NtoV@singlefix{%
+ \expandafter\collargs@fix@next\string
+}
+% If this is the first fix of two, we know |#1| is a control sequence, so it is
+% safe to grab it.
+\def\collargs@fix@NtoV@onemore#1{%
+ \collargs@do@one@more@fix{%
+ \expandafter\collargs@fix@next\string#1%
+ }%
+}
+% If this is the second fix of the two, we have to check whether the next token
+% is a control sequence, and if it is, we need to remember it. Afterwards, we
+% redirect to the single-fix.
+\def\collargs@fix@NtoV@secondfix{%
+ \if\noexpand\collargs@temp\relax
+ \expandafter\collargs@fix@NtoV@secondfix@i
+ \else
+ \expandafter\collargs@fix@NtoV@singlefix
+ \fi
+}
+\def\collargs@fix@NtoV@secondfix@i#1{%
+ \gdef\collargs@double@fix@cs@ii{#1}%
+ \collargs@fix@NtoV@singlefix#1%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@vtoN}
+% Do nothing for the grouping tokens, redirect to |\collargs@fix@VtoN| for
+% other tokens.
+\def\collargs@fix@vtoN{%
+ \futurelet\collargs@token\collargs@fix@vtoN@i
+}
+\def\collargs@fix@vtoN@i{%
+ \ifcat\noexpand\collargs@token\bgroup
+ \expandafter\collargs@fix@next
+ \else
+ \ifcat\noexpand\collargs@token\egroup
+ \expandafter\expandafter\expandafter\collargs@fix@next
+ \else
+ \expandafter\expandafter\expandafter\collargs@fix@VtoN
+ \fi
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@vtoV}
+% Redirect group tokens to |\collargs@fix@NtoV|, and do nothing for other
+% tokens.
+\def\collargs@fix@vtoV{%
+ \futurelet\collargs@token\collargs@fix@vtoV@i
+}
+\def\collargs@fix@vtoV@i{%
+ \ifcat\noexpand\collargs@token\bgroup
+ \expandafter\collargs@fix@NtoV
+ \else
+ \ifcat\noexpand\collargs@token\egroup
+ \expandafter\expandafter\expandafter\collargs@fix@NtoV
+ \else
+ \expandafter\expandafter\expandafter\collargs@fix@next
+ \fi
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@Vtov}
+% Redirect group tokens to |\collargs@fix@VtoN|, and do nothing for other
+% tokens. |#1| is surely of category 12, so we can safely grab it.
+\def\collargs@fix@catcode@of@braces@fromverbatim#1{%
+ \ifnum\catcode`#1=1
+ \expandafter\collargs@fix@VtoN
+ \expandafter#1%
+ \else
+ \ifnum\catcode`#1=2
+ \expandafter\expandafter\expandafter\collargs@fix@cc@VtoN
+ \expandafter\expandafter\expandafter#1%
+ \else
+ \expandafter\expandafter\expandafter\collargs@fix@next
+ \fi
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@VtoN}
+% This is the only complicated part. Control sequences and comments (but not
+% grouping characters!) require special attention. We're fine to grab the
+% token right away, as we know it is of category 12.
+\def\collargs@fix@VtoN#1{%
+ \ifnum\catcode`#1=0
+ \expandafter\collargs@fix@VtoN@escape
+ \else
+ \ifnum\catcode`#1=14
+ \expandafter\expandafter\expandafter\collargs@fix@VtoN@comment
+ \else
+ \expandafter\expandafter\expandafter\collargs@fix@VtoN@token
+ \fi
+ \fi
+ #1%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@VtoN@token}
+% We create a new character with the current
+% category code behing the next-code. This works even for grouping
+% characters.
+\def\collargs@fix@VtoN@token#1{%
+ \collargs@insert@char\collargs@fix@next{`#1}{\the\catcode`#1}%
+}
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@VtoN@comment}
+% This macro defines a macro which will,
+% when placed at a comment character, remove the tokens until the end of the
+% line. The code is adapted from the TeX.SE answer at
+% \url(https://){tex.stackexchange.com/a/10454/16819} by Bruno Le Floch.
+\def\collargs@defcommentstripper#1#2{%
+ % We chuck a parameter into the following definition, to grab the (verbatim)
+ % comment character. This is why this macro must be executed precisely
+ % before the (verbatim) comment character.
+ \def#1##1{%
+ \begingroup%
+ \escapechar=`\\%
+ \catcode\endlinechar=\active%
+ % We assign the ``other'' category code to comment characters. Without
+ % this, comment characters behind the first one make trouble: there would
+ % be no |^||^M| at the end of the line, so the comment stripper would
+ % gobble the following line as well; in fact, it would gobble all
+ % subsequent lines containing a comment character. We also make sure to
+ % change the category code of \emph{all} comment characters, even if there
+ % is usually just one.
+ \def\collargs@do####1{\catcode####1=12 }%
+ \collargs@comments
+ \csname\string#1\endcsname%
+ }%
+ \begingroup%
+ \escapechar=`\\%
+ \lccode`\~=\endlinechar%
+ \lowercase{%
+ \expandafter\endgroup
+ \expandafter\def\csname\string#1\endcsname##1~%
+ }{%
+ % I have removed |\space| from the end of the following line. We don't
+ % want it for our application.
+ \endgroup#2%
+ }%
+}
+\collargs@defcommentstripper\collargs@fix@VtoN@comment{%
+ \collargs@fix@next
+}
+% We don't need the generator any more.
+\let\collargs@defcommentstripper\relax
+% \end{macro}
+%
+% \begin{macro}{\collargs@fix@VtoN@escape}
+% An escape character of category code 12
+% is the most challenging --- and we won't get things completely right --- as
+% we have swim further down the input stream to create a control sequence.
+% This macro will throw away the verbatim escape character |#1|.
+\def\collargs@fix@VtoN@escape#1{%
+ \ifcollargs@double@fix
+ % We need to do things in a special way if we're in the double-fix
+ % situation triggered by the previous fixing of a control sequence
+ % (probably this very one). In that case, we can't collect it in the usual
+ % way because the entire control sequence is spelled out in verbatim.
+ \expandafter\collargs@fix@VtoN@escape@d
+ \else
+ % This here is the usual situation where the escape character was tokenized
+ % verbatim, but the control sequence name itself will be collected (right
+ % away) in the non-verbatim regime.
+ \expandafter\collargs@fix@VtoN@escape@i
+ \fi
+}
+\def\collargs@fix@VtoN@escape@i{%
+ % The sole character forming a control symbol name may be of any category.
+ % Temporarily redefining the category codes of the craziest characters allows
+ % |\collargs@fix@VtoN@escape@ii| to simply grab the following
+ % character.
+ \begingroup
+ \catcode`\\=12
+ \catcode`\{=12
+ \catcode`\}=12
+ \catcode`\ =12
+ \collargs@fix@VtoN@escape@ii
+}
+% The argument is the first character of the control sequence name.
+\def\collargs@fix@VtoN@escape@ii#1{%
+ \endgroup
+ \def\collargs@csname{#1}%
+ % Only if |#1| is a letter may the control sequence name continue.
+ \ifnum\catcode`#1=11
+ \expandafter\collargs@fix@VtoN@escape@iii
+ \else
+ % In the case of a control space, we have to throw away the following
+ % spaces.
+ \ifnum\catcode`#1=10
+ \expandafter\expandafter\expandafter\collargs@fix@VtoN@escape@s
+ \else
+ % We have a control symbol. That means that we haven't peeked ahead and
+ % can thus skip |\collargs@fix@VtoN@escape@z|.
+ \expandafter\expandafter\expandafter\collargs@fix@VtoN@escape@z@i
+ \fi
+ \fi
+}
+% We still have to collect the rest of the control sequence name. Braces have
+% their usual meaning again, so we have to check for them explicitly (and bail
+% out if we stumble upon them).
+\def\collargs@fix@VtoN@escape@iii{%
+ \futurelet\collargs@temp\collargs@fix@VtoN@escape@iv
+}
+\def\collargs@fix@VtoN@escape@iv{%
+ \ifcat\noexpand\collargs@temp\bgroup
+ \let\collargs@action\collargs@fix@VtoN@escape@z
+ \else
+ \ifcat\noexpand\collargs@temp\egroup
+ \let\collargs@action\collargs@fix@VtoN@escape@z
+ \else
+ \expandafter\ifx\space\collargs@temp
+ \let\collargs@action\collargs@fix@VtoN@escape@s
+ \else
+ \let\collargs@action\collargs@fix@VtoN@escape@v
+ \fi
+ \fi
+ \fi
+ \collargs@action
+}
+% If we have a letter, store it and loop back, otherwise finish.
+\def\collargs@fix@VtoN@escape@v#1{%
+ \ifcat\noexpand#1a%
+ \appto\collargs@csname{#1}%
+ \expandafter\collargs@fix@VtoN@escape@iii
+ \else
+ \expandafter\collargs@fix@VtoN@escape@z\expandafter#1%
+ \fi
+}
+% Throw away the following spaces.
+\def\collargs@fix@VtoN@escape@s{%
+ \futurelet\collargs@temp\collargs@fix@VtoN@escape@s@i
+}
+\def\collargs@fix@VtoN@escape@s@i{%
+ \expandafter\ifx\space\collargs@temp
+ \expandafter\collargs@fix@VtoN@escape@s@ii
+ \else
+ \expandafter\collargs@fix@VtoN@escape@z
+ \fi
+}
+\def\collargs@fix@VtoN@escape@s@ii{%
+ \expandafter\collargs@fix@VtoN@escape@z\romannumeral-0%
+}
+% Once we have collected the control sequence name into |\collargs@csname|, we
+% will create the control sequence behind the next-code. However, we have two
+% complications. The minor one is that |\csname| defines an unexisting control
+% sequence to mean |\relax|, so we have to check whether the control sequence
+% we will create is defined, and if not, ``undefine'' it in advance.
+% ^^A todo: do nicer
+\def\collargs@fix@VtoN@escape@z@i{%
+ \collargs@fix@VtoN@escape@z@maybe@undefine@cs@begin
+ \collargs@fix@VtoN@escape@z@ii
+}%
+\def\collargs@fix@VtoN@escape@z@maybe@undefine@cs@begin{%
+ \ifcsname\collargs@csname\endcsname
+ \@tempswatrue
+ \else
+ \@tempswafalse
+ \fi
+}
+\def\collargs@fix@VtoN@escape@z@maybe@undefine@cs@end{%
+ \if@tempswa
+ \else
+ \cslet{\collargs@csname}\collargs@undefined
+ \fi
+}
+\def\collargs@fix@VtoN@escape@z@ii{%
+ \expandafter\collargs@fix@VtoN@escape@z@maybe@undefine@cs@end
+ \expandafter\collargs@fix@next\csname\collargs@csname\endcsname
+}
+% The second complication is much greater, but it only applies to control words
+% and spaces, and that's why control symbols went directly to the macro above.
+% Control words and spaces will only get there via a detour through the
+% following macro.
+%
+% The problem is that collecting the control word\slash space name peeked ahead
+% in the stream, so the character following the control sequence (name) is
+% already tokenized. We will (at least partially) address this by requesting a
+% ``double-fix'': until the control sequence we're about to create is consumed
+% into some argument, each category code fix will fix two ``tokens'' rather
+% than one.
+\def\collargs@fix@VtoN@escape@z{%
+ \collargs@if@one@more@fix{%
+ % Some previous fixing has requested a double fix, so let's do it.
+ % Afterwards, redirect to the control symbol code
+ % |\collargs@fix@VtoN@escape@z@i|. It will surely use the correct
+ % |\collargs@csname| because we do the second fix in a group.
+ \collargs@do@one@more@fix\collargs@fix@VtoN@escape@z@i
+ }{%
+ % Remember the collected control sequence. It will be used in
+ % |\collargs@cancel@double@fix|.
+ \collargs@fix@VtoN@escape@z@maybe@undefine@cs@begin
+ \xdef\collargs@double@fix@cs@i{\expandonce{\csname\collargs@csname\endcsname}}%
+ \collargs@fix@VtoN@escape@z@maybe@undefine@cs@end
+ % Request the double-fix.
+ \global\collargs@double@fixtrue
+ % The complication is addressed, redirect to the control symbol finish.
+ \collargs@fix@VtoN@escape@z@ii
+ }%
+}
+% When we have to ``redo'' a control sequence, because it was ping-ponged back
+% into the verbatim mode, we cannot collect it by
+% |\collargs@fix@VtoN@escape@i|, because it is spelled out entirely in
+% verbatim. However, we have seen this control sequence before, and remembered
+% it, so we'll simply grab it. Another complication is that we might be either
+% at the ``first'' control sequence, whose fixing created all these double-fix
+% trouble, or at the ``second'' control sequence, if the first one was
+% immediately followed by another one. But we have remembered both of them:
+% the first one in |\collargs@fix@VtoN@escape@z|, the second one in
+% |\collargs@fix@NtoV@secondfix|.
+\def\collargs@fix@VtoN@escape@d{%
+ \ifcollargs@in@second@fix
+ \expandafter\collargs@fix@VtoN@escape@d@i
+ \expandafter\collargs@double@fix@cs@ii
+ \else
+ \expandafter\collargs@fix@VtoN@escape@d@i
+ \expandafter\collargs@double@fix@cs@i
+ \fi
+}
+% We have the contents of either |\collargs@double@fix@cs@i| or
+% |\collargs@double@fix@cs@ii| here, a control sequence in both cases.
+\def\collargs@fix@VtoN@escape@d@i#1{%
+ \expandafter\expandafter\expandafter\collargs@fix@VtoN@escape@d@ii
+ \expandafter\string#1\relax
+}
+% We have the verbatimized control sequence name in |#2| (|#1| is the escape
+% character). By storing it into |\collargs@csname|, we pretend we have
+% collected it. By defining and executing |\collargs@fix@VtoN@escape@d@iii|,
+% we actually gobble it from the input stream. Finally, we reroute to
+% |\collargs@fix@VtoN@escape@z|.
+\def\collargs@fix@VtoN@escape@d@ii#1#2\relax{%
+ \def\collargs@csname{#2}%
+ \def\collargs@fix@VtoN@escape@d@iii#2{%
+ \collargs@fix@VtoN@escape@z
+ }%
+ \collargs@fix@VtoN@escape@d@iii
+}
+% This conditional signals a double-fix request. It should be always set
+% globally, because it is cleared by |\collargs@double@fixfalse| in a group.
+\newif\ifcollargs@double@fix
+% This conditional signals that we're currently performing the second fix.
+\newif\ifcollargs@in@second@fix
+% Inspect the two conditionals above to decide whether we have to perform
+% another fix: if so, execute the first argument, otherwise the second one.
+% This macro is called only from |\collargs@fix@VtoN@escape@z| and
+% |\collargs@fix@NtoV|, because these are the only two places where we might
+% need the second fix, ping-ponging a control sequence between the verbatim and
+% the non-verbatim mode.
+\def\collargs@if@one@more@fix{%
+ \ifcollargs@double@fix
+ \ifcollargs@in@second@fix
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \else
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \fi
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\def\collargs@do@one@more@fix#1{%
+ % We perform the second fix in a group, signalling that we're performing
+ % it.
+ \begingroup
+ \collargs@in@second@fixtrue
+ % Reexecute the fixing routine, at the end, close the group and execute
+ % the given code afterwards.
+ \collargs@fix{%
+ \endgroup
+ #1%
+ }%
+}
+% This macro is called from |\collargs@appendarg| to cancel the double-fix
+% request.
+\def\collargs@cancel@double@fix{%
+ % |\collargs@appendarg| is only executed when something was actually
+ % consumed. We thus know that at least one of the problematic ``tokens'' is
+ % gone, so the double fix is not necessary anymore.
+ \global\collargs@double@fixfalse
+ % What we have to figure out, still, is whether both problematic ``tokens''
+ % we consumed. If so, no more fixing is required. But if only one of them
+ % was consumed, we need to request the normal, single, fix for the remaining
+ % ``token''.
+ \begingroup
+ % This will attach the delimiters directly to the argument, so we'll see what
+ % was actually consumed.
+ \collargs@process@arg
+ % We compare what was consumed when collecting the current argument with the
+ % control word that triggered double-fixing. If they match, only the
+ % offending control word was consumed, so we need to set the fix request to
+ % true for the following token.
+ \edef\collargs@temp{\the\collargsArg}%
+ \edef\collargs@tempa{\expandafter\string\collargs@double@fix@cs@i}%
+ \ifx\collargs@temp\collargs@tempa
+ \global\collargs@fix@requestedtrue
+ \fi
+ \endgroup
+}
+% \end{macro}
+%
+%
+% \begin{macro}{\collargs@insert@char,\collargs@make@char}
+% These macros create a character of character code |#2| and category code
+% |#3|. The first macro inserts it into the stream behind the code in |#1|;
+% the second one defines the control sequence in |#1| to hold the created
+% character (clearly, it should not be used for categories 1 and 2).
+%
+% We use the facilities of \hologo{LuaTeX}, \hologo{XeTeX} and \hologo{LaTeX}
+% where possible. In the end, we only have to implement our own macros for
+% plain \hologo{pdfTeX}.
+%<!context>\ifdefined\luatexversion
+ \def\collargs@insert@char#1#2#3{%
+ \edef\collargs@temp{\unexpanded{#1}}%
+ \expandafter\collargs@temp\directlua{%
+ tex.cprint(\number#3,string.char(\number#2))}%
+ }%
+ \def\collargs@make@char#1#2#3{%
+ \edef#1{\directlua{tex.cprint(\number#3,string.char(\number#2))}}%
+ }%
+%<*!context>
+\else
+ \ifdefined\XeTeXversion
+ \def\collargs@insert@char#1#2#3{%
+ \edef\collargs@temp{\unexpanded{#1}}%
+ \expandafter\collargs@temp\Ucharcat #2 #3
+ }%
+ \def\collargs@make@char#1#2#3{%
+ \edef#1{\Ucharcat#2 #3}%
+ }%
+ \else
+ %<*latex>
+ \ExplSyntaxOn
+ \def\collargs@insert@char#1#2#3{%
+ \edef\collargs@temp{\unexpanded{#1}}%
+ \expandafter\expandafter\expandafter\collargs@temp\char_generate:nn{#2}{#3}%
+ }%
+ \def\collargs@make@char#1#2#3{%
+ \edef#1{\char_generate:nn{#2}{#3}}%
+ }%
+ \ExplSyntaxOff
+ %</latex>
+ %<*plain>
+ % The implementation is inspired by |expl3|'s implementation of
+ % |\char_generate:nn|, but our implementation is not expandable, for
+ % simplicity. We first store an (arbitrary) character |^||^@| of category
+ % code $n$ into control sequence |\collargs@charofcat@|$n$, for every
+ % (implementable) category code.
+ \begingroup
+ \catcode`\^^@=1 \csgdef{collargs@charofcat@1}{%
+ \noexpand\expandafter^^@\iffalse}\fi}
+ \catcode`\^^@=2 \csgdef{collargs@charofcat@2}{\iffalse{\fi^^@}
+ \catcode`\^^@=3 \csgdef{collargs@charofcat@3}{^^@}
+ \catcode`\^^@=4 \csgdef{collargs@charofcat@4}{^^@}
+ % As we have grabbed the spaces already, a remaining newline should surely be
+ % fixed into a |\par|.
+ \csgdef{collargs@charofcat@5}{\par}
+ \catcode`\^^@=6 \csxdef{collargs@charofcat@6}{\unexpanded{^^@}}
+ \catcode`\^^@=7 \csgdef{collargs@charofcat@7}{^^@}
+ \catcode`\^^@=8 \csgdef{collargs@charofcat@8}{^^@}
+ \csgdef{collargs@charofcat@10}{\noexpand\space}
+ \catcode`\^^@=11 \csgdef{collargs@charofcat@11}{^^@}
+ \catcode`\^^@=12 \csgdef{collargs@charofcat@12}{^^@}
+ \catcode`\^^@=13 \csgdef{collargs@charofcat@13}{^^@}
+ \endgroup
+ \def\collargs@insert@char#1#2#3{%
+ % Temporarily change the lowercase code of |^||^@| to the requested character
+ % |#2|.
+ \begingroup
+ \lccode`\^^@=#2\relax
+ % We'll have to close the group before executing the next-code.
+ \def\collargs@temp{\endgroup#1}%
+ % |\collargs@charofcat@|\meta{requested category code} is f-expanded first,
+ % leaving us to lowercase |\expandafter\collargs@temp^||^@|. Clearly,
+ % lowercasing |\expandafter\collargs@temp| is a no-op, but lowercasing
+ % |^||^@| gets us the requested character of the requested category.
+ % |\expandafter| is executed next, and this gets rid of the conditional for
+ % category codes 1 and 2.
+ \expandafter\lowercase\expandafter{%
+ \expandafter\expandafter\expandafter\collargs@temp
+ \romannumeral-`0\csname collargs@charofcat@\the\numexpr#3\relax\endcsname
+ }%
+ }
+ % This macro cannot not work for category code 6 (because we assign the
+ % result to a macro), but no matter, we only use it for category code 12
+ % anyway.
+ \def\collargs@make@char#1#2#3{%
+ \begingroup
+ \lccode`\^^@=#2\relax
+ % Define |\collargs@temp| to hold |^||^@| of the appropriate category.
+ \edef\collargs@temp{%
+ \csname collargs@charofcat@\the\numexpr#3\relax\endcsname}%
+ % Preexpand the second |\collargs@temp| so that we lowercase
+ % |\def\collargs@temp{^||^@}|, with |^||^@| of the appropriate category.
+ \expandafter\lowercase\expandafter{%
+ \expandafter\def\expandafter\collargs@temp\expandafter{\collargs@temp}%
+ }%
+ \expandafter\endgroup
+ \expandafter\def\expandafter#1\expandafter{\collargs@temp}%
+ }
+ %</plain>
+ \fi
+\fi
+%</!context>
+% \end{macro}
+%
+%<plain>\resetatcatcode
+%<context>\stopmodule
+%<context>\protect
+% \end{macrocode}
+%
+% Local Variables:
+% TeX-engine: luatex
+% TeX-master: "doc/memoize-code.tex"
+% TeX-auto-save: nil
+% End: \ No newline at end of file
diff --git a/macros/generic/collargs/collargs.ins b/macros/generic/collargs/collargs.ins
new file mode 100644
index 0000000000..a8673b6edc
--- /dev/null
+++ b/macros/generic/collargs/collargs.ins
@@ -0,0 +1,33 @@
+%% collargs.ins
+%%
+%% This file is a part of CollArgs, a TeX package providing a command which can
+%% determine the argument scope of any command whose argument structure
+%% conforms to xparse's argument specification, available at
+%% https://ctan.org/pkg/advice and https://github.com/sasozivanovic/advice.
+%%
+%% Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work 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.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/collargs/)FILES.
+%%
+\input docstrip.tex
+\keepsilent
+\preamble
+\endpreamble
+\askforoverwritefalse
+\generate{%
+ \file{collargs.sty}{\from{collargs.dtx}{latex}}%
+ \file{collargs.tex}{\from{collargs.dtx}{plain}}%
+ \file{t-collargs.tex}{\from{collargs.dtx}{context}}%
+}
+\endbatchfile
diff --git a/macros/generic/etoolbox-generic/LICENCE b/macros/generic/etoolbox-generic/LICENCE
new file mode 100644
index 0000000000..1b57559a83
--- /dev/null
+++ b/macros/generic/etoolbox-generic/LICENCE
@@ -0,0 +1,416 @@
+The LaTeX Project Public License
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+LPPL Version 1.3c 2008-05-04
+
+Copyright 1999 2002-2008 LaTeX3 Project
+ Everyone is allowed to distribute verbatim copies of this
+ license document, but modification of it is not allowed.
+
+
+PREAMBLE
+========
+
+The LaTeX Project Public License (LPPL) is the primary license under
+which the LaTeX kernel and the base LaTeX packages are distributed.
+
+You may use this license for any work of which you hold the copyright
+and which you wish to distribute. This license may be particularly
+suitable if your work is TeX-related (such as a LaTeX package), but
+it is written in such a way that you can use it even if your work is
+unrelated to TeX.
+
+The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
+below, gives instructions, examples, and recommendations for authors
+who are considering distributing their works under this license.
+
+This license gives conditions under which a work may be distributed
+and modified, as well as conditions under which modified versions of
+that work may be distributed.
+
+We, the LaTeX3 Project, believe that the conditions below give you
+the freedom to make and distribute modified versions of your work
+that conform with whatever technical specifications you wish while
+maintaining the availability, integrity, and reliability of
+that work. If you do not see how to achieve your goal while
+meeting these conditions, then read the document `cfgguide.tex'
+and `modguide.tex' in the base LaTeX distribution for suggestions.
+
+
+DEFINITIONS
+===========
+
+In this license document the following terms are used:
+
+ `Work'
+ Any work being distributed under this License.
+
+ `Derived Work'
+ Any work that under any applicable law is derived from the Work.
+
+ `Modification'
+ Any procedure that produces a Derived Work under any applicable
+ law -- for example, the production of a file containing an
+ original file associated with the Work or a significant portion of
+ such a file, either verbatim or with modifications and/or
+ translated into another language.
+
+ `Modify'
+ To apply any procedure that produces a Derived Work under any
+ applicable law.
+
+ `Distribution'
+ Making copies of the Work available from one person to another, in
+ whole or in part. Distribution includes (but is not limited to)
+ making any electronic components of the Work accessible by
+ file transfer protocols such as FTP or HTTP or by shared file
+ systems such as Sun's Network File System (NFS).
+
+ `Compiled Work'
+ A version of the Work that has been processed into a form where it
+ is directly usable on a computer system. This processing may
+ include using installation facilities provided by the Work,
+ transformations of the Work, copying of components of the Work, or
+ other activities. Note that modification of any installation
+ facilities provided by the Work constitutes modification of the Work.
+
+ `Current Maintainer'
+ A person or persons nominated as such within the Work. If there is
+ no such explicit nomination then it is the `Copyright Holder' under
+ any applicable law.
+
+ `Base Interpreter'
+ A program or process that is normally needed for running or
+ interpreting a part or the whole of the Work.
+
+ A Base Interpreter may depend on external components but these
+ are not considered part of the Base Interpreter provided that each
+ external component clearly identifies itself whenever it is used
+ interactively. Unless explicitly specified when applying the
+ license to the Work, the only applicable Base Interpreter is a
+ `LaTeX-Format' or in the case of files belonging to the
+ `LaTeX-format' a program implementing the `TeX language'.
+
+
+
+CONDITIONS ON DISTRIBUTION AND MODIFICATION
+===========================================
+
+1. Activities other than distribution and/or modification of the Work
+are not covered by this license; they are outside its scope. In
+particular, the act of running the Work is not restricted and no
+requirements are made concerning any offers of support for the Work.
+
+2. You may distribute a complete, unmodified copy of the Work as you
+received it. Distribution of only part of the Work is considered
+modification of the Work, and no right to distribute such a Derived
+Work may be assumed under the terms of this clause.
+
+3. You may distribute a Compiled Work that has been generated from a
+complete, unmodified copy of the Work as distributed under Clause 2
+above, as long as that Compiled Work is distributed in such a way that
+the recipients may install the Compiled Work on their system exactly
+as it would have been installed if they generated a Compiled Work
+directly from the Work.
+
+4. If you are the Current Maintainer of the Work, you may, without
+restriction, modify the Work, thus creating a Derived Work. You may
+also distribute the Derived Work without restriction, including
+Compiled Works generated from the Derived Work. Derived Works
+distributed in this manner by the Current Maintainer are considered to
+be updated versions of the Work.
+
+5. If you are not the Current Maintainer of the Work, you may modify
+your copy of the Work, thus creating a Derived Work based on the Work,
+and compile this Derived Work, thus creating a Compiled Work based on
+the Derived Work.
+
+6. If you are not the Current Maintainer of the Work, you may
+distribute a Derived Work provided the following conditions are met
+for every component of the Work unless that component clearly states
+in the copyright notice that it is exempt from that condition. Only
+the Current Maintainer is allowed to add such statements of exemption
+to a component of the Work.
+
+ a. If a component of this Derived Work can be a direct replacement
+ for a component of the Work when that component is used with the
+ Base Interpreter, then, wherever this component of the Work
+ identifies itself to the user when used interactively with that
+ Base Interpreter, the replacement component of this Derived Work
+ clearly and unambiguously identifies itself as a modified version
+ of this component to the user when used interactively with that
+ Base Interpreter.
+
+ b. Every component of the Derived Work contains prominent notices
+ detailing the nature of the changes to that component, or a
+ prominent reference to another file that is distributed as part
+ of the Derived Work and that contains a complete and accurate log
+ of the changes.
+
+ c. No information in the Derived Work implies that any persons,
+ including (but not limited to) the authors of the original version
+ of the Work, provide any support, including (but not limited to)
+ the reporting and handling of errors, to recipients of the
+ Derived Work unless those persons have stated explicitly that
+ they do provide such support for the Derived Work.
+
+ d. You distribute at least one of the following with the Derived Work:
+
+ 1. A complete, unmodified copy of the Work;
+ if your distribution of a modified component is made by
+ offering access to copy the modified component from a
+ designated place, then offering equivalent access to copy
+ the Work from the same or some similar place meets this
+ condition, even though third parties are not compelled to
+ copy the Work along with the modified component;
+
+ 2. Information that is sufficient to obtain a complete,
+ unmodified copy of the Work.
+
+7. If you are not the Current Maintainer of the Work, you may
+distribute a Compiled Work generated from a Derived Work, as long as
+the Derived Work is distributed to all recipients of the Compiled
+Work, and as long as the conditions of Clause 6, above, are met with
+regard to the Derived Work.
+
+8. The conditions above are not intended to prohibit, and hence do not
+apply to, the modification, by any method, of any component so that it
+becomes identical to an updated version of that component of the Work as
+it is distributed by the Current Maintainer under Clause 4, above.
+
+9. Distribution of the Work or any Derived Work in an alternative
+format, where the Work or that Derived Work (in whole or in part) is
+then produced by applying some process to that format, does not relax or
+nullify any sections of this license as they pertain to the results of
+applying that process.
+
+10. a. A Derived Work may be distributed under a different license
+ provided that license itself honors the conditions listed in
+ Clause 6 above, in regard to the Work, though it does not have
+ to honor the rest of the conditions in this license.
+
+ b. If a Derived Work is distributed under a different license, that
+ Derived Work must provide sufficient documentation as part of
+ itself to allow each recipient of that Derived Work to honor the
+ restrictions in Clause 6 above, concerning changes from the Work.
+
+11. This license places no restrictions on works that are unrelated to
+the Work, nor does this license place any restrictions on aggregating
+such works with the Work by any means.
+
+12. Nothing in this license is intended to, or may be used to, prevent
+complete compliance by all parties with all applicable laws.
+
+
+NO WARRANTY
+===========
+
+There is no warranty for the Work. Except when otherwise stated in
+writing, the Copyright Holder provides the Work `as is', without
+warranty of any kind, either expressed or implied, including, but not
+limited to, the implied warranties of merchantability and fitness for a
+particular purpose. The entire risk as to the quality and performance
+of the Work is with you. Should the Work prove defective, you assume
+the cost of all necessary servicing, repair, or correction.
+
+In no event unless required by applicable law or agreed to in writing
+will The Copyright Holder, or any author named in the components of the
+Work, or any other party who may distribute and/or modify the Work as
+permitted above, be liable to you for damages, including any general,
+special, incidental or consequential damages arising out of any use of
+the Work or out of inability to use the Work (including, but not limited
+to, loss of data, data being rendered inaccurate, or losses sustained by
+anyone as a result of any failure of the Work to operate with any other
+programs), even if the Copyright Holder or said author or said other
+party has been advised of the possibility of such damages.
+
+
+MAINTENANCE OF THE WORK
+=======================
+
+The Work has the status `author-maintained' if the Copyright Holder
+explicitly and prominently states near the primary copyright notice in
+the Work that the Work can only be maintained by the Copyright Holder
+or simply that it is `author-maintained'.
+
+The Work has the status `maintained' if there is a Current Maintainer
+who has indicated in the Work that they are willing to receive error
+reports for the Work (for example, by supplying a valid e-mail
+address). It is not required for the Current Maintainer to acknowledge
+or act upon these error reports.
+
+The Work changes from status `maintained' to `unmaintained' if there
+is no Current Maintainer, or the person stated to be Current
+Maintainer of the work cannot be reached through the indicated means
+of communication for a period of six months, and there are no other
+significant signs of active maintenance.
+
+You can become the Current Maintainer of the Work by agreement with
+any existing Current Maintainer to take over this role.
+
+If the Work is unmaintained, you can become the Current Maintainer of
+the Work through the following steps:
+
+ 1. Make a reasonable attempt to trace the Current Maintainer (and
+ the Copyright Holder, if the two differ) through the means of
+ an Internet or similar search.
+
+ 2. If this search is successful, then enquire whether the Work
+ is still maintained.
+
+ a. If it is being maintained, then ask the Current Maintainer
+ to update their communication data within one month.
+
+ b. If the search is unsuccessful or no action to resume active
+ maintenance is taken by the Current Maintainer, then announce
+ within the pertinent community your intention to take over
+ maintenance. (If the Work is a LaTeX work, this could be
+ done, for example, by posting to comp.text.tex.)
+
+ 3a. If the Current Maintainer is reachable and agrees to pass
+ maintenance of the Work to you, then this takes effect
+ immediately upon announcement.
+
+ b. If the Current Maintainer is not reachable and the Copyright
+ Holder agrees that maintenance of the Work be passed to you,
+ then this takes effect immediately upon announcement.
+
+ 4. If you make an `intention announcement' as described in 2b. above
+ and after three months your intention is challenged neither by
+ the Current Maintainer nor by the Copyright Holder nor by other
+ people, then you may arrange for the Work to be changed so as
+ to name you as the (new) Current Maintainer.
+
+ 5. If the previously unreachable Current Maintainer becomes
+ reachable once more within three months of a change completed
+ under the terms of 3b) or 4), then that Current Maintainer must
+ become or remain the Current Maintainer upon request provided
+ they then update their communication data within one month.
+
+A change in the Current Maintainer does not, of itself, alter the fact
+that the Work is distributed under the LPPL license.
+
+If you become the Current Maintainer of the Work, you should
+immediately provide, within the Work, a prominent and unambiguous
+statement of your status as Current Maintainer. You should also
+announce your new status to the same pertinent community as
+in 2b) above.
+
+
+WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
+======================================================
+
+This section contains important instructions, examples, and
+recommendations for authors who are considering distributing their
+works under this license. These authors are addressed as `you' in
+this section.
+
+Choosing This License or Another License
+----------------------------------------
+
+If for any part of your work you want or need to use *distribution*
+conditions that differ significantly from those in this license, then
+do not refer to this license anywhere in your work but, instead,
+distribute your work under a different license. You may use the text
+of this license as a model for your own license, but your license
+should not refer to the LPPL or otherwise give the impression that
+your work is distributed under the LPPL.
+
+The document `modguide.tex' in the base LaTeX distribution explains
+the motivation behind the conditions of this license. It explains,
+for example, why distributing LaTeX under the GNU General Public
+License (GPL) was considered inappropriate. Even if your work is
+unrelated to LaTeX, the discussion in `modguide.tex' may still be
+relevant, and authors intending to distribute their works under any
+license are encouraged to read it.
+
+A Recommendation on Modification Without Distribution
+-----------------------------------------------------
+
+It is wise never to modify a component of the Work, even for your own
+personal use, without also meeting the above conditions for
+distributing the modified component. While you might intend that such
+modifications will never be distributed, often this will happen by
+accident -- you may forget that you have modified that component; or
+it may not occur to you when allowing others to access the modified
+version that you are thus distributing it and violating the conditions
+of this license in ways that could have legal implications and, worse,
+cause problems for the community. It is therefore usually in your
+best interest to keep your copy of the Work identical with the public
+one. Many works provide ways to control the behavior of that work
+without altering any of its licensed components.
+
+How to Use This License
+-----------------------
+
+To use this license, place in each of the components of your work both
+an explicit copyright notice including your name and the year the work
+was authored and/or last substantially modified. Include also a
+statement that the distribution and/or modification of that
+component is constrained by the conditions in this license.
+
+Here is an example of such a notice and statement:
+
+ %% pig.dtx
+ %% Copyright 2008 M. Y. Name
+ %
+ % This work 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
+ % https://www.latex-project.org/lppl.txt
+ % and version 1.3c or later is part of all distributions of LaTeX
+ % version 2008 or later.
+ %
+ % This work has the LPPL maintenance status `maintained'.
+ %
+ % The Current Maintainer of this work is M. Y. Name.
+ %
+ % This work consists of the files pig.dtx and pig.ins
+ % and the derived file pig.sty.
+
+Given such a notice and statement in a file, the conditions
+given in this license document would apply, with the `Work' referring
+to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
+generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
+referring to any `LaTeX-Format', and both `Copyright Holder' and
+`Current Maintainer' referring to the person `M. Y. Name'.
+
+If you do not want the Maintenance section of LPPL to apply to your
+Work, change `maintained' above into `author-maintained'.
+However, we recommend that you use `maintained', as the Maintenance
+section was added in order to ensure that your Work remains useful to
+the community even when you can no longer maintain and support it
+yourself.
+
+Derived Works That Are Not Replacements
+---------------------------------------
+
+Several clauses of the LPPL specify means to provide reliability and
+stability for the user community. They therefore concern themselves
+with the case that a Derived Work is intended to be used as a
+(compatible or incompatible) replacement of the original Work. If
+this is not the case (e.g., if a few lines of code are reused for a
+completely different task), then clauses 6b and 6d shall not apply.
+
+
+Important Recommendations
+-------------------------
+
+ Defining What Constitutes the Work
+
+ The LPPL requires that distributions of the Work contain all the
+ files of the Work. It is therefore important that you provide a
+ way for the licensee to determine which files constitute the Work.
+ This could, for example, be achieved by explicitly listing all the
+ files of the Work near the copyright notice of each file or by
+ using a line such as:
+
+ % This work consists of all files listed in manifest.txt.
+
+ in that place. In the absence of an unequivocal list it might be
+ impossible for the licensee to determine what is considered by you
+ to comprise the Work and, in such a case, the licensee would be
+ entitled to make reasonable conjectures as to which files comprise
+ the Work.
+
diff --git a/macros/generic/etoolbox-generic/README.md b/macros/generic/etoolbox-generic/README.md
new file mode 100644
index 0000000000..8b5fb17fe7
--- /dev/null
+++ b/macros/generic/etoolbox-generic/README.md
@@ -0,0 +1,8 @@
+This package implements a wrapper which allows the user to load the
+LaTeX-independent part of LaTeX package `etoolbox` in other formats.
+
+Load the package by `\input etoolbox-generic`.
+
+The wrapper has been tested in plain TeX and ConTeXt on `etoolbox` version
+`2020/10/05 v2.5k`. (The version of the wrapper should match the latest
+`etoolbox` version.)
diff --git a/macros/generic/etoolbox-generic/etoolbox-generic.tex b/macros/generic/etoolbox-generic/etoolbox-generic.tex
new file mode 100644
index 0000000000..c1fcd869ac
--- /dev/null
+++ b/macros/generic/etoolbox-generic/etoolbox-generic.tex
@@ -0,0 +1,80 @@
+% etoolbox-generic.tex 2023/10/10 v2.5k
+%
+% This is a loader for etoolbox.sty 2020/10/05 v2.5k in non-LaTeX formats.
+%
+% Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License, either version 1.3c of this license or (at
+% your option) any later version. The latest version of this license is in
+% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+% all distributions of LaTeX version 2008 or later.
+%
+% This work has the LPPL maintenance status `maintained`.
+% The Current Maintainer of this work is Saso Zivanovic.
+%
+% This work consist of this file and README.md.
+%
+% Prevent double-loading.
+\ifcsname ver@etoolbox.sty\endcsname
+ \expandafter\endinput
+\fi
+% We need miniltx and a couple of auxiliary macros.
+\input miniltx
+\def\newif#1{%
+ \count@\escapechar \escapechar\m@ne
+ \let#1\iffalse
+ \@if#1\iftrue
+ \@if#1\iffalse
+ \escapechar\count@}
+\def\@if#1#2{%
+ \expandafter\def\csname\expandafter\@gobbletwo\string#1%
+ \expandafter\@gobbletwo\string#2\endcsname
+ {\let#1#2}}
+% We need to define \AtEndOfPackage; etoolbox uses it to undefine its
+% catcodes. We're careful and restore the old (probably empty) definition at
+% the end.
+\let\etb@AtEndOfPackage\AtEndOfPackage
+\def\AtEndOfPackage#1{\def\AtEndOfPackageDo{#1}}
+% Kindly, all the LaTeX-specific code in etoolbox.sty occurs after
+% the call to \IfFormatAtLeastTF. Redefining this macro to \endinput will
+% therefore remove the LaTeX-specific part of the package:
+\def\IfFormatAtLeastTF#1#2#3{\endinput}
+\let\etb@extrafloats\extrafloats
+\let\extrafloats\relax
+\input etoolbox.sty
+% Restore what we changed, and execute the end-of-package code.
+\let\extrafloats\etb@extrafloats
+\AtEndOfPackageDo
+\let\AtEndOfPackage\etb@AtEndOfPackage
+\let\AtEndOfPackageDo\relax
+\cslet{ver@etoolbox.sty}\relax
+% To have this package work in ConTeXt, we must patch the macros by replacing
+% \unexpanded with \normalunexpanded.
+\ifcsname normalunexpanded\endcsname
+ \def\etb@patchunexpanded#1{%
+ \patchcmd#1\unexpanded\normalunexpanded{}{%
+ \PackageError{etoolbox}{Cannot adapt command \string#1 to ConTeXt}{}%
+ }%
+ }
+ % \patchcmd itself uses \etb@patchcmd@scantoks which uses \unexpanded; so we
+ % temporarily redefine \unexpanded to patch \etb@patchcmd@scantoks.
+ \let\unexpanded\normalunexpanded
+ \etb@patchunexpanded\etb@patchcmd@scantoks
+ \let\unexpanded\protected
+ % Now we can patch the rest.
+ \etb@patchunexpanded\expandonce
+ \etb@patchunexpanded\etb@unexpandable
+ \etb@patchunexpanded\appto\etb@patchunexpanded\appto
+ \etb@patchunexpanded\gappto\etb@patchunexpanded\gappto
+ \etb@patchunexpanded\preto\etb@patchunexpanded\preto
+ \etb@patchunexpanded\gpreto\etb@patchunexpanded\gpreto
+ \etb@patchunexpanded\etb@hooktocmd
+ % Patching \protecting is a bit involved, as its parameters text is #.
+ \expandafter\def\expandafter\protecting\expandafter{\protecting{}}
+ \etb@patchunexpanded\protecting
+ \patchcmd\protecting{{}}{}{}{}%
+ \expandafter\def\expandafter\protecting\expandafter#\expandafter{\protecting}
+\fi
+\resetatcatcode
+\endinput
diff --git a/macros/generic/memoize/INSTALL.md b/macros/generic/memoize/INSTALL.md
new file mode 100644
index 0000000000..99957a9181
--- /dev/null
+++ b/macros/generic/memoize/INSTALL.md
@@ -0,0 +1,216 @@
+# Installation from the TDS archive
+
+If Memoize is not (yet) offered by your TeX distribution, the easiest way to
+install it is by downloading the TDS archive `memoize.tds.zip` from [Memoize's
+CTAN page](https://ctan.org/pkg/memoize), and unpacking it into your `texmf`
+directory. You will most likely also have to do the same for two auxiliary
+packages Memoize depends on: [Advice](https://ctan.org/pkg/advice) and
+[CollArgs](https://ctan.org/pkg/collargs).
+
+Read on only if you have an unstoppable urge to install from source and/or
+compile the manual or the documented source code.
+
+# Installation from the source
+
+# Getting the sources
+
+There are several options:
+
+* Download and unpack the zip archive of the package from [Memoize's CTAN
+ page](https://ctan.org/pkg/memoize).
+
+* Download and unpack the TDS archive, or copy the files from your local
+ distribution. The sources reside in `<texmf>/source/generic/memoize`.
+
+* Clone the [GitHub repository](https://github.com/sasozivanovic/memoize).
+
+## Generating runtime files
+
+The easiest way to generate the runtime files is by running `make`. The
+following command will generate (i) runtime TeX files for all supported formats
+(currently: LaTeX, plain TeX and ConTeXt), and (ii) the man pages for the
+accompanying scripts:
+
+```
+make runtime
+```
+
+To only generate the runtime TeX files, execute
+
+```
+make memoize.sty
+```
+
+Alternatively, you can generate the runtime files manually. The source of this
+package was written using [EasyDTX](https://ctan.org/pkg/easydtx). Therefore,
+you first have to convert the `.edtx` file into a regular `.dtx`:
+
+```
+edtx2dtx memoize.edtx > memoize.dtx
+```
+
+The next step is standard. Produce the runtime files by compiling the
+installation file:
+
+```
+tex memoize.ins
+```
+
+If you require the ConTeXt runtime, replace all instances of `\expanded` and
+`\unexpanded` in `t-memoize.tex` by `\normalexpanded` and `\normalunexpanded`,
+respectively. One way to do this is:
+
+```
+sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-memoize.tex
+```
+
+The man pages are produced by converting their MarkDown sources by `pandoc`
+(execute this in the `doc` subdirectory):
+
+```
+pandoc memoize-extract.1.md -s -t man -o memoize-extract.1
+pandoc memoize-clean.1.md -s -t man -o memoize-clean.1
+```
+
+Additionally, links from `memoize-x.pl.1` and `memoize-x.py.1` to `memoize-x.1`
+can be created by:
+
+```
+echo .so man1/memoize-extract.1 > memoize-extract.pl.1
+echo .so man1/memoize-extract.1 > memoize-extract.py.1
+echo .so man1/memoize-clean.1 > memoize-clean.pl.1
+echo .so man1/memoize-clean.1 > memoize-clean.py.1
+```
+
+## Installation
+
+It is recommended to install the files into a TDS-compliant `texmf` directory,
+as usual. Inspect file `FILES` or the TDS archive `memoize.tds.zip` to see
+what goes where.
+
+Next, the scripts residing in `<texmf>/scripts/memoize` should be linked into
+some directory listed in the executable search `PATH`. The scripts are the
+following:
+
+* `memoize-extract.pl`
+* `memoize-extract.py`
+* `memoize-clean.pl`
+* `memoize-clean.py`
+
+If you have downloaded the sources from GitHub, you can build the TDS
+directories/archives of both Memoize and its auxiliary packages Advice and
+CollArgs by issuing
+
+```
+make
+```
+
+This command creates:
+
+* TDS directories `memoize.tds`, `advice.tds` and `collargs.tds`,
+
+* CTAN directories `ctan/memoize`, `ctan/advice` and `ctan/memoize`,
+
+* TDS archives `memoize.tds.zip`, `advice.tds.zip` and `collargs.tds.zip`
+ inside the CTAN directories, and
+
+* CTAN archives `memoize.zip`, `advice.zip` and `collargs.zip` inside directory
+ `ctan`.
+
+The plain `make` shown above will also attempt to compile the documentation.
+If you're not ready for that (yet), you can avoid that by executing this
+instead:
+
+```
+make PDF=
+```
+
+# Compiling the documentation
+
+Compiling both the documented code listing and the manual requires a Unix-like
+operating system. I have developed Memoize on Linux, but the documentation
+should also be compilable under Cygwin on Windows (not tested).
+
+The documentation of Advice and CollArgs, both their manuals and documented
+code listings, is included within Memoize's documentation.
+
+## Getting the source
+
+In principle, the options are the same as for the installation from the source,
+but the GitHub option is strongly preferred here, as the other two options
+require manually copying the sources of Advice and CollArgs into the Memoize
+directory. That said:
+
+* Clone the [GitHub repository](https://github.com/sasozivanovic/memoize).
+ You're done.
+
+* Download and unpack the zip archives of all three packages from their CTAN
+ pages: https://ctan.org/pkg/memoize, https://ctan.org/pkg/advice and
+ https://ctan.org/pkg/collargs.
+
+ Copy `advice.edtx` and `collargs.edtx` into the Memoize directory, alongside
+ `memoize.edtx`.
+
+* From TDS archives (of all three packages), or your local distribution's
+ `<texmf>` folder. This is not straightforward:
+
+ 1. Make a local copy of directory `<texmf>/source/generic/memoize`; we'll
+ call it "the Memoize directory".
+
+ 2. Copy directory `<texmf>/doc/generic/memoize` into the the Memoize
+ directory as `doc`.
+
+ 3. Copy `memoize-extract.pl`, `memoize-extract.py`, `memoize-clean.pl` and
+ `memoize-clean.py` from directory `<texmf>/scripts` into the Memoize
+ directory.
+
+ 4. Copy `advice.edtx` from `<texmf>/source/generic/advice` and
+ `collargs.edtx` from `<texmf>/source/generic/collargs` into the the
+ Memoize directory.
+
+## Compiling the documented code listing
+
+I have compiled the code docs with LuaLaTeX on a Linux system with
+TeXLive 2023. If you have `make`, the easiest way to compile them is by
+issuing
+
+```
+make doc/memoize-code.pdf
+```
+
+Alternatively, you can use `latexmk`, but you first have to convert the `.edtx`
+sources of all three packages into `.dtx`, if you haven't done so yet:
+
+```
+edtx2dtx memoize.edtx > memoize.dtx
+edtx2dtx advice.edtx > advice.dtx
+edtx2dtx collargs.edtx > collargs.dtx
+```
+
+Then, you can execute `latexmk` from the `doc` subdirectory:
+
+```
+latexmk -lualatex -bibtex memoize-code
+```
+
+To compile the code docs manually, three iterations of `lualatex memoize-code`
+with `makeindex -s gind.ist memoize-code.idx` between them should suffice.
+
+## Compiling the manual
+
+I have compiled the manual with LuaLaTeX on a Linux system with TeXLive 2023,
+`make`, `latexmk`, `perl` and `sed` installed. Furthermore, you absolutely
+have to run the compilation with some form of `--shell-escape`, as it executes
+`make` and `sed` to build the examples. (There is no way to compile these from
+the command line, as the instructions are baked into the manual source.)
+
+Given all this, either of the following should do the trick:
+
+* `make doc/memoize.pdf` from the Memoize directory;
+
+* `latexmk -lualatex -bibtex memoize` for the `doc` subdirectory; or
+
+* quite a few runs of `lualatex memoize` interspersed by `makeindex memoize.idx`.
+
+If all worked well, you can change `\usepackage{nomemoize}` in
+`doc/memoize.tex` to `\usepackage{memoize}` and observe Memoize at work.
diff --git a/macros/generic/memoize/LICENCE b/macros/generic/memoize/LICENCE
new file mode 100644
index 0000000000..1b57559a83
--- /dev/null
+++ b/macros/generic/memoize/LICENCE
@@ -0,0 +1,416 @@
+The LaTeX Project Public License
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+LPPL Version 1.3c 2008-05-04
+
+Copyright 1999 2002-2008 LaTeX3 Project
+ Everyone is allowed to distribute verbatim copies of this
+ license document, but modification of it is not allowed.
+
+
+PREAMBLE
+========
+
+The LaTeX Project Public License (LPPL) is the primary license under
+which the LaTeX kernel and the base LaTeX packages are distributed.
+
+You may use this license for any work of which you hold the copyright
+and which you wish to distribute. This license may be particularly
+suitable if your work is TeX-related (such as a LaTeX package), but
+it is written in such a way that you can use it even if your work is
+unrelated to TeX.
+
+The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
+below, gives instructions, examples, and recommendations for authors
+who are considering distributing their works under this license.
+
+This license gives conditions under which a work may be distributed
+and modified, as well as conditions under which modified versions of
+that work may be distributed.
+
+We, the LaTeX3 Project, believe that the conditions below give you
+the freedom to make and distribute modified versions of your work
+that conform with whatever technical specifications you wish while
+maintaining the availability, integrity, and reliability of
+that work. If you do not see how to achieve your goal while
+meeting these conditions, then read the document `cfgguide.tex'
+and `modguide.tex' in the base LaTeX distribution for suggestions.
+
+
+DEFINITIONS
+===========
+
+In this license document the following terms are used:
+
+ `Work'
+ Any work being distributed under this License.
+
+ `Derived Work'
+ Any work that under any applicable law is derived from the Work.
+
+ `Modification'
+ Any procedure that produces a Derived Work under any applicable
+ law -- for example, the production of a file containing an
+ original file associated with the Work or a significant portion of
+ such a file, either verbatim or with modifications and/or
+ translated into another language.
+
+ `Modify'
+ To apply any procedure that produces a Derived Work under any
+ applicable law.
+
+ `Distribution'
+ Making copies of the Work available from one person to another, in
+ whole or in part. Distribution includes (but is not limited to)
+ making any electronic components of the Work accessible by
+ file transfer protocols such as FTP or HTTP or by shared file
+ systems such as Sun's Network File System (NFS).
+
+ `Compiled Work'
+ A version of the Work that has been processed into a form where it
+ is directly usable on a computer system. This processing may
+ include using installation facilities provided by the Work,
+ transformations of the Work, copying of components of the Work, or
+ other activities. Note that modification of any installation
+ facilities provided by the Work constitutes modification of the Work.
+
+ `Current Maintainer'
+ A person or persons nominated as such within the Work. If there is
+ no such explicit nomination then it is the `Copyright Holder' under
+ any applicable law.
+
+ `Base Interpreter'
+ A program or process that is normally needed for running or
+ interpreting a part or the whole of the Work.
+
+ A Base Interpreter may depend on external components but these
+ are not considered part of the Base Interpreter provided that each
+ external component clearly identifies itself whenever it is used
+ interactively. Unless explicitly specified when applying the
+ license to the Work, the only applicable Base Interpreter is a
+ `LaTeX-Format' or in the case of files belonging to the
+ `LaTeX-format' a program implementing the `TeX language'.
+
+
+
+CONDITIONS ON DISTRIBUTION AND MODIFICATION
+===========================================
+
+1. Activities other than distribution and/or modification of the Work
+are not covered by this license; they are outside its scope. In
+particular, the act of running the Work is not restricted and no
+requirements are made concerning any offers of support for the Work.
+
+2. You may distribute a complete, unmodified copy of the Work as you
+received it. Distribution of only part of the Work is considered
+modification of the Work, and no right to distribute such a Derived
+Work may be assumed under the terms of this clause.
+
+3. You may distribute a Compiled Work that has been generated from a
+complete, unmodified copy of the Work as distributed under Clause 2
+above, as long as that Compiled Work is distributed in such a way that
+the recipients may install the Compiled Work on their system exactly
+as it would have been installed if they generated a Compiled Work
+directly from the Work.
+
+4. If you are the Current Maintainer of the Work, you may, without
+restriction, modify the Work, thus creating a Derived Work. You may
+also distribute the Derived Work without restriction, including
+Compiled Works generated from the Derived Work. Derived Works
+distributed in this manner by the Current Maintainer are considered to
+be updated versions of the Work.
+
+5. If you are not the Current Maintainer of the Work, you may modify
+your copy of the Work, thus creating a Derived Work based on the Work,
+and compile this Derived Work, thus creating a Compiled Work based on
+the Derived Work.
+
+6. If you are not the Current Maintainer of the Work, you may
+distribute a Derived Work provided the following conditions are met
+for every component of the Work unless that component clearly states
+in the copyright notice that it is exempt from that condition. Only
+the Current Maintainer is allowed to add such statements of exemption
+to a component of the Work.
+
+ a. If a component of this Derived Work can be a direct replacement
+ for a component of the Work when that component is used with the
+ Base Interpreter, then, wherever this component of the Work
+ identifies itself to the user when used interactively with that
+ Base Interpreter, the replacement component of this Derived Work
+ clearly and unambiguously identifies itself as a modified version
+ of this component to the user when used interactively with that
+ Base Interpreter.
+
+ b. Every component of the Derived Work contains prominent notices
+ detailing the nature of the changes to that component, or a
+ prominent reference to another file that is distributed as part
+ of the Derived Work and that contains a complete and accurate log
+ of the changes.
+
+ c. No information in the Derived Work implies that any persons,
+ including (but not limited to) the authors of the original version
+ of the Work, provide any support, including (but not limited to)
+ the reporting and handling of errors, to recipients of the
+ Derived Work unless those persons have stated explicitly that
+ they do provide such support for the Derived Work.
+
+ d. You distribute at least one of the following with the Derived Work:
+
+ 1. A complete, unmodified copy of the Work;
+ if your distribution of a modified component is made by
+ offering access to copy the modified component from a
+ designated place, then offering equivalent access to copy
+ the Work from the same or some similar place meets this
+ condition, even though third parties are not compelled to
+ copy the Work along with the modified component;
+
+ 2. Information that is sufficient to obtain a complete,
+ unmodified copy of the Work.
+
+7. If you are not the Current Maintainer of the Work, you may
+distribute a Compiled Work generated from a Derived Work, as long as
+the Derived Work is distributed to all recipients of the Compiled
+Work, and as long as the conditions of Clause 6, above, are met with
+regard to the Derived Work.
+
+8. The conditions above are not intended to prohibit, and hence do not
+apply to, the modification, by any method, of any component so that it
+becomes identical to an updated version of that component of the Work as
+it is distributed by the Current Maintainer under Clause 4, above.
+
+9. Distribution of the Work or any Derived Work in an alternative
+format, where the Work or that Derived Work (in whole or in part) is
+then produced by applying some process to that format, does not relax or
+nullify any sections of this license as they pertain to the results of
+applying that process.
+
+10. a. A Derived Work may be distributed under a different license
+ provided that license itself honors the conditions listed in
+ Clause 6 above, in regard to the Work, though it does not have
+ to honor the rest of the conditions in this license.
+
+ b. If a Derived Work is distributed under a different license, that
+ Derived Work must provide sufficient documentation as part of
+ itself to allow each recipient of that Derived Work to honor the
+ restrictions in Clause 6 above, concerning changes from the Work.
+
+11. This license places no restrictions on works that are unrelated to
+the Work, nor does this license place any restrictions on aggregating
+such works with the Work by any means.
+
+12. Nothing in this license is intended to, or may be used to, prevent
+complete compliance by all parties with all applicable laws.
+
+
+NO WARRANTY
+===========
+
+There is no warranty for the Work. Except when otherwise stated in
+writing, the Copyright Holder provides the Work `as is', without
+warranty of any kind, either expressed or implied, including, but not
+limited to, the implied warranties of merchantability and fitness for a
+particular purpose. The entire risk as to the quality and performance
+of the Work is with you. Should the Work prove defective, you assume
+the cost of all necessary servicing, repair, or correction.
+
+In no event unless required by applicable law or agreed to in writing
+will The Copyright Holder, or any author named in the components of the
+Work, or any other party who may distribute and/or modify the Work as
+permitted above, be liable to you for damages, including any general,
+special, incidental or consequential damages arising out of any use of
+the Work or out of inability to use the Work (including, but not limited
+to, loss of data, data being rendered inaccurate, or losses sustained by
+anyone as a result of any failure of the Work to operate with any other
+programs), even if the Copyright Holder or said author or said other
+party has been advised of the possibility of such damages.
+
+
+MAINTENANCE OF THE WORK
+=======================
+
+The Work has the status `author-maintained' if the Copyright Holder
+explicitly and prominently states near the primary copyright notice in
+the Work that the Work can only be maintained by the Copyright Holder
+or simply that it is `author-maintained'.
+
+The Work has the status `maintained' if there is a Current Maintainer
+who has indicated in the Work that they are willing to receive error
+reports for the Work (for example, by supplying a valid e-mail
+address). It is not required for the Current Maintainer to acknowledge
+or act upon these error reports.
+
+The Work changes from status `maintained' to `unmaintained' if there
+is no Current Maintainer, or the person stated to be Current
+Maintainer of the work cannot be reached through the indicated means
+of communication for a period of six months, and there are no other
+significant signs of active maintenance.
+
+You can become the Current Maintainer of the Work by agreement with
+any existing Current Maintainer to take over this role.
+
+If the Work is unmaintained, you can become the Current Maintainer of
+the Work through the following steps:
+
+ 1. Make a reasonable attempt to trace the Current Maintainer (and
+ the Copyright Holder, if the two differ) through the means of
+ an Internet or similar search.
+
+ 2. If this search is successful, then enquire whether the Work
+ is still maintained.
+
+ a. If it is being maintained, then ask the Current Maintainer
+ to update their communication data within one month.
+
+ b. If the search is unsuccessful or no action to resume active
+ maintenance is taken by the Current Maintainer, then announce
+ within the pertinent community your intention to take over
+ maintenance. (If the Work is a LaTeX work, this could be
+ done, for example, by posting to comp.text.tex.)
+
+ 3a. If the Current Maintainer is reachable and agrees to pass
+ maintenance of the Work to you, then this takes effect
+ immediately upon announcement.
+
+ b. If the Current Maintainer is not reachable and the Copyright
+ Holder agrees that maintenance of the Work be passed to you,
+ then this takes effect immediately upon announcement.
+
+ 4. If you make an `intention announcement' as described in 2b. above
+ and after three months your intention is challenged neither by
+ the Current Maintainer nor by the Copyright Holder nor by other
+ people, then you may arrange for the Work to be changed so as
+ to name you as the (new) Current Maintainer.
+
+ 5. If the previously unreachable Current Maintainer becomes
+ reachable once more within three months of a change completed
+ under the terms of 3b) or 4), then that Current Maintainer must
+ become or remain the Current Maintainer upon request provided
+ they then update their communication data within one month.
+
+A change in the Current Maintainer does not, of itself, alter the fact
+that the Work is distributed under the LPPL license.
+
+If you become the Current Maintainer of the Work, you should
+immediately provide, within the Work, a prominent and unambiguous
+statement of your status as Current Maintainer. You should also
+announce your new status to the same pertinent community as
+in 2b) above.
+
+
+WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
+======================================================
+
+This section contains important instructions, examples, and
+recommendations for authors who are considering distributing their
+works under this license. These authors are addressed as `you' in
+this section.
+
+Choosing This License or Another License
+----------------------------------------
+
+If for any part of your work you want or need to use *distribution*
+conditions that differ significantly from those in this license, then
+do not refer to this license anywhere in your work but, instead,
+distribute your work under a different license. You may use the text
+of this license as a model for your own license, but your license
+should not refer to the LPPL or otherwise give the impression that
+your work is distributed under the LPPL.
+
+The document `modguide.tex' in the base LaTeX distribution explains
+the motivation behind the conditions of this license. It explains,
+for example, why distributing LaTeX under the GNU General Public
+License (GPL) was considered inappropriate. Even if your work is
+unrelated to LaTeX, the discussion in `modguide.tex' may still be
+relevant, and authors intending to distribute their works under any
+license are encouraged to read it.
+
+A Recommendation on Modification Without Distribution
+-----------------------------------------------------
+
+It is wise never to modify a component of the Work, even for your own
+personal use, without also meeting the above conditions for
+distributing the modified component. While you might intend that such
+modifications will never be distributed, often this will happen by
+accident -- you may forget that you have modified that component; or
+it may not occur to you when allowing others to access the modified
+version that you are thus distributing it and violating the conditions
+of this license in ways that could have legal implications and, worse,
+cause problems for the community. It is therefore usually in your
+best interest to keep your copy of the Work identical with the public
+one. Many works provide ways to control the behavior of that work
+without altering any of its licensed components.
+
+How to Use This License
+-----------------------
+
+To use this license, place in each of the components of your work both
+an explicit copyright notice including your name and the year the work
+was authored and/or last substantially modified. Include also a
+statement that the distribution and/or modification of that
+component is constrained by the conditions in this license.
+
+Here is an example of such a notice and statement:
+
+ %% pig.dtx
+ %% Copyright 2008 M. Y. Name
+ %
+ % This work 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
+ % https://www.latex-project.org/lppl.txt
+ % and version 1.3c or later is part of all distributions of LaTeX
+ % version 2008 or later.
+ %
+ % This work has the LPPL maintenance status `maintained'.
+ %
+ % The Current Maintainer of this work is M. Y. Name.
+ %
+ % This work consists of the files pig.dtx and pig.ins
+ % and the derived file pig.sty.
+
+Given such a notice and statement in a file, the conditions
+given in this license document would apply, with the `Work' referring
+to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
+generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
+referring to any `LaTeX-Format', and both `Copyright Holder' and
+`Current Maintainer' referring to the person `M. Y. Name'.
+
+If you do not want the Maintenance section of LPPL to apply to your
+Work, change `maintained' above into `author-maintained'.
+However, we recommend that you use `maintained', as the Maintenance
+section was added in order to ensure that your Work remains useful to
+the community even when you can no longer maintain and support it
+yourself.
+
+Derived Works That Are Not Replacements
+---------------------------------------
+
+Several clauses of the LPPL specify means to provide reliability and
+stability for the user community. They therefore concern themselves
+with the case that a Derived Work is intended to be used as a
+(compatible or incompatible) replacement of the original Work. If
+this is not the case (e.g., if a few lines of code are reused for a
+completely different task), then clauses 6b and 6d shall not apply.
+
+
+Important Recommendations
+-------------------------
+
+ Defining What Constitutes the Work
+
+ The LPPL requires that distributions of the Work contain all the
+ files of the Work. It is therefore important that you provide a
+ way for the licensee to determine which files constitute the Work.
+ This could, for example, be achieved by explicitly listing all the
+ files of the Work near the copyright notice of each file or by
+ using a line such as:
+
+ % This work consists of all files listed in manifest.txt.
+
+ in that place. In the absence of an unequivocal list it might be
+ impossible for the licensee to determine what is considered by you
+ to comprise the Work and, in such a case, the licensee would be
+ entitled to make reasonable conjectures as to which files comprise
+ the Work.
+
diff --git a/macros/generic/memoize/Makefile b/macros/generic/memoize/Makefile
new file mode 100644
index 0000000000..7edbd7ba34
--- /dev/null
+++ b/macros/generic/memoize/Makefile
@@ -0,0 +1,139 @@
+# Prepare the CTAN submission for all three packages.
+
+PACKAGES = memoize advice collargs
+
+all: ctan/memoize.zip
+ $(MAKE) -f Makefile.advice ctan/advice.zip
+ $(MAKE) -f Makefile.collargs ctan/collargs.zip
+
+# Prepare the CTAN submission.
+
+PACKAGE = memoize
+VERSION = 1.0.0
+YEAR = 2023
+MONTH = 10
+DAY = 10
+
+FORMAT = generic
+
+COMMON = memoize nomemoize memoizable
+PLAIN = memoize-extract-one.tex
+SOURCE = memoize.edtx memoize.ins # $(makefiles)
+
+SCRIPTS := memoize-extract memoize-clean
+man-src := $(SCRIPTS:%=doc/%.1.md)
+MAN := $(SCRIPTS:%=%.1) $(SCRIPTS:%=%.pl.1) $(SCRIPTS:%=%.py.1)
+MAN := $(MAN:%=doc/%)
+SCRIPTS := $(SCRIPTS:%=%.pl) $(SCRIPTS:%=%.py)
+
+%.pl.1: %.1
+ echo .so man1/$*.1 > $@ # link to .1 man page
+%.py.1: %.1
+ echo .so man1/$*.1 > $@ # link to .1 man page
+
+.PHONY: runtime
+runtime: $(RUNTIME)
+
+README = doc/README.memoize.md
+INSTALL = INSTALL.md
+MAKEFILE = Makefile
+LICENCE = LICENCE
+
+makefiles = Makefile.package Makefile.runtimes Makefile.advice Makefile.collargs
+
+codedoc-source = memoize-code.tex \
+ memoize-code.sty memoize-doc-common.sty
+
+manual-source = memoize.tex \
+ memoize-doc.sty memoize-doc-common.sty yadoc.sty \
+ memoize.mst
+
+PDF = memoize.pdf memoize-code.pdf
+
+codedoc-source := $(codedoc-source:%=doc/%)
+manual-source := $(manual-source:%=doc/%)
+pdf := $(PDF:%=doc/%)
+DOC = $(sort $(codedoc-source) $(manual-source)) $(pdf) $(man-src)
+
+examples-src := Makefile ins.begin ins.mid ins.end
+examples-src := $(examples-src:%=doc/examples/%)
+#examples-src += $(shell git ls-files | grep ^doc/examples/.*dtx$)
+examples-src += $(shell find doc/examples -name '*.dtx')
+
+# doc/attachments.lst is produced by compiling memoize.tex (without memoization).
+# doc-examples will hold soft links to the relevant generated example files.
+doc-examples := $(shell sed 's/^.* \(.*\) ##.*$$/\1/' doc/attachments.lst)
+doc-examples := $(doc-examples:%=doc/examples/%)
+
+ctan/$(PACKAGE).zip:
+ $(TDS-BEGIN)
+# Check for duplicate filenames:
+ echo $(doc-examples) | tr ' ' '\n' | uniq -d | ifne false
+ cd doc && zip ../$(TDS-DOC-DIR)/examples-src.zip $(examples-src:doc/%=%)
+# For each line ($1 $2) in attachments.lst, link $1 to $2 ...
+ cd doc/examples && sed 's!^examples/!ln -sfr !' ../attachments.lst | sh
+# ... and zip those links.
+ cd doc && zip -r ../$(TDS-DOC-DIR)/examples.zip $(doc-examples:doc/%=%)
+ $(TDS-END)
+ $(CTAN-BEGIN)
+ ln -sr $(TDS-DOC-DIR)/examples-src.zip $(CTAN-DIR)/doc
+ ln -sr $(TDS-DOC-DIR)/examples.zip $(CTAN-DIR)/doc
+ $(CTAN-END)
+
+
+
+doc/memoize-code.pdf: $(SOURCE) $(codedoc-source)
+
+doc/memoize.pdf: $(manual-source) $(examples-src)
+
+%.pdf: %.tex
+ latexmk -cd -lualatex -bibtex- $< && touch $@
+
+
+
+# Maintanence
+
+test.tex = $(wildcard test*.tex)
+
+.PHONY: all runtime force clean versions-show
+
+.PRECIOUS: %.1
+
+clean: # clean this directory
+ memoize-clean.py -a $(test.tex:%.tex=-p %.) $(test.tex:%.tex=-p %.memo.dir/)
+ latexmk -C -f $(test.tex) _region_
+
+version:
+ $(MAKE) -f Makefile.collargs version
+ $(MAKE) -f Makefile.advice version
+ $(call EDIT-VERSION-LATEX,memoize.edtx,memoize)
+ $(call EDIT-VERSION-LATEX,memoize.edtx,nomemoize)
+ $(call EDIT-VERSION-LATEX,memoize.edtx,memoizable)
+ $(call EDIT-VERSION-CONTEXT,memoize.edtx)
+ $(call EDIT-VERSION-PLAIN,memoize.edtx,memoize)
+ $(call EDIT-VERSION-PLAIN,memoize.edtx,nomemoize)
+ $(call EDIT-VERSION-PLAIN,memoize.edtx,memoizable)
+ $(call EDIT-VERSION-PERL,memoize-extract.pl)
+ $(call EDIT-VERSION-PERL,memoize-clean.pl)
+ $(call EDIT-VERSION-PYTHON,memoize-extract.py)
+ $(call EDIT-VERSION-PYTHON,memoize-clean.py)
+ $(call EDIT-VERSION-MAN,doc/memoize-extract.1.md)
+ $(call EDIT-VERSION-MAN,doc/memoize-clean.1.md)
+# Change the date of the latest release (identified by the version).
+ sed -Ei 's!^\\item\[\\githubrelease\{[0-9]{4}/[0-9]{2}/[0-9]{2}\}\{v$(VERSION)\}\] *$$!\\item\[\\githubrelease\{$(YEAR)/$(MONTH)/$(DAY)\}\{v$(VERSION)\}\]!' doc/memoize.tex
+
+define COLOR_VERSION
+grep -E --color '[0-9]{4}[/-][0-9]{2}[/-][0-9]{2}|v?[0-9]\.[0-9]\.[0-9]|(January|February|March|April|May|June|July|August|September|October|November|December) [0-9]+, [0-9]{4}'
+endef
+
+versions-show:
+ @grep -E '%<latex>\\ProvidesPackage|^%<context>%D\s*(version|date)=' $(PACKAGES:%=%.edtx) | ${COLOR_VERSION}
+ @grep __version__ *.py | ${COLOR_VERSION}
+ @grep VERSION *.pl | ${COLOR_VERSION}
+ @grep -E '^(footer|date):' doc/memoize-*.md | ${COLOR_VERSION}
+ @grep -E 'githubrelease' doc/memoize.tex | ${COLOR_VERSION}
+
+include Makefile.package
+include Makefile.runtimes
+
+VERSION-MAN = of Memoize v$(VERSION)
diff --git a/macros/generic/memoize/README.md b/macros/generic/memoize/README.md
new file mode 100644
index 0000000000..9acde7b26e
--- /dev/null
+++ b/macros/generic/memoize/README.md
@@ -0,0 +1,11 @@
+Memoize is a package for externalization of graphics and memoization of
+compilation results in general, allowing the author to reuse the results of
+compilation-intensive code.
+
+Memoize (i) induces very little overhead, as all externalized graphics is
+produced in a single compilation. It features (ii) automatic recompilation upon
+the change of code or user-adjustable context, and (iii) automatic
+externalization of TikZ pictures and Forest trees, easily extensible to other
+commands and environments. Furthermore, Memoize (iv) supports
+cross-referencing, TikZ overlays and Beamer, (v) works with all major engines
+and formats, and (vi) is adaptable to any workflow.
diff --git a/macros/generic/memoize/doc/memoize-clean.1.md b/macros/generic/memoize/doc/memoize-clean.1.md
new file mode 100644
index 0000000000..138e0ee871
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-clean.1.md
@@ -0,0 +1,62 @@
+---
+title: memoize-clean
+section: 1
+header: User Manual
+footer: memoize-clean of Memoize v1.0.0
+date: October 10, 2023
+hyphenate: false
+---
+
+# NAME
+memoize-clean.pl, memoize-clean.py - Remove (stale) memo and extern files
+
+
+# SYNOPSIS
+**memoize-clean.pl** [*OPTIONS*] [*document1.mmz* ...]
+
+**memoize-clean.py** [*OPTIONS*] [*document1.mmz* ...]
+
+
+# DESCRIPTION
+
+**memoize-clean** is a script accompanying Memoize, a TeX package which allows
+the author to reuse the results of compilation-intensive code such as TikZ
+pictures.
+
+By default, this script removes stale memo and extern files. A stale memo or
+extern is an extern produced during a compilation of a previous version of the
+document which was neither used nor produced during the last compilation of the
+document. Typically, stale files arise when we change the memoized code (or
+its context).
+
+**memoize-clean.pl** removes all memo and extern files with prefixes mentioned
+in the listed **.mmz** files and by options **\--prefix** which are not
+explicitly mentioned in the **.mmz** files.
+
+Before deleting anything, **memoize-clean.pl** lists all the files it would
+delete and asks for confirmation.
+
+# OPTIONS
+
+**-p, \--prefix**
+: Add a memo/extern prefix for cleaning. This option may be given multiple
+ times.
+
+**-a, \--all**
+: Remove all memos and externs, rather than only the stale ones.
+
+**-y, \--yes**
+: Do not ask for confirmation.
+
+**-q, \--quiet**
+: Don't describe what's happening.
+
+**-h, \--help**
+: Show help.
+
+**-V, \--version**
+: Show the Memoize version number and exit.
+
+# SEE ALSO
+
+[Memoize manual](https://ctan.org/pkg/memoize), section 6.6.3.
diff --git a/macros/generic/memoize/doc/memoize-code.pdf b/macros/generic/memoize/doc/memoize-code.pdf
new file mode 100644
index 0000000000..7eeed4b3bf
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-code.pdf
Binary files differ
diff --git a/macros/generic/memoize/doc/memoize-code.sty b/macros/generic/memoize/doc/memoize-code.sty
new file mode 100644
index 0000000000..30d48f364c
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-code.sty
@@ -0,0 +1,276 @@
+%% memoize-code.sty
+%%
+%% This file is a part of Memoize, a TeX package for externalization of
+%% graphics and memoization of compilation results in general, available at
+%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+%%
+%% Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/memoize/)FILES.
+
+\ProvidesPackage{memoize-code}
+\RequirePackage{memoize-doc-common}
+
+% Typesetting the code & indentation
+\MacroIndent=0pt
+\MacroTopsep = 0pt
+\MacrocodeTopsep = 7pt plus 2pt minus 2pt
+\AddToHook{env/macrocode/before}{\macrocodepar}%
+\let\macrocodepar\par
+
+% A mark for extraction into the manual. We need to remove some vertical space
+% when this environment occurs alone in a doc block.
+\newenvironment{listingregion}[1]{%
+ \ifvmode
+ \let\macrocodepar\relax
+ \AddToHookNext{env/macrocode/begin}{\MacrocodeTopsep=0pt\relax}%
+ \def\listingregionskip{\vspace{-\baselineskip}}%
+ \listingregionskip
+ \else
+ \def\listingregionskip{}%
+ \fi
+}{\listingregionskip}
+
+\setlist{nosep}
+
+% Paragraph headings in the left margin, same as macro environments.
+\RenewDocumentCommand\paragraph{s t. m}{%
+ \setbox0=\hbox{%
+ \mbox{%
+ \textcolor{blue}{%
+ #3%
+ \IfBooleanT{#1}{\mbox{\ ---}}%
+ \IfBooleanT{#2}{\hspace{0.7em}}%
+ }%
+ }%
+ }%
+ \noindent
+ \ifdim\wd0>\marginparwidth
+ \hangindent\dimexpr\wd0-\marginparwidth\relax
+ \hangafter-1\relax
+ \fi
+ \marginpar{\ifdim\wd0<\marginparwidth\hfill\fi\box0}%
+ \AddToHookNext{env/macrocode/before}{\par\nohang}%
+ \pgf@keys@utilifnextchar\par{\myparagraph@gobblepar}{\ignorespaces}%
+}
+\long\def\myparagraph@gobblepar#1{\ignorespaces}
+
+\def\macrocodeenvname{macrocode}
+\def\MacroFont{\fontencoding\encodingdefault
+ \fontfamily\ttdefault
+ \fontseries\mddefault
+ \fontshape\shapedefault
+ \small
+ \ifx\@currenvir\macrocodeenvname\else\color{blue}\fi
+}
+\let\AltMacroFont\MacroFont % No special font for guarded code.
+
+% Typeset one-line guards to the left,
+% indent multi-line guard begin/ends by the guard level,
+% and let guards be orange.
+% Move the codeline number left.
+\def\Module#1{%
+ \begingroup
+ \IfBeginWith{#1}{*}{%
+ \def\next{}%
+ }{%
+ \IfBeginWith{#1}{/}{%
+ \def\next{}%
+ \advance\guard@level-1
+ }
+ {%
+ \def\next##1{%
+ \guard@level0
+ \setbox0=\lastbox
+ \llap{\unhbox0 ##1}%
+ }%
+ }%
+ }%
+ \next{%
+ \loop
+ \ifnum\guard@level>0
+ \hskip 1em
+ \advance\guard@level-1
+ \repeat
+ \color{orange}\mod@math@codes$\langle\mathsf{#1}\rangle$\hspace{0.1em}%
+ }%
+ \endgroup
+}
+
+
+% doc elements
+\NewDocElement[idxgroup={\texttt{/mmz} keys}, idxtype={\texttt{/mmz}}]{Key}{key}
+\NewDocElement[idxgroup={\texttt{/collargs} keys}, idxtype={\texttt{/collargs}}]{CollargsKey}{collargskey}
+\NewDocElement[idxgroup={\texttt{/advice} keys}, idxtype={\texttt{/advice}}]{AdviceKey}{advicekey}
+\NewDocElement[idxgroup={\texttt{/mmz/auto} keys}, idxtype={\texttt{/mmz/auto}}]{MmzAutoKey}{mmzautokey}
+\NewDocElement[idxgroup={\texttt{/handlers} keys}, idxtype={\texttt{/handlers}}]{HandlersKey}{handlerskey}
+\NewDocElement[idxgroup={\texttt{/advice/install} keys}, idxtype={\texttt{/advice/install}}]{AdviceInstallkey}{adviceinstallkey}
+
+% Funny: without repeating this here, I can't use commas to separate several macros.
+\RenewDocElement[macrolike=true, idxtype=,idxgroup=,printtype=]{Macro}{macro}
+\NewDocElement[idxtype={Lua function}, idxgroup=Lua functions]{LuaFunction}{luafun}
+
+
+\newcommand\PrintMainMacro[1]{{\MacroFont\string#1}\SpecialMainMacroIndex{#1}}
+
+\newcommand\MyIndex[3]{%
+ \global\advance\c@CodelineNo 1
+ \csuse{special@index}{#1\actualchar#2\encapchar#3}%
+ \global\advance\c@CodelineNo -1
+ \ignorespaces
+}
+\NewDocumentCommand\exclamationmark{}{!}
+
+
+% hanging indent for "key" and "macro" environments
+\newcommand\hang[2]{%
+ \setbox0=\hbox{\MacroFont \string#2\relax}% "\relax" is short enough to never trigger a hanging indent
+ \ifdim\wd0>\dimexpr\marginparwidth\relax
+ \hangindent\dimexpr\wd0-\marginparwidth\relax
+ \hangafter-#1\relax
+ \AddToHookNext{env/macrocode/before}{\par\nohang}%
+ \AddToHookNext{para/after}{\aftergroup\nohang}%
+ \fi
+ \ignorespaces
+}
+\newcommand\nohang{\hangindent 0pt\relax}
+\newcommand\indentmacrocode{%
+ \settowidth\MacroIndent{\theCodelineNo\ }%
+ \addtolength\MacroIndent{\hangindent}%
+}
+\newcommand\noindentmacrocode{%
+ \setlength\MacroIndent{0em}%
+ \AddToHookNext{env/macrocode/begin}{\MacrocodeTopsep 0pt\relax}%
+}
+
+% and now ... autohang!
+% (the macros should be listed without spaces after commas)
+\usepackage{advice}
+\pgfkeys{
+ /my/.cd,
+ .install advice,
+ advice/hang/.style={outer handler=\autohang},
+ advice=\key{hang},
+ advice=\macro{hang},
+ advice=\autokey{hang},
+ advice=\mmzautokey{hang},
+ advice=\collargskey{hang},
+ advice=\handlerskey{hang},
+ advice=\adviceinstallkey{hang},
+ advice=\luafun{hang},
+}
+\def\hangn{0}
+\def\hanglength{0}
+\def\hangstring{}
+\newcommand\autohang[2][]{%
+ \ifstrequal{#1}{noprint}{}{%
+ \def\temp{#2}%
+ \@for\hangtemp:=\temp\do{\computehang}%
+ \edef\temp{\noexpand\hang{\hangn}{\expandonce\hangstring}}\temp
+ }%
+ \AdviceOriginal[#1]{#2}%
+}
+\def\computehang{%
+ \StrLen{\expandafter\string\hangtemp}[\temp]%
+ \edef\hangn{\the\numexpr\hangn+1}
+ \ifnum\temp>\hanglength\relax
+ \let\hanglength\temp
+ \let\hangstring\hangtemp
+ \fi
+}
+
+
+
+%%% Various:
+\newcommand\MS{\textsuperscript{M}\S} % manual section
+
+% Read in the manual .aux, for \MS cross-references.
+\begingroup
+\let\orig@newlabel\newlabel
+\def\newlabel#1#2{%
+ \IfBeginWith{#1}{sec:}{\orig@newlabel{#1}{#2}}{}%
+}
+\def\doline{%
+ \expandafter\futurelet\expandafter\firsttoken\expandafter\dolinei\line\fi}
+\def\dolinei{\ifx\firsttoken\newlabel}%
+\openin0=memoize.aux
+\loop
+ \unless\ifeof0
+ \read0 to \line
+ \doline
+\repeat
+\closein0
+\endgroup
+
+
+
+%%%% Filter the index, keeping only the entries with a corresponding "main"
+%%%% entry.
+
+\AddToHook{enddocument/end}{%
+ \immediate\closeout\@indexfile % it is never explicitly closed!
+ \filterindex
+}
+
+\newwrite\tempidx
+\def\filterindex{%
+ \IfFileExists{\jobname.idx}{%
+ \begingroup
+ \catcode`\%=12
+ \def\indexentry{\filterindex@parse\filterindex@first@pass}%
+ \immediate\openout\tempidx \jobname.idx.orig
+ \input \jobname.idx
+ \immediate\closeout\tempidx
+ \def\indexentry{\filterindex@parse\filterindex@second@pass}%
+ \immediate\openout\tempidx \jobname.idx
+ % \tracingall
+ \input \jobname.idx.orig
+ \immediate\closeout\tempidx
+ \endgroup
+ }{}%
+}
+
+\def\filterindex@parse{%
+ \catcode`\\=12
+ \filterindex@parse@i
+}
+\long\def\filterindex@parse@i#1#2#3{\filterindex@parse@ii#1#2{#3}}
+\long\def\filterindex@parse@ii#1#2=#3hdclindex#4#5#6{%
+ \catcode`\\=0
+ #1{#2}{#3}{#4}{#5}{#6}%
+}
+
+\long\def\filterindex@first@pass#1#2#3#4#5{%
+ \filterindex@write{#1}{#2}{#3}{#4}{#5}%
+ \IfStrEq{#4}{main}{%
+ \csdef{\detokenize{filt@#1}}{}%
+ }{}%
+}
+\long\def\filterindex@second@pass#1#2#3#4#5{%
+ \ifcsdef{\detokenize{filt@#1}}{%
+ \filterindex@write{#1}{#2}{#3}{#4}{#5}%
+ }{%
+ }%
+}
+\long\def\filterindex@write#1#2#3#4#5{%
+ \immediate\write\tempidx{\string\indexentry\detokenize{{#1=#2hdclindex{#3}{#4}}{#5}}}%
+}
+
+
+
+% Local Variables:
+% TeX-engine: luatex
+% TeX-master: "memoize-code.tex"
+% TeX-auto-save: nil
+% End: \ No newline at end of file
diff --git a/macros/generic/memoize/doc/memoize-code.tex b/macros/generic/memoize/doc/memoize-code.tex
new file mode 100644
index 0000000000..6daa583383
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-code.tex
@@ -0,0 +1,120 @@
+\documentclass[a4paper,11pt]{ltxdoc}
+
+\usepackage[left=1cm,right=1cm,top=1cm,bottom=1cm,
+ marginparwidth=0cm,marginparsep=0pt,
+ nohead,includefoot
+]{geometry}
+\settowidth\marginparsep{\ }
+
+% There is a \mmzset in memoize-doc-common.
+\usepackage{nomemoize}
+
+% Hypdoc (which loads hyperref) must be loaded before memoize-code.
+\usepackage{hypdoc}
+\hypersetup{colorlinks=true, allcolors=blue}
+
+\usepackage{memoize-code} % Also loads memoize-doc-common
+
+\pdfsystem{makeindex -s gind.ist \jobname.idx}
+
+\CodelineIndex
+\EnableCrossrefs
+
+\title{The documented source of Memoize, Advice and CollArgs}
+\author{Sašo Živanović\\[2mm]
+ \emailsymbol~\url(mailto:){saso.zivanovic@guest.arnes.si}\\
+ \homepagesymbol~\url(http://){spj.ff.uni-lj.si/zivanovic}\\
+ \faGithub~\url(https://){github.com/sasozivanovic}}
+
+\datefrompackageversion{collargs}
+\edef\allpackagever{CollArgs v\packagever}
+\datefrompackageversion{advice}
+\epreto\allpackagever{Advice v\packagever, }
+\datefrompackageversion{memoize}
+\epreto\allpackagever{Memoize v\packagever, }
+\let\packagever\allpackagever
+
+\hypersetup{
+ % pdftitle={Memoize},
+ pdfauthor={Sašo Živanović},
+ pdfsubject={externalization},
+ pdfkeywords={LaTeX, externalization, memoization}
+}
+
+\begin{document}
+
+\maketitle
+
+\def\docdir{..}
+\DocInput{\docdir/memoize.dtx}
+
+\section{Auxiliary packages}
+\label{sec:code:utils}
+
+\subsection{Extending commands and environments with Advice}
+\label{sec:code:auto}
+
+\DocInput{\docdir/advice.dtx}
+
+\subsection{Argument collection with CollArgs}
+\label{sec:code:collargs}
+
+\DocInput{\docdir/collargs.dtx}
+
+\clearpage
+\restoregeometry
+
+\section{The scripts}
+\label{sec:code:scripts}
+
+\def\continuation{\llap{\textcolor{purple}{$\rightarrow$}\,}}
+
+\subsection{The Perl extraction script \texttt{memoize-extract.pl}}
+
+\lstinputlisting[firstline=20, % manual (exclude the license information)
+ language=Perl,
+ breaklines, breakindent=4em, postbreak=\continuation,
+ commentstyle=,
+]{../memoize-extract.pl}
+
+\subsection{The Python extraction script \texttt{memoize-extract.py}}
+
+\lstinputlisting[firstline=20, % manual (exclude the license information)
+ language=Python,
+ breaklines, breakindent=4em, postbreak=\continuation,
+ commentstyle=,
+]{../memoize-extract.py}
+
+\subsection{The Perl clean-up script \texttt{memoize-clean.pl}}
+
+\lstinputlisting[firstline=20, % manual (exclude the license information)
+ language=Perl,
+ breaklines, breakindent=4em, postbreak=\continuation,
+ commentstyle=,
+]{../memoize-clean.pl}
+
+\subsection{The Python clean-up script \texttt{memoize-clean.py}}
+
+\lstinputlisting[firstline=20, % manual (exclude the license information)
+ language=Python,
+ breaklines, breakindent=4em, postbreak=\continuation,
+ commentstyle=,
+]{../memoize-clean.py}
+
+\clearpage
+
+\IndexPrologue{\section*{Index}Numbers written in red refer to the code line
+ where the corresponding entry is defined; numbers in blue refer to the code
+ lines where the entry is used.}
+
+\setcounter{IndexColumns}{2}
+\def\main#1{\begingroup\hypercolor{link}{red}#1\endgroup}
+\PrintIndex
+
+\end{document}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-engine: luatex
+%%% TeX-master: t
+%%% End:
diff --git a/macros/generic/memoize/doc/memoize-doc-common.sty b/macros/generic/memoize/doc/memoize-doc-common.sty
new file mode 100644
index 0000000000..fe6ab0023f
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-doc-common.sty
@@ -0,0 +1,173 @@
+%% memoize-doc-common.sty
+%%
+%% This file is a part of Memoize, a TeX package for externalization of
+%% graphics and memoization of compilation results in general, available at
+%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+%%
+%% Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/memoize/)FILES.
+
+\ProvidesPackage{memoize-doc-common}
+
+\usepackage[inline,shortlabels]{enumitem}
+\usepackage{tcolorbox}
+\tcbuselibrary{listings,hooks,raster,skins}
+\usepackage{tikz}
+\usepackage{xstring}
+\usepackage{microtype}
+
+\usepackage{listings}
+\lstset{
+ language=[LaTeX]TeX,
+ columns=fullflexible,
+ basicstyle=\ttfamily\small,
+ commentstyle=\color{purple},
+ moredelim={[is][\pstyle]{~}{~}}
+}
+\lstMakeShortInline[moredelim={[is][\pstyle]{~}{~}}]{ˇ}%
+\tcbset{
+ linerange/.style={listing options app={linerange=#1}},
+}
+
+
+%%%%%%%%%%%%%%
+% title page %
+
+\usepackage{pdftexcmds}
+\let\pdfsystem\pdf@system
+
+% version and date
+\def\datefrompackageversion#1{%
+ \setbox0=\hbox{%
+ \def\ProvidesPackage##1[##2]{%
+ \gdef\@packagever{##2}%
+ \endinput
+ }%
+ \input{#1.sty}%
+ }%
+ \expandafter\parsepackagever@\@packagever\parsepackagever@
+}
+\def\parsepackagever@#1/#2/#3 v#4 #5\parsepackagever@{%
+ \year=#1\relax\month=#2\relax\day=#3\relax
+ \def\packagever{#4}\def\packagedesc{#5}%
+}
+
+\renewcommand\maketitle{%
+ \begingroup
+ \mmzset{disable, auto={tcolorbox}{clear options}}% \mmznext does not work here -- todo: maybe it does now
+ \begin{tcolorbox}[
+ colback=emphcolor,
+ fonttitle=\LARGE\bf,
+ halign title=center,
+ halign upper=center,
+ halign lower=center,
+ tikznode lower,
+ adjusted title=\@title,
+ ]
+ \packagever\\
+ \@date
+ \tcblower
+ \Large\@author
+ \end{tcolorbox}
+ \endgroup
+}
+\colorlet{emphcolor}{yellow!90!black}
+\usepackage{marvosym}
+\let\emailsymbol\Letter
+\let\homepagesymbol\ComputerMouse
+\usepackage{fontawesome} % for \faGithub
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%
+% \verb@eol@error hack %
+
+% The problem: doc.sty (re)defines \verb "to check for newlines in its argument
+% since a missing delimiter is difficult to detect in doc source." In
+% principle, that's great, but I really hate it that I can't use Emacs's
+% "fill-paragraph" without fear of getting the "Text for \noexpand\verb command
+% ended by end of line" error.
+%
+% Solution: the original \verb@eol@error defines a newline (which is active at
+% that point) to throw an error. We redefine \verb@eol@error to define a
+% newline to gobble an immediately following percent character (assuming that
+% we are processing .dtx documentation) and spaces.
+
+\begingroup
+ \obeylines%
+ \gdef\verb@eol@error{\obeylines%
+ \def^^M{\futurelet\verb@eol@nextchar\verb@eol@peek}%
+ }%
+\endgroup
+\gdef\verb@eol@peek{%
+ \if\@percentchar\verb@eol@nextchar
+ \expandafter\verb@eol@ignorepercentchar
+ \else
+ \space % we need one space, though!
+ \expandafter\verb@eol@ignorespaces
+ \fi
+}
+\def\verb@eol@ignorepercentchar#1{% #1 = "%"
+ \@xobeysp\verb@eol@ignorespaces}
+\begingroup\catcode`\ =13 \gdef\verb@eol@otherspace{ }\endgroup
+% |\ignorespaces| wouldn't work here, as our spaces are of category 13
+\def\verb@eol@ignorespaces{%
+ \futurelet\verb@eol@nextchar\verb@eol@ignorespaces@peek}
+\def\verb@eol@ignorespaces@peek{%
+ \expandafter\ifx\verb@eol@otherspace\verb@eol@nextchar
+ \expandafter\verb@eol@ignorespaces@space
+ \fi
+}
+\def\verb@eol@ignorespaces@space#1{\verb@eol@ignorespaces}
+
+% The same hack, but for \lstinline of package listings.
+% https://tex.stackexchange.com/a/473459/16819
+
+\def\lst@InlineM#1{\gdef\lst@inlinechars{%
+ \lst@Def{`#1}{\lst@DeInit\egroup\global\let\lst@inlinechars\@empty}%
+ \lst@Def{13}{\lst@ProcessSpace}}% <---
+ \lst@inlinechars}
+
+
+%%%%%%%%%%%
+% various %
+
+\usepackage{hologo}
+\def\TikZ;{{\rm Ti\emph{k}Z}}
+\def\PGF;{PGF}
+\newcommand\PGFmanual[1]{%
+ \href
+ {http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf}
+ {\S#1 of the Ti\emph{k}Z \& \textsc{PGF} manual}%
+}
+\newcommand\Alt{\,$\vert$\,}
+\newcommand\hyp{\discretionary{}{}{}}
+\newcommand\fncomma{\ensuremath{{^,}}}
+
+
+% load hyperref before this
+
+\protected\def\hypercolor#1#2{% #1 = url/link/.., #2 = color
+ \expanded{%
+ \noexpand\HyColor@HyperrefColor{#2}\expandonce{\csname @#1color\endcsname}%
+ }%
+}
+
+\RenewDocumentCommand\url{ O{} D(){} m }{%
+ {\hypercolor{url}{#1}\href{#2#3}{\texttt{#3}}}}
+
+\def\pkgcolor{black}
+\NewDocumentCommand\pkg{O{\pkgcolor}m}{{%
+ \hypercolor{url}{#1}%
+ \href{https://ctan.org/pkg/#2}{\texttt{#2}}}}
diff --git a/macros/generic/memoize/doc/memoize-doc.sty b/macros/generic/memoize/doc/memoize-doc.sty
new file mode 100644
index 0000000000..2a1d7482c4
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-doc.sty
@@ -0,0 +1,711 @@
+%% memoize-doc.sty
+%%
+%% This file is a part of Memoize, a TeX package for externalization of
+%% graphics and memoization of compilation results in general, available at
+%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+%%
+%% Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/memoize/)FILES.
+
+% \usepackage{lstdoc} % this must be loaded before hyperref
+\usepackage{shortvrb}
+\AtBeginDocument{\MakeShortVerb{\|}}
+% \usepackage{hypdoc}
+\usepackage[hyperindex=false]{hyperref}
+\hypersetup{
+ colorlinks=true,
+ allcolors=black,
+ linkcolor=Hyperlink,
+}
+
+\usepackage{microtype}
+%\SetExpansion[context=sloppy,stretch=30,shrink=50,step=1]{encoding=*}{}%
+
+\usepackage{fnpct}
+\usepackage{memoize-doc-common}
+
+% explicitly load advice (and thereby collargs) for when we load nomemoize
+\usepackage{advice}
+
+\usepackage{forest}
+\useforestlibrary{edges}
+
+% \usepackage[extract=latex]{memoize}
+% \usepackage{memoize}
+\usepackage[infoshow]{tracefnt}
+
+\tcbuselibrary{xparse,breakable}
+
+\mmzset{
+ auto={tcolorbox}{memoize, options=verbatim},
+ auto={tcboxedraster}{memoize, options=verbatim},
+ auto={tcbraster}{memoize, options={verbatim,ignore spaces}},
+ auto={tcblisting}{memoize, options={verbatim,ignore spaces}},
+ auto csname={tcbinputexample code}{memoize, args=mmm+m, ignore spaces},
+ auto=\tcbinputlisting{memoize, args=m, options=ignore spaces},
+ % The following doesn't work perfectly, but it's good enough.
+ auto key={/tcb/breakable}{run if memoizing, outer handler=\makeunmemoizableunless{false}},
+ auto key={/tcb/float}{run if memoizing, outer handler=\makeunmemoizableunless{}},
+}
+
+\def\makeunmemoizableunless#1#2\pgfeov{%
+ \ifstrequal{#1}{#2}{}{\mmzUnmemoizable}%
+ \AdviceOriginal#1\pgfeov
+}
+
+\newcommand\introboxtitle[1]{\strut\textcolor{emphcolor}{\textbf{#1}}}
+
+\usepackage{fancyhdr}
+\usepackage[skip=0.3\baselineskip plus 2pt]{parskip}
+\usepackage[bottom]{footmisc}
+\usepackage{xparse}
+\usepackage{multicol}
+
+
+
+
+\usepackage{graphicx}
+
+\usepackage{cprotect}
+\setlist[description]{
+ itemsep=0.3\baselineskip plus 2pt minus 1pt,
+ parsep=0.3\baselineskip plus 2pt
+}
+\SetEnumitemKey{comma}{itemjoin={{, }}}
+\SetEnumitemKey{and}{itemjoin={{, }}, itemjoin*={{, and }}}
+
+% \usepackage{lstdoc} % this must be loaded before hyperref
+%\usepackage{lstautogobble} % todo: does not work!
+\def\listings@file@value@in@reset{}
+\tcbset{
+ listing file/.append code={%
+ \ifmemoizing
+ \ifstrequal{#1}{\jobname.listing}{%
+ % We're in tcolorbox's reset, do nothing
+ }{%
+ \mmzset{
+ context={%
+ listing file={#1},
+ md5sum=\csuse{pdf@filemdfivesum}{#1},
+ },
+ }%
+ }%
+ \fi
+ },
+ centering/.style={before=\centering},
+}
+\colorlet{pointcolor}{green!50!black}
+\def\pstyle{\color{pointcolor}}% todo: hyperlink?
+\setlength\textfloatsep{0.5\baselineskip plus 2pt minus 2pt}
+\tcbset{
+ top=1mm, bottom=1mm,
+ beforeafter skip balanced=0.5\baselineskip plus 2pt minus 2pt,
+ raster every box/.style={top=1mm, bottom=1mm},
+ before upper={\parskip0.3\baselineskip plus 2pt\relax},
+ every box on layer 1/.style={
+ fonttitle=\bfseries,
+ },
+ my listing options/.style={
+ listing options app={
+ moredelim={[is][\pstyle]{~}{~}},
+ commentstyle=\color{purple},
+ morekeywords={unexpanded,expanded,expandonce,NewDocumentCommand,IfValueTF},
+ breakindent=10pt,
+ },
+ },
+ my listing options,
+ % for listings inside a tcboxedraster ...
+ reset/.append style=my listing options,
+ % titles
+ attach shifted boxed title to top right/.style={
+ attach boxed title to top right={
+ xshift=1.5mm, yshift=-\tcboxedtitleheight/2, #1},
+ },
+ attach shifted boxed title to top right/.default={},
+ attach shifted boxed title to top left/.style={
+ attach boxed title to top left={
+ xshift=-1.5mm, yshift=-\tcboxedtitleheight/2, #1},
+ },
+ attach shifted boxed title to top left/.default={},
+ my boxed title/.style={
+ enhanced, title={#1},
+ fonttitle=\scriptsize,
+ boxed title style={size=small},
+ },
+ my boxed title/.value required,
+ extern page/.style={
+ my boxed title=extern page,
+ boxed title style={colback=blue!70!black, colframe=blue!25!white},
+ attach shifted boxed title to top right,
+ },
+ document page/.style={
+ my boxed title=document page,
+ boxed title style={colback=green!60!black, colframe=green!25!white},
+ attach shifted boxed title to top right,
+ },
+ % end titles
+ bad/.style={enhanced,
+ finish={
+ \begin{tcbclipinterior}
+ \draw[red!40!white, opacity=0.4, line width=1cm]
+ (interior.south west)--(interior.north east);
+ \end{tcbclipinterior}
+ },
+ },
+ mark region/.style 2 args={
+ enhanced,
+ underlay={
+ \fill[pointcolor,opacity=0.1]
+ ([yshift=-\kvtcb@boxsep-\kvtcb@top-2.5ex*(#1-1)]interior.north west) rectangle ([yshift=-\kvtcb@boxsep-\kvtcb@top-2.5ex*#2]interior.north east);
+ },
+ },
+ warning/.style={colback=red!15},
+ to be continued on right/.style={
+ frame code={% line thickness is uniform and depends on tcolorbox's leftrule
+ \draw[color=tcbcolframe,
+ line width=2*\kvtcb@left@rule, rounded corners=2*\kvtcb@left@rule,
+ ]
+ (interior.north east)--(interior.north west)
+ --(interior.south west)--(interior.south east);
+ },
+ interior code app={
+ \draw[color=tcbcolframe,line width=\kvtcb@left@rule,dashed]
+ ([xshift=-0.5*\kvtcb@left@rule]interior.south east)
+ --([xshift=-0.5*\kvtcb@left@rule]interior.north east);
+ },
+ },
+}
+\def\examplepdfpath{\examplepath.c1.pdf}
+\NewDocumentCommand{\includeexamplepdf}{ O{} O{\examplepdfpath} D(){} m}{%
+ \mbox{%
+ \tcbincludegraphics[reset,capture=hbox,graphics options={clip,#4},#1]{#2}#3%
+ }%
+}%
+\def\ExampleName#1{\edef\examplename{#1}\ignorespaces}
+\def\makeexample#1{\pdfsystem{make -C \exampledir\space#1}\ignorespaces}
+% \def\makeexample#1{\pdfsystem{make -B -C \exampledir\space#1}}
+\def\examplepath{\exampledir\examplename}
+\RequirePackage{intopdf}
+\RequirePackage{fontawesome}
+\tcbset{
+ example title/.style={
+ enhanced,
+ % uniform height and (zero) depth
+ before title={\begingroup \setbox0\hbox\bgroup},
+ after title={\egroup\ht0 1.2ex \dp0 0pt \box0 \endgroup},
+ title={\texttt{#1}},
+ top=2mm,
+ attach shifted boxed title to top left,
+ fonttitle={\small\hypercolor{link}{white}},
+ },
+ example title/.default=\examplename.tex,
+ attachment/.estore in=\attachmentpath,
+ attachment name/.estore in=\attachmentname,
+ attachment name/.default=noname.tex,
+ no attachment/.style={attach/.style={}},
+ attachment=\jobname.listing.attachment,
+ attachment name,
+ % attach example/.style={
+ % attachment/.expanded=\examplepath.tex.work,
+ % attachment name/.expanded=\examplename.tex,
+ % attach,
+ % },
+ attach/.style={
+ overlay app={%
+ \node at (frame.north east) [
+ fill=white, draw=gray, thick,
+ ellipse, inner xsep=-0.5mm, inner ysep=0, shift={(-2mm,-2mm)}, rotate=45,
+ ]{%
+ \pdfsystem{make -f examples/Makefile \attachmentpath}%
+ \expandafter\myattachandlink\expandafter[\attachmentname]{\attachmentpath}[application/x-tex]{Click here to open the code.}{\rotatebox{-45}{\faPaperclip}}
+ };
+ }
+ },
+ excerpt/.code 2 args={%
+ \makeexample{#2.excerpt SOURCE=#1}%
+ },
+}
+\NewDocumentCommand\attachexample{O{\examplename.tex} O{\examplepath.tex.c1.attachment}}{%
+ {\textsuperscript{\kern-0.25em \expandafter\myattachandlink\expandafter[#1]{#2}[application/x-tex]{Click here to open the code.}{\rotatebox{-45}{\faPaperclip}}\kern-0.25em \relax}}}
+\newcommand\myattachandlink[2][\filename]{%
+ \begingroup
+ \def\filename{#2}%
+ \immediate\write\attachments{#2 #1 ## line \the\inputlineno}%
+ \ifmemoizing
+ \xtoksapp\mmzCCMemo{%
+ \immediate\write\attachments{#2 #1 ## line \the\inputlineno}%
+ }%
+ \fi
+ \expanded{%
+ \endgroup
+ \noexpand\attachandlink[#1]{#2}%
+ }%
+}
+\newwrite\attachments
+\immediate\openout\attachments attachments.lst
+\AtEndDocument{\immediate\closeout\attachments}
+
+\NewTCBInputListing{\tcbinputexample}{
+ >{\edef\ProcessedArgument} D(){\examplename} O{.tex} O{.c1} +m }
+{%
+ /mmz/context={dtxmd5sum=\csuse{pdf@filemdfivesum}{\exampledir#1#2.dtx}},
+ example title={#1#2},
+ % enlarge left by=\leftmargin,% this takes care of using this box in lists
+ listing and comment,
+ one file/.style={
+ listing file={\exampledir#1#2#3},
+ attachment={\exampledir#1#2#3},
+ },
+ listing file=\exampledir#1#2#3.listing,
+ /utils/exec={\edef\examplepdfpath{\exampledir#1#3.pdf}},%
+ attachment=\exampledir#1#2#3.attachment,
+ attachment name=#1#2,%
+ #4,
+ attach,
+}
+\nommzkeys{context}
+
+\tcbset{
+ full width/.style={grow to left by=\leftmargin},
+ listing and compile/.style={
+ listing and comment,
+ comment={%
+ \input\examplepath.tex.c#1
+ }
+ },
+ listing and compile/.default=1,
+}
+
+\pgfkeys{
+ /handlers/.detokenize/.style={\pgfkeyscurrentpath/.expand once=\detokenize{#1}},
+ /utils/typeout/.code={\typeout{#1}},
+}
+\let\pdfsystem\pdf@system
+\let\pdffilemdfivesum\pdf@filemdfivesum
+
+\usepackage{booktabs}
+\usepackage{tabularx}
+
+
+\usetikzlibrary{decorations.pathmorphing, arrows.meta}
+\usepackage{tikzlings-penguins,tikzlings-koalas,tikzlings-owls}
+\tikzset{
+ ->/.tip={Kite},
+ snake arrow/.style=
+ {->, decorate,
+ decoration={snake, amplitude=.4mm, segment length=2mm, post length=2mm},
+ },
+}
+
+% title page
+\renewcommand\abstractname{\vskip-\baselineskip}
+
+% sections
+\newtcbox{\section@box}[3]{tile,before=\noindent,after=,
+ fontupper=\normalfont#1\bfseries,capture=minipage,
+ colback=emphcolor,
+ boxsep=0mm,top=#2,bottom=#2,left=\oddsidemargin+1in,right=\oddsidemargin+1in,
+ spread sidewards,#3
+}
+
+\newif\ifsectionclearpage
+\sectionclearpagetrue
+\newif\ifsubsectionclearpage
+\subsectionclearpagetrue
+
+\renewcommand\section{%
+ \ifsectionclearpage\clearpage\fi
+ \@startsection{section}{1}{\z@}%
+ {5mm}{5mm}%
+ {\section@box{\Large}{4mm}{fuzzy halo=1mm with blue!50!gray}}}
+\renewcommand\subsection{%
+ \ifsubsectionclearpage\ifnum\c@subsection=0 \else\clearpage\fi\fi
+ \@startsection{subsection}{2}{\z@}%
+ {-3.25ex\@plus -1ex \@minus -.2ex}{1.5ex \@plus .2ex}%
+ {\section@box{\large}{2mm}{fuzzy halo=1mm with blue!50!gray}}}
+\renewcommand\subsubsection{%
+ \mmznext{disable}%
+ \@startsection{subsubsection}{2}{\z@}%
+ {-3.25ex\@plus -1ex \@minus -.2ex}{1.5ex \@plus .2ex}%
+ {\section@box{}{2mm}{}}}
+\newtcbox{\paragraph@box}{tile,before=,after=,capture=hbox,
+ fontupper=\normalfont\normalsize\bfseries\hypercolor{link}{black}\vphantom{dj},
+ box align=base,
+ boxsep=0mm,
+ left=\oddsidemargin+1in, enlarge left by=-\oddsidemargin-1in,
+ top=1.2mm, enlarge top by=-1.2mm,
+ bottom=1mm, enlarge bottom by=-1mm,
+ right=12mm, enlarge right by=-8mm, arc=0mm, rightrule=0mm,
+ interior style={left color=emphcolor, right color=white},
+}
+\let\oldparagraph\paragraph
+\def\paragraphskip{3.25ex \@plus1ex \@minus.2ex}
+\RenewDocumentCommand\paragraph{sm}{%
+ \mmznext{disable}%
+ \@startsection{paragraph}{4}{\z@}{\paragraphskip}{-1em}{\paragraph@box}{#2}%
+ \IfBooleanT{#1}{\hspace*{\dimexpr-8mm+0.5em}}%
+ \hskip 0pt plus .5em
+ \IfBooleanF{#1}{\nopagebreak}% % todo: this is bad, if the paragraph is long
+}
+
+\NewTotalTCBox{\Emph}{m}{my code box, fontupper=\rm}{#1}
+\NewTotalTCBox{\EmphTT}{m}{my code box}{#1}
+\NewTotalTCBox{\EmphVerbatim}{v}{my code box}{#1}
+\tikzset{
+ emphshade/.style={
+ opacity=0.6,
+ top color=#1, bottom color=#1, middle color=emphcolor,
+ },
+ emphshade/.default=white,
+}
+\tcbset{
+ my code box/.style={
+ reset, enhanced, verbatim,
+ boxsep=0pt, left=0.3ex,right=0.3ex, box align=base,
+ interior hidden, frame hidden,
+ overlay={\shade[emphshade]
+ ([yshift=0.7ex]frame.north west) rectangle ([yshift=-0.7ex]frame.south east);
+ },
+ },
+}
+
+% verbatim code in the implementation
+\lstdefinestyle{code}{style=tcblatex,xleftmargin=\leftmargin,aboveskip=\parskip}
+
+
+
+
+
+
+\newcommand\therefore{\ensuremath{\Rightarrow}}
+\newcommand\nohyphen{\discretionary{}{}{}}
+\let\gobble\@gobble
+
+\lstset{
+ rangebeginprefix=\ \ \%\%\%\ begin\ listing\ region:\ ,
+ rangebeginsuffix=,
+ rangeendprefix=\ \ \%\%\%\ end\ listing\ region:\ ,
+ rangeendsuffix=,
+ includerangemarker=false,
+ keepspaces=true,
+}
+
+\def\relaxmmzcommands{%
+ \let\mmzPrefix\gobble
+ \let\mmzNewCMemo\gobble
+ \let\mmzNewCCMemo\gobble
+ \def\mmzNewExtern##1##2##3##4##5{}%
+ \let\mmzUsedCMemo\gobble
+ \let\mmzUsedCCMemo\gobble
+ \let\mmzUsedExtern\gobble
+}
+
+\usepackage{xstring}
+\usepackage{placeins}
+
+\NewDocumentCommand\makeexcerpt{ m O{.tex} D(){../../memoize.edtx} }{%
+ \ExampleName{#1}%
+ \makeexample{#1#2.excerpt SOURCE=#3}%
+ \ignorespaces
+}
+
+\newcommand\sed[2]{%
+ \begingroup
+ \def\cmd##1{\noexpand\\##1}%
+ \def\0{\bslash0}%
+ \def\1{\bslash1}%
+ \def\2{\bslash2}%
+ \def\3{\bslash3}%
+ \def\4{\bslash4}%
+ \def\5{\bslash5}%
+ \def\6{\bslash6}%
+ \def\7{\bslash7}%
+ \def\8{\bslash8}%
+ \def\9{\bslash9}%
+ \def~{\noexpand~}%
+ \def\n{\string\n}%
+ \def\({\bslash(}%
+ \def\){\bslash)}%
+ \let\lbrace\sedlbrace
+ \let\rbrace\sedrbrace
+ \edef\nobrace{[^\sedlbrace\sedrbrace]}
+ \edef\marg{{[^\sedrbrace]*}}%
+ \def\repeat##1{\bslash\sedlbrace##1\bslash\sedrbrace}%
+ \pdfsystem{sed -i "#1" #2}%
+ \endgroup
+}
+\begingroup
+\catcode`\(=1
+\catcode`\)=2
+\catcode`\{=12
+\catcode`\}=12
+\gdef\sedlbrace({)%
+\gdef\sedrbrace(})%
+\endgroup
+
+\usepackage{pifont}
+\newcommand\yes{{\small\ding{51}}} % pifont
+\newcommand\no{{\small\ding{55}}} % pifont
+
+%\newcommand\oarg[1]{{\ttfamily[}\meta{#1}{\ttfamily]}}
+
+\definecolor{Option}{rgb}{0.118,0.546,0.222}
+\definecolor{Definition}{rgb}{0.784,0.06,0.176}
+\definecolor{ExampleFrame}{rgb}{0.628,0.705,0.942}
+\definecolor{ExampleBack}{rgb}{0.963,0.971,0.994}
+\definecolor{Hyperlink}{rgb}{0.281,0.275,0.485}
+\definecolor{Fade}{rgb}{0.5,0.5,0.5}
+\definecolor{EasyDefinition}{rgb}{0.06,0.784,0.176}
+
+{\catcode`\|=\z@ \catcode`\\=12
+|gdef|bslash{\}}
+\DeclareRobustCommand\cs[1]{\texttt{\bslash\detokenize{#1}}}%
+\DeclareRobustCommand\env[1]{\texttt{#1}}%
+%\def\marg#1{{\ttfamily\char`\{}\meta{#1}{\ttfamily\char`\}}}
+\def\marg#1{\hskip 0pt plus 1pt{\ttfamily\char`\{}\meta{#1}{\ttfamily\char`\}}}
+\def\oarg#1{\hskip 0pt plus 1pt{\ttfamily[}\meta{#1}{\ttfamily]}}
+\def\bracestt#1{\hskip 0pt plus 1pt{\ttfamily\char`\{#1\char`\}}}
+\def\braces#1{\hskip 0pt plus 1pt{\ttfamily\char`\{}#1{\ttfamily\char`\}}}
+\def\bracketstt#1{\hskip 0pt plus 1pt{\ttfamily[#1]}}
+\def\brackets#1{\hskip 0pt plus 1pt{\ttfamily[}#1{\ttfamily]}}
+\DeclareRobustCommand\meta[1]{%
+ \ensuremath\langle
+ \ifmmode \expandafter \nfss@text \fi
+ {%
+ \meta@font@select
+ \edef\meta@hyphen@restore{\hyphenchar\the\font\the\hyphenchar\font}%
+ \hyphenchar\font\m@ne
+ \language\l@nohyphenation
+ #1\/%
+ \meta@hyphen@restore
+ }%
+ \ensuremath\rangle
+}
+\def\meta@font@select{\rm\itshape}
+\DeclareRobustCommand\metabf[1]{%
+ \begingroup
+ \def\meta@font@select{\rm\itshape\bfseries}%
+ \meta{#1}%
+ \endgroup
+}
+{\catcode`\%=12 \gdef\percentchar{%}}
+\def\coloredpercentchar{\hbox{\textcolor{purple}{\percentchar}}}
+\newcommand\alt{\ensuremath{\vert}}% without space around, unlike \Alt
+\newcommand\code[1]{\texttt{\spaceskip 0.5em plus 0.2em minus 0.2em #1}}
+\newcommand\Arg[1]{\texttt{\##1}}
+
+\def\TikZ{\href{https://ctan.org/pkg/pgf}{{\rm Ti\emph{k}Z}}\xspace}
+\def\PGF{\href{https://ctan.org/pkg/pgf}{PGF}\xspace}
+\def\Emacs{\href{https://www.gnu.org/software/emacs}{Emacs}\xspace}
+\def\AucTeX{\href{https://www.gnu.org/software/auctex}{AUC\hologo{TeX}}\xspace}
+
+% collargs reference, pi = programmer's interface
+% Shrink the glyphs in the footnote if necessary.
+\tcbset{
+ pi/.style={
+ overlay={%
+ \node at (frame.north east) [anchor=north west, inner sep=0] {\footnotemark};
+ },
+ after app={%
+ \footnotetext{%
+ % \adjustspacing=2 % already 2 ... microtype?
+ \myfontexpansionon
+ \yadocset{before/.code={\cspreto{yadoc@name@prefix}{\myfontexpansionon}}}%
+ \mbox{The programmer's interface:} #1.%
+ }%
+ },
+ },
+}
+\DeclareRobustCommand\myfontexpansionon{%
+ \directlua{font.setexpansion(font.current(),50,50,1)}%
+}
+\DeclareRobustCommand\myfontexpansionoff{%
+ \directlua{font.setexpansion(font.current(),0,0,1)}%
+}
+
+\AtBeginDocument{%
+ \setbox0=\hbox{%
+ \footnotesize\ttfamily
+ \directlua{ninettfont=font.current()}%
+ }%
+}
+
+% \AtBeginDocument{%
+% \setbox0=\hbox{%
+% \footnotesize\ttfamily
+% \global\expandafter\let\expandafter\fnttfont\font@name
+% %\expandglyphsinfont\fnttfont 30 500 1 autoexpand
+% }%
+% }
+
+\usepackage{yadoc}
+\newif\ifyadoc@short
+\newif\ifyadoc@long
+\yadocset{
+ name color=Definition,
+ before body=\parskip 0.3\baselineskip plus 2pt,
+ % after body=\medskip,
+ head/.style={
+ interior style={fill, left color=red!5,right color=red!5!black!2},
+ },
+ easy/.style={
+ name color=green!50!black,
+ head/.style={
+ interior style={fill, left color=green!5,right color=black!5},
+ },
+ },
+ keypath color opacity=30,
+ index encapsulator={`},
+ index annotation font=\color{gray},
+ def options/.append style={index page number format=colorhyperpage{red}},
+ aux options/.append style={index page number format=colorhyperpage{red}},
+ ref options/.append style={index page number format=hyperpage},
+ par/.style={parameters={#1}},
+ desc/.style={description={#1}},
+ keypath=/mmz,
+ xparse modifier item/.style={
+ index annotation=\texttt{xparse} modifier,
+ label prefix=xparse,
+ },
+ xparse type item/.style={
+ index annotation=\texttt{xparse} type,
+ label prefix=xparse,
+ },
+ script item/.style={
+ index annotation=script,
+ label prefix=script,
+ parameters prefix=\space,
+ },
+ key path item/.style={
+ index annotation=keypath,
+ label prefix:=keypath:/,
+ name prefix=/,
+ description=keypath,
+ },
+ option item/.style={
+ name prefix={\ifdefempty\yadoc@short@name{}{-\yadoc@short@name\,\Alt\,}--},
+ ref prefix={\protect\ifyadoc@short-\yadoc@short@name\protect\else--},
+ ref suffix={\protect\fi},
+ index prefix={--},
+ index suffix={\ifdefempty\yadoc@short@name{}{\Alt-\yadoc@short@name}},
+ parameters prefix=\ ,
+ label prefix:={\yadoc@of--},
+ index annotation=option of {\docref[into index=false,link color=gray]{\yadoc@of}},
+ },
+ short name/.store in=\yadoc@short@name,
+ short/.is if=yadoc@short,
+ long/.is if=yadoc@long,
+ conditional/.style={
+ parameters={\texttt{true}\Alt\texttt{false}},
+ /utils/exec={%
+ \appto\yadoc@description{default \texttt{true}, initially \texttt{#1}}%
+ },
+ },
+ conditional/.value required,
+ package item/.style={
+ index annotation=package,
+ label prefix=pkg,
+ description=package,
+ },
+ pkg/.style={
+ after/.style={index annotation/.append={\space of package \pkg{#1}}}
+ },
+ hook item/.style={
+ label prefix=hook,
+ index annotation=hook,
+ },
+ pdfvariable item/.style={
+ label prefix=pdfvar,
+ index annotation={\hologo{LuaTeX}'s \refcmd{pdfvariable} register},
+ },
+ pdfcmd item/.style={
+ label prefix=cmd,
+ name prefix={%
+ \textbackslash
+ \protect\ifyadoc@short
+ \protect\else
+ \protect\ifyadoc@long
+ pdf%
+ \protect\else
+ % todo: revert to the real original font rather than just say \rmfamily
+ \rmfamily(\ttfamily pdf\rmfamily)\ttfamily
+ \protect\fi
+ \protect\fi
+ },
+ index prefix=\textbackslash,
+ },
+}
+\def\colorhyperpage#1#2{%
+ \begingroup
+ \hypercolor{link}{#1}%
+ \hyperpage{#2}%
+ \endgroup
+}
+
+\patchcmd{\@setref}{??}{#3??}{}{}
+\patchcmd{\real@setref}{??}{#3??}{}{}
+
+\mmzset{
+ auto={tcb@manual@entry}{nomemoize},
+ auto={doc}{nomemoize},
+}
+
+\DeclareRobustCommand\refkey[2][]{\docref[#1]{key:#2}}
+\DeclareRobustCommand\refmmz[2][]{\docref[#1]{key:/mmz/#2}}
+\DeclareRobustCommand\refmmzauto[2][]{\docref[#1]{key:/mmz/auto/#2}}
+\DeclareRobustCommand\refmmzpath[2][]{\docref[#1]{key:/mmz/path/#2}}
+\DeclareRobustCommand\refcollargs[2][]{\docref[#1]{key:/collargs/#2}}
+\DeclareRobustCommand\refenv[2][]{\docref[#1]{env:#2}}
+\DeclareRobustCommand\refcmd[2][]{\docref[#1]{cmd:#2}}
+\DeclareRobustCommand\reffile[2][]{\docref[#1]{file:#2}}
+\DeclareRobustCommand\refkeypath[2][]{\docref[#1]{keypath:#2}}
+\DeclareRobustCommand\refpkg[2][]{\docref[#1]{pkg:#2}}
+\DeclareRobustCommand\refscript[2][]{\docref[#1]{script:#2}}
+
+\usepackage{xspace}
+\newcommand\dmmz{\docref{file:mmz}\xspace}
+
+\newcommand\hreftt[2]{\href{#1}{\texttt{#2}}}
+
+\ifcsname ifregion\endcsname
+ \ifregion{%
+ \AddToHook{begindocument/before}{%
+ \makeatletter
+ \InputIfFileExists{memoize.aux}{}{}%
+ \makeatother
+ }%
+ \AddToHook{enddocument}{%
+ \printindex
+ }%
+ }
+\fi
+
+\AddToHook{begindocument}{%
+ \robustify\hyperref
+ \robustify\hologo
+ \robustify\Alt
+}
+
+\newcommand\noprint[1]{\setbox0=\hbox{#1}}
+\usepackage{wrapfig}
+
+
+% \usepackage{caption}
+% \captionsetup{labelformat=empty}
+
+% Local Variables:
+% TeX-master: "memoize.tex"
+% TeX-engine: luatex
+% End:
diff --git a/macros/generic/memoize/doc/memoize-extract.1.md b/macros/generic/memoize/doc/memoize-extract.1.md
new file mode 100644
index 0000000000..434f2fea2f
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize-extract.1.md
@@ -0,0 +1,94 @@
+---
+title: memoize-extract
+section: 1
+header: User Manual
+footer: memoize-extract of Memoize v1.0.0
+date: October 10, 2023
+hyphenate: false
+---
+
+# NAME
+memoize-extract.pl, memoize-extract.py - Extract extern pages out of the PDF
+
+
+# SYNOPSIS
+**memoize-extract.pl** [*OPTIONS*] *document.mmz*
+
+**memoize-extract.py** [*OPTIONS*] *document.mmz*
+
+
+# DESCRIPTION
+
+**memoize-extract** is a script accompanying Memoize, a TeX package which
+allows the author to reuse the results of compilation-intensive code such as
+TikZ pictures.
+
+Memoize dumps the created externs (boxes containing the typeset material to be
+reused) onto their own pages in the produced PDF file. It is the job of
+**memoize-extract** to extract these extern pages into separate PDF files. At
+subsequent compilations, Memoize will include those extern files into the
+document, without compiling their source again.
+
+Memoize communicates with **memoize-extract** through file *document.mmz*. When
+*document.tex* is compiled to produce *document.pdf*, Memoize produces
+*document.mmz*, which records which pages in the produced document are extern
+pages and to which extern files they should be extracted. Therefore, after
+compiling *document.tex*, the externs should be extracted by
+**memoize-extract** *document.mmz*.
+
+*document.mmz* also records the expected width and height of each extern. In
+case of a mismatch, **memoize-extract** refuses to extract the page and removes
+the extern file if it already exist, and prints a warning message to the
+standard error. The script furthermore refuses to extract the page if a
+(c)c-memo associated to the extern does not exist, and to write to any file
+whose absolute path does not occur under the current directory or the directory
+set by TEXMFOUTPUT (in *texmf.cnf* or as an environment variable); TEXMFOUTPUT
+is also not allowed to point to the root directory, except on Windows, where it
+can only point to a drive root.
+
+The Perl (.pl) and the Python (.py) version of the script are functionally
+equivalent. The Perl script requires library
+[PDF::API2](https://metacpan.org/pod/PDF::API2), and the Python script requires
+library [pdfrw2](https://pypi.org/project/pdfrw2).
+
+# OPTIONS
+
+**-P, \--pdf** *filename.pdf*
+: The externs will be extracted from *filename.pdf*. By default,
+ they are extracted from *document.pdf*.
+
+**-p, \--prune**
+: Remove the extern pages from the PDF after extraction.
+
+**-k, \--keep**
+: Do not modify the *document.mmz* to mark the externs as extracted. By
+ default, they are commented out to prevent double extraction.
+
+**-f, \--force**
+: Extract the extern even if the size-check fails.
+
+**-l, \--log** *filename*
+: Log size mismatches to *filename* rather than to the standard error.
+
+**-w, \--warning-template** *string*
+: Wrap the size mismatch warning text into the given template: \\warningtext in
+ the template will be replaced by the warning text.
+
+**-q, \--quiet**
+: Don't describe what's happening.
+
+**-e, \--embedded**
+: Prefix all messages to the standard output with the script name.
+
+**-m, \--mkdir**
+: A paranoid *mkdir -p*. (No extraction occurs, *document.mmz* is interpreted as a directory name.)
+
+**-h, \--help**
+: Show help and exit.
+
+**-V, \--version**
+: Show the Memoize version number and exit.
+
+# SEE ALSO
+
+[Memoize manual](https://ctan.org/pkg/memoize), section 6.6.1.
diff --git a/macros/generic/memoize/doc/memoize.mst b/macros/generic/memoize/doc/memoize.mst
new file mode 100644
index 0000000000..68a11283a5
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize.mst
@@ -0,0 +1 @@
+encap '`'
diff --git a/macros/generic/memoize/doc/memoize.pdf b/macros/generic/memoize/doc/memoize.pdf
new file mode 100644
index 0000000000..5642f641b6
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize.pdf
Binary files differ
diff --git a/macros/generic/memoize/doc/memoize.tex b/macros/generic/memoize/doc/memoize.tex
new file mode 100644
index 0000000000..8bc647f0ba
--- /dev/null
+++ b/macros/generic/memoize/doc/memoize.tex
@@ -0,0 +1,9094 @@
+\documentclass[a4paper,11pt]{article}
+\usepackage[margin=2cm,top=1cm,bottom=1cm,nohead,includefoot]{geometry}
+
+\usepackage{nomemoize}
+\usepackage{memoize-doc}
+\mmzset{
+ % recompile,
+ % readonly,
+ % disable,
+ % inverse search=false,
+ % include context in ccmemo,
+ % direct ccmemo input,
+ % trace,
+}
+\def\exampledir{examples/}
+
+\title{\pkg[white]{Memoize}}
+\author{Sašo Živanović\\[2mm]
+ \emailsymbol~\url(mailto:){saso.zivanovic@guest.arnes.si}\\
+ \homepagesymbol~\url(http://){spj.ff.uni-lj.si/zivanovic}\\
+ \faGithub~\url(https://){github.com/sasozivanovic}}
+\datefrompackageversion{memoize}
+\preto\packagever{v}
+
+\hypersetup{
+ pdftitle={Memoize},
+ pdfauthor={Sašo Živanović},
+ pdfsubject={externalization},
+ pdfkeywords={LaTeX, externalization, memoization}
+}
+
+\usepackage{makeidx}
+\pdfsystem{makeindex -s memoize.mst \jobname.idx}
+\makeindex
+\usepackage[hangindent=1em,justific=raggedright,font=small]{idxlayout}
+\appto\indexfont{\def\pkgcolor{gray}}
+
+\AddToHook{begindocument}{% so that the region compilation takes these in
+ \docForeign{
+ scope={
+ after/.style={index annotation/.prefix={\hologo{LaTeX}\space}},
+ cmd={name=begin}, cmd={name=end},
+ cmd={name=label}, cmd={name=@currentlabel},
+ cmd={name=ref}, cmd={name=pageref},
+ cmd={name=index},
+ cmd={name=NewDocumentCommand}, cmd={name=GetDocumentCommandArgSpec},
+ env={name=verbatim},
+ cmd={name=ReadonlyShipoutCounter},
+ hook={name=begindocument},
+ cmd={name=usepackage},
+ },
+ scope={
+ before/.style={index annotation=\hologo{TeX} primitive},
+ cmd={name=shipout},
+ cmd={name=hbox}, cmd={name=vbox},
+ cmd={name=ignorespaces}, cmd={name=unskip},
+ cmd={name=errmessage},
+ cmd={name=catcode},
+ cmd={name=mag},
+ },
+ scope={
+ before/.style={index annotation=\hologo{eTeX} primitive},
+ cmd={name=scantokens},
+ cmd={name=currentgrouplevel},
+ },
+ scope={
+ before/.style={index annotation=\hologo{pdfTeX} primitive},
+ cmd={name=quitvmode},
+ },
+ scope={
+ before/.style={index annotation=\hologo{LuaTeX} primitive},
+ pdfcmd={name=savepos},
+ cmd={name=pdfvariable},
+ },
+ pdfvariable={name=compresslevel},
+ pdfvariable={name=horigin},
+ pdfvariable={name=vorigin},
+ scope={
+ after/.style={index annotation/.prefix={\hologo{ConTeXt}\space}},
+ cmd={name=realpageno},
+ },
+ pdfcmd={name=primitive, index annotation=\hologo{LuaTeX}/\hologo{XeTeX} primitive},
+ register={name=pdfmajorversion},
+ register={name=pdfminorversion},
+ scope={
+ after/.style={index annotation/.prefix={\hologo{plainTeX}\space}},
+ cmd={name=llap}, cmd={name=rlap},
+ },
+ scope={
+ pkg=forest,
+ env={name=forest},
+ cmd={name=Forest},
+ },
+ scope={
+ pkg=tikz, keypath=/tikz,
+ cmd={name=tikz},
+ env={name=tikzpicture},
+ key={name=remember picture},
+ key={name=overlay},
+ cmd={name=tikzexternalize},
+ cmd={name=pgfsys@getposition},
+ },
+ file={name=texmf.cnf},
+ env={name=tcblisting, pkg=tcolorbox},
+ cmd={name=vref, pkg=varioref},
+ cmd={name=cref, pkg=cleveref},
+ cmd={name=crefrange, pkg=cleveref},
+ xparse type={name=l, index annotation/.append={\ (up to begin-group)}},
+ xparse type={name=u, index annotation/.append={\ (until tokens)}},
+ xparse type={name=r, index annotation/.append={\ (required delimited)}},
+ xparse type={name=R, index annotation/.append={\ (required delimited with default)}},
+ xparse type={name=d, index annotation/.append={\ (optional delimited)}},
+ xparse type={name=D, index annotation/.append={\ (optional delimited with default)}},
+ xparse type={name=o, index annotation/.append={\ (standard optional)}},
+ xparse type={name=O, index annotation/.append={\ (standard optional with default)}},
+ xparse type={name=t, index annotation/.append={\ (optional token)}},
+ xparse type={name=s, index annotation/.append={\ (optional star)}},
+ xparse type={name=m, index annotation/.append={\ (mandatory)}},
+ xparse type={name=g, index annotation/.append={\ (optional group)}},
+ xparse type={name=G, index annotation/.append={\ (optional group with default)}},
+ xparse type={name=v, index annotation/.append={\ (verbatim)}},
+ xparse type={name=e, index annotation/.append={\ (embellishments)}},
+ xparse type={name=E, index annotation/.append={\ (embellishments with defaults)}},
+ xparse modifier={name=+, index annotation/.append={\ (long)}},
+ xparse modifier={name=!, index annotation/.append={\ (don't ignore spaces)}},
+ xparse modifier={name=>, index annotation/.append={\ (argument processor)}},
+ generic={name=shell-escape, name prefix=-, label prefix:=-,
+ index annotation=option of \hologo{TeX} binaries},
+ generic={name=enable-write18, name prefix=--, label prefix:=--,
+ index annotation=option of \hologo{TeX} binaries},
+ generic={name=TEXMFOUTPUT, index annotation={variable in
+ \reffile[into index=false]{texmf.cnf}}},
+ }%
+ \docindex{%
+ cmd={name=pdfprimitive, see={\refcmd[into index=false,short]{primitive}}},
+ cmd={name=pdfsavepos, see={\refcmd[into index=false,short]{savepos}}},
+ cmd={name=pdfhorigin, see={\docref[into index=false]{pdfvar:horigin}}},
+ cmd={name=pdfvorigin, see={\docref[into index=false]{pdfvar:vorigin}}},
+ cmd={name=pdfcompresslevel, see={\docref[into index=false]{pdfvar:compresslevel}}},
+ pdfvariable={name=majorversion, see={\docref[into index=false,long]{reg:pdfmajorversion}}},
+ pdfvariable={name=minorversion, see={\docref[into index=false,long]{reg:pdfminorversion}}},
+ }%
+}
+
+\begin{document}
+
+
+\maketitle
+\thispagestyle{empty}
+
+\begin{abstract}
+ Memoize is a package for externalization of graphics and memoization of
+ compilation results in general, allowing the author to reuse the results of
+ compilation-intensive code.
+ Memoize
+ \begin{enumerate*}[(i)]
+ \item induces very little overhead, as all externalized graphics is produced
+ in a single compilation. It features
+ \item automatic recompilation upon the change of code or user-adjustable
+ context, and
+ \item automatic externalization of \TikZ pictures and Forest trees, easily
+ extensible to other commands and environments. Furthermore, Memoize
+ \item supports cross-referencing, \TikZ overlays and Beamer,
+ \item works with all major engines and formats, and
+ \item is adaptable to any workflow.
+ \end{enumerate*}
+\end{abstract}
+
+\bigskip
+
+\ExampleName{titlepage}
+\makeexample{\examplename.pdf N=2} % N=2, because we show the .mmz file later
+\begingroup
+\tcbset{page box/.style={
+ box align=center,boxsep=2mm,top=0pt,bottom=0pt,left=0pt,right=0pt,
+ enhanced, remember as=#1,
+ }}%
+\begin{tcboxedraster}
+ [raster columns=1]
+ {title=The two steps of externalization of graphics in Memoize}
+ \tcbinputexample{
+ title=\tt doc.tex,
+ listing only,
+ remember as=tex,
+ }
+ \begin{tcolorbox}[example title=doc.pdf, no attachment, remember as=pdf1]
+ \includeexamplepdf[page box=extern1]{page=1,trim=1in 1in 1in 1in}\hfill
+ \includeexamplepdf[page box=extern2]{page=2,trim=1in 1in 1in 1in}\hfill
+ \includeexamplepdf[page box=extern3]{page=3,trim=1in 1in 1in 1in}\hfill
+ \includeexamplepdf[page box=docpage]{page=4}%
+ \end{tcolorbox}
+ \vspace{10mm}
+ \begin{tcboxedraster}[raster columns=3, raster column skip=1cm]{blankest}
+ \begin{tcolorbox}[example title=.pdf]\centering
+ \includeexamplepdf[page box=externfile1]{page=1,trim=1in 1in 1in 1in}\hfill
+ \end{tcolorbox}
+ \begin{tcolorbox}[example title=.pdf]\centering
+ \includeexamplepdf[page box=externfile2]{page=2,trim=1in 1in 1in 1in}\hfill
+ \end{tcolorbox}
+ \begin{tcolorbox}[example title=.pdf]\centering
+ \includeexamplepdf[page box=externfile3]{page=3,trim=1in 1in 1in 1in}\hfill
+ \end{tcolorbox}
+ \end{tcboxedraster}
+\end{tcboxedraster}
+
+\medskip
+
+\begin{tcolorbox}[title=Using the externalized graphics]
+ \begin{tcolorbox}[example title=doc.pdf,
+ halign=center, remember as=pdf2]
+ \tcbox[remember, enhanced]{\footnotesize
+ We all love Ti\emph{k}Zlings!
+ \def\mytikzling#1#2{%
+ \tcbox[blankest, baseline=1mm, remember as=used extern #1]
+ {\tikz[x=0.3cm,y=0.3cm]{#2;}}}%
+ \mytikzling1{\penguin} is a penguin,
+ \mytikzling2{\koala} is a koala, and
+ \mytikzling3{\owl} is an owl.
+ }
+ \end{tcolorbox}
+\end{tcolorbox}
+
+\begin{tikzpicture}[remember picture, overlay]
+ \draw[->, snake arrow, thick, red] (tex.west) to[out=-90-60, in=90+60] (pdf1.west);
+ \draw[->, snake arrow, thick, red] (tex.east) to[out=-90+19, in=90-19] (pdf2.east);
+ \draw[->, thick, red] (extern1.south) to[out=south, in=north] (externfile1);
+ \draw[->, thick, red] (extern2.south) to[out=south, out looseness=1.1, in=north, in looseness=0.9] (externfile2);
+ \draw[->, thick, red] (extern3.south) to[out=south, out looseness=0.7, in=north, in looseness=0.9] (externfile3);
+ \draw[->, thick,blue] (externfile1) to[out=south, in=north] ([yshift=0.8mm]used extern 1.north);
+ \draw[->, thick,blue] (externfile2) to[out=south, in=north] (used extern 2.north);
+ \draw[->, thick,blue] (externfile3) to[out=south, in=north] ([yshift=0.3mm]used extern 3.north);
+\end{tikzpicture}
+\endgroup
+
+\begin{tcolorbox}[colback=emphcolor, fontupper=\footnotesize]
+ This manual also documents packages Advice
+ ({\datefrompackageversion{advice}v\packagever}) and CollArgs
+ ({\datefrompackageversion{collargs}v\packagever}). These are auxiliary
+ packages which were developed alongside Memoize, but are distributed as
+ independent packages as they might be useful outside the context of Memoize,
+ as well. See sections~\ref{sec:advice} and \ref{sec:ref:advice} for Advice, and
+ sections~\ref{sec:collargs} and \ref{sec:ref:collargs} for CollArgs.
+\end{tcolorbox}
+
+
+
+\section*{Introduction}
+\label{sec:intro}
+
+\begin{tcolorbox}[
+ title={\introboxtitle{What} is externalization and why you might want it?},
+ ]
+ If you have ever worked on a long document full of \TikZ pictures and maybe
+ Forest trees, you have probably had some compilation-enforced coffee breaks
+ --- even on modern computers, compiling pictures, trees and such takes a lot
+ of time. And you might have wondered, why do I need to compile these
+ pictures over and over again? --- after all, I'm not changing them anymore!
+ Enter \emph{externalization}, a mechanism designed to deal precisely with
+ your issue, by saving the produced pictures into separate PDFs and including
+ those PDFs in subsequent compilations --- in no time at all!
+\end{tcolorbox}
+
+\begin{tcolorbox}[
+ title={\introboxtitle{Why} yet another externalization package?},
+ ]
+ \TikZ, the popular and all-powerful graphics language for \TeX, ships
+ including an externalization library (described in \PGFmanual{53}). \TikZ's
+ library does an excellent job, but with one caveat. Assume you're using it
+ for the first time (or after a clean-up) on that long document full of \TikZ
+ pictures and Forest trees. It will take ages to produce all the externalized
+ graphics. Why? Because to get you up to speed, your document has to be
+ compiled many many times --- once for each and every externalized picture.
+ Even with \TikZ's advanced mechanism for skipping the parts of the document
+ irrelevant for the picture at hand, the first externalization can be a
+ daunting task.
+\end{tcolorbox}
+
+\begin{tcolorbox}[
+ title={\introboxtitle{How} does Memoize save your time?},
+ ]
+ There is a reason why \TikZ uses an entire compilation cycle to produce a
+ single externalized picture: \TeX\ itself can only produce a single PDF per
+ compilation (at least at the moment). Memoize evades this limitation by
+ dumping the externalized pictures right in the middle of the document
+ (ouch!). More precisely, an externalized picture occurs in the PDF twice,
+ first on a special page of its own and then on a regular page, where you
+ intended it to be. The daring dump obviously necessitates a second step of
+ the procedure, when those special pages are \emph{extracted} into separate
+ PDFs, called \emph{externs}, which are then included into the document in
+ subsequent compilations.
+
+ This two-step procedure, illustrated on the cover page of this manual, is
+ very fast. The first step, which externalizes \emph{all} the pictures into
+ the document itself (the squiggly red arrow), takes virtually no more time
+ than a regular compilation. The time needed for the second step, extraction
+ (the normal red arrows), depends on the system setup, but it ranges from
+ little to almost none.
+\end{tcolorbox}
+
+\begin{tcolorbox}[
+ title={\introboxtitle{When} should I use Memoize?},
+ ]
+ In short, whenever you are writing a document containing lots of \TikZ
+ pictures, Forest trees, or other time-consuming constructs, and you are bored
+ waiting for the compilation to finish.
+
+ Using Memoize on a paper containing a single picture does not make much of a
+ difference. But with more complex documents, the speed-up can be immense.
+ For example, the compilation time of my 400-page book containing about 160
+ Forest trees was reduced by more than half, and the compilation time of a
+ 260-page Beamer presentation with a hundred complex dynamic trees went from
+ four minutes to a mere half minute!
+\end{tcolorbox}
+
+
+\begin{tcolorbox}[
+ title={\introboxtitle{How} much extra work does Memoize require?},
+ ]
+ In principle, none.
+
+ For one, while allowing for manual memoization of selected document chunks
+ (\S\ref{sec:tut:memoize}), Memoize features a system which automatically
+ triggers memoization at each invocation of selected commands and
+ environments. Out of the box, Memoize \emph{automemoizes} \TikZ
+ pictures\noprint{\refenv{tikzpicture}} and Forest
+ trees\noprint{\refenv{forest}}, but the author can easily submit (almost) any
+ command or environment to automemoization (\S\ref{sec:tut:automemoization}).
+ Memoize also does its best to automatically prevent memoization of code that
+ cannot be externalized, like \TikZ pictures with \refkey{/tikz/remember
+ picture}, and to abort memoization in case the memoized code yields any
+ errors.
+\end{tcolorbox}
+
+
+\begin{tcolorbox}[
+ title={\introboxtitle{Why} is Memoize not called Externalize?},
+ ]
+ Fundamentally, Memoize is about producing and utilizing \emph{memos} ---
+ pieces of \hologo{TeX} code replicating the effect of the compilation of a
+ document chunk in a computationally less intensive manner. Typically, each
+ memo has an associated extern, which is where the effect of
+ \emph{typesetting} is stored, but conceptually, memos come first. For
+ example, the extern is included back into the document by the memo, and a
+ memo may be associated with any number of externs, including zero.
+
+ Memos solve several externalization-related problems in a generic fashion,
+ allowing for a multitude of applications. For example, they store the
+ information about the associated externs, so that an extern can be integrated
+ back into the document as a box with the original orientation, width, height
+ and depth. They solve the problem of cross-referencing from and into the
+ memoized code by storing its \emph{context} (\S\ref{sec:cross-referencing})
+ and replicating any \cs{label}s which occur in it. They are also crucial for
+ externalizing pictures in Beamer frames overlay by overlay.
+
+ Incidentally, the term ``memoization'' is used with some programming
+ languages to refer to the process of remembering the result of the function,
+ along with the given arguments, so that on subsequent invocations of the
+ function with the same arguments, the result can be returned from memory
+ rather than recomputing it. I would say that, give or take the functions,
+ what Memoize does fits the bill.
+\end{tcolorbox}
+
+
+\begin{tcolorbox}[
+ title={\introboxtitle{How} can I make my command (auto)memoizable?},
+ ]
+ Any command which interacts with the rest of the document, like a command
+ which produces a float, must receive special treatment. Some issues can be
+ resolved from within Memoize. Other issues require a memoization-compatible
+ (re)implementation of the command. It is in the hope that package writers
+ will adapt their ``difficult'' commands to Memoize that this package offers a
+ documented interface to the memoization process, fully described in
+ sections~\ref{sec:tut:package}, \ref{sec:memoization-drivers}
+ and~\ref{sec:tut:automemoization-details}.
+
+ An advanced user might also want to know that Memoize ships with two
+ auxiliary packages, which form the base of Memoize's automemoization feature.
+ Package Advice implements a generic framework for extending the functionality
+ of selected commands and environments, while package CollArgs provides a
+ command which can determine the argument scope of any command whose argument
+ structure conforms to \pkg{xparse}'s argument specification.
+\end{tcolorbox}
+
+\begin{tcolorbox}[
+ title={\introboxtitle{What else} is out there?},
+ ]
+ Not long before submitting Memoize to CTAN, I became aware of another new
+ externalization package, \pkg{robust-externalize}, and it seems that the same
+ happened to the author of that package \Smiley, who found the
+ proof-of-concept version of Memoize, which was available
+ at \href{https://github.com/sasozivanovic/memoize}{GitHub} for a while.
+
+ The key idea behind \pkg{robust-externalize} seems to be to extract the code
+ submitted to externalization into separate files, and add the necessary
+ preamble. While a compilation from scratch takes more time than with Memoize
+ (but less than with \TikZ library), the approach allows for parallel
+ compilation of externs --- nice!
+\end{tcolorbox}
+
+\newpage
+\tableofcontents
+
+
+\section{Before you start}
+\label{sec:setup}
+
+\subsection{Installing the extern extraction software}
+\label{sec:install}
+
+Good news: using Memoize can be as easy as writing
+\EmphVerbatim{\usepackage{memoize}} in the preamble.
+
+Bad news: Memoize won't work out of the box. The culprit is the extern
+extraction --- the process which ships the externalized graphics from the main
+document into separate extern files; for details, see the title page
+illustration and the ``How'' box in the Introduction. For the extraction to
+work, you will probably have to install some additional software, and you might
+also have to allow your \hologo{TeX} to execute the extraction script. But
+there's a silver lining: once Memoize is set up, it is set up for good.
+
+\begin{tcolorbox}[title=What do I have to do?]
+
+ In principle, all you have to do for Memoize to work \emph{under the default
+ configuration} is install Perl libraries
+ \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} and
+ \hreftt{https://metacpan.org/pod/Path::Class}{Path::Class}; see the Perl
+ section below for the installation guideline.
+
+\end{tcolorbox}
+
+Consult section~\ref{sec:extraction} if you want to use an extraction method
+other than the default \refmmz{extract=perl}-based method or adapt Memoize to
+your particular workflow (for example, if you're compiling via a Makefile).
+
+If you installed Memoize through the package manager of your \hologo{TeX}
+distribution, your system should be already set up to allow the execution of
+Memoize's extraction scripts. If this is not the case, please contact either
+me or the maintainer of your distribution; until the issue is resolved, you
+have to either
+\begin{enumerate}[(a)]
+\item compile documents loading Memoize with command-line option
+ \docref{-shell-escape} (on \hologo{TeX}Live) or
+ \docref{--enable-write18} (on MiK\hologo{TeX}), or
+\item set up the restricted shell escape mode to allow for the execution of
+ \refscript{memoize-extract.pl}.\footnote{\label{fn:shell-escape-commands}On
+ \hologo{TeX}Live, execute \code{tlmgr conf texmf shell\_escape\_commands}
+ to get the list of currently allowed commands \meta{current}, then add the
+ script by executing \code{tlmgr conf texmf shell\_escape\_commands
+ \meta{current},memoize-extract.pl}. On MiK\hologo{TeX}, you get the
+ \meta{current} list by \code{initexmf
+ --show-config-value=[Core]AllowedShellCommands[]}, and add to it by
+ \code{initexmf
+ --set-config-value=[Core]AllowedShellCommands[]=\meta{current};memoize-extract.pl}.}
+\end{enumerate}
+
+Once you have set up your system, I advise you to follow the instructions in
+section~\ref{sec:tut:test} to test if the setup was successful.
+
+
+\begingroup
+\setlength\intextsep{0pt}
+
+\paragraph{Perl} If you're running GNU/Linux or macOS, Perl is most likely
+already installed on your system. On Windows, you might have to install it. I
+tested Memoize with Strawberry Perl, available
+at \url(https://){strawberryperl.com}; see \url(https://){www.perl.org} for
+other options.
+
+\begin{wrapfigure}[3]{r}{0.25\linewidth}
+ \raisebox{0.5mm}[\dimexpr\height-0.5mm][\depth]{%
+ \mmznext{no verbatim}
+ \begin{tcolorbox}[
+ % example title=Installing the required libraries in Perl,
+ % attach shifted boxed title to top right,
+ % top=2.5mm,
+ fontupper=\small,
+ left=2mm,
+ force nobeforeafter,
+ ]
+ |cpan PDF::API2|
+
+ |cpan Path::Class|
+ \end{tcolorbox}%
+ }%
+\end{wrapfigure}
+Once Perl is installed on your system, you will need to install two Perl
+libraries as well: the PDF processing library
+\hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2}, and the cross-platform
+path specification manipulation library
+\hreftt{https://metacpan.org/pod/Path::Class}{Path::Class}. On some GNU/Linux
+distributions, these libraries are included as packages --- just use your
+package manager to install them. Otherwise, install them from
+\hreftt{https://www.cpan.org}{CPAN} using
+\hreftt{https://metacpan.org/pod/CPAN}{cpan} tool, as shown in the box.
+
+
+\paragraph{Python} Installing (Python and) the required Python library is only
+necessary if you decide to use the Python-based extraction script; see
+section~\ref{sec:extraction}.
+
+If you're running GNU/Linux, install Python using your package manager.
+Otherwise, download the installer from \url(https://){www.python.org}. You can
+install Python even if you don't have administrator privileges: simply uncheck
+the ``Install launcher for all users'' when running the installer.
+
+\begin{wrapfigure}[2]{r}{0.25\linewidth}
+ \raisebox{0.2mm}[\dimexpr\height-0.2mm][\depth]{%
+ \mmznext{no verbatim}
+ \begin{tcolorbox}[
+ % example title=Installing the required library in Python,
+ % attach shifted boxed title to top right,
+ % top=2.5mm,
+ fontupper=\small,
+ left=2mm,
+ nobeforeafter,
+ ]
+ |pip install pdfrw2|
+ \end{tcolorbox}%
+ }%
+\end{wrapfigure}
+
+Once Python is installed on your system, you will also need to install the
+|pdfrw2| library (or its predecessor, |pdfrw|, which will work just as well).
+Some GNU/Linux distributions offer this library as a package; if this is not
+the case, and on other operating systems, install it
+from \href{https://pypi.org}{The Python Package Index}
+using \href{https://pip.pypa.io}{pip} tool (if you
+run \href{https://pip.pypa.io}{pip} as a superuser, it will install the library
+system-wide, otherwise locally), as shown in the box.
+
+\endgroup % \intextsep
+
+
+\subsection{The configuration commands}
+\label{sec:mmzset}
+
+Memoize can be configured using command \Emph{\refcmd{mmzset}\marg{keylist}}
+(and friends). The \meta{keylist} argument is a comma-separated list of
+configuration settings, each setting having the form \meta{key}|=|\meta{value},
+or sometimes just \meta{key}. The \meta{keylist} argument is processed by package
+\pkg{pgfkeys} (see \PGFmanual{88}), so you can use all the bells and whistles
+of that fantastic PGF utility (like easily defining your own styles).
+
+Here's some examples of \refcmd{mmzset}. For one, to whet your appetite to learn
+about the various keys in the \refkeypath{/mmz} path, but more importantly now, to show
+you that white-space is irrelevant in the \meta{keylist} argument, so you can
+format the keylist as you wish --- as long as it does not contain an empty
+line.\footnote{I like to add a comma after the final key as well, as shown in
+ the bottom left example, because if I don't, I often forget to insert it when
+ I add more keys.}
+
+\begin{tcbraster}[raster columns=4, raster valign=bottom]
+ \begin{tcboxedraster}[raster columns=1]{blankest, raster multicolumn=3, valign=bottom}
+ \begin{tcblisting}{listing only}
+~\mmzset~{memo dir,recompile,memoize=circuitikz}
+ \end{tcblisting}
+ \begin{tcblisting}{listing only}
+~\mmzset~{memo dir, recompile, memoize=circuitikz}
+ \end{tcblisting}
+ \end{tcboxedraster}
+ \begin{tcblisting}{listing only}
+~\mmzset~{
+ memo dir,
+ recompile,
+ padding=2in}
+ \end{tcblisting}
+\end{tcbraster}\par
+\begin{tcbraster}[raster columns=4, raster valign=top]
+ \begin{tcblisting}{listing only, raster multicolumn=2}
+~\mmzset~{
+ memo dir, readonly,
+ memoize=\qrcode{om},
+ deactivate=\label,
+ disable,
+}
+ \end{tcblisting}
+ \begin{tcblisting}{listing only}
+~\mmzset~{
+ memo dir,
+ recompile,
+ % comment
+ padding=2in
+}
+ \end{tcblisting}
+ \begin{tcblisting}{listing only, bad}
+~\mmzset~{
+ memo dir,
+ recompile,
+
+ padding=2in
+}
+ \end{tcblisting}
+\end{tcbraster}
+
+Command \refcmd{mmzset} can be used any time after loading the package. It is
+very common in the preamble, but also useful in the document body, where its
+effect is local to the \hologo{TeX} group.\footnote{Any keys with a non-local
+ effect are explicitly marked as such in the reference section.} For example,
+you can use the idiom on the left below to force recompilation of a single
+Forest tree somewhere in the middle of the document (in the code listings
+below, highlighting marks the resulting scope of the \refmmz{recompile}
+directive). However, as applying some setting to a single piece of
+automatically memoized code is common, Memoize provides a special command for
+the occasion: the keys given as the argument of \Emph{\refcmd{mmznext}} will be
+applied only at the next instance of automemoization, overriding any keys set
+by \refcmd{mmzset} in case of a conflict. If the command is given more than
+once, only the final invocation takes effect.
+
+\begin{tcbraster}[raster columns=2, raster equal height=rows, raster force size=false]
+\begin{tcblisting}{listing only, mark region={3}{6}}
+~{~
+ ~\mmzset~{recompile}
+ \begin{forest}
+ [VP[V][DP]]
+ \end{forest}
+ % ...
+~}~
+\end{tcblisting}
+\begin{tcblisting}{listing only, add to width=-1em, mark region={3}{5}}
+% ...
+~\mmznext~{recompile}
+\begin{forest}
+ [VP[V][DP]]
+\end{forest}
+% ...
+
+\end{tcblisting}
+\end{tcbraster}
+
+I like to follow |\usepackage{memoize}| by \refcmd{mmzset}, but if you prefer, you
+can also provide the document-wide configuration as \Emph{package options.}
+Note, however, that \hologo{LaTeX} removes spaces from package
+options, so keys such as \refmmz{memo dir} won't work. That said, the following are
+equivalent --- both will force re-externalization of all the externs in the
+document.
+
+\begin{tcbraster}[raster columns=2, raster equal height=rows]
+ \begin{tcblisting}{listing only}
+\usepackage{memoize}
+\mmzset{recompile}
+ \end{tcblisting}
+ \begin{tcblisting}{listing only}
+\usepackage[recompile]{memoize}
+ \end{tcblisting}
+\end{tcbraster}
+
+
+\subsection{The configuration file}
+\label{sec:memoize.cfg}
+
+Memoize allows you to configure settings which apply to more than just one
+document. It does that by attempting to load file \Emph{\reffile{memoize.cfg}}
+just before executing package options. Given how \hologo{TeX} searches for
+files, the location of this file determines whether it applies system-wide,
+user-wide or directory-wide. The directory-wide location is clearly the
+directory itself. The user-wide and system-wide location depend on the
+\hologo{TeX} distribution and which format(s) you want to use
+\reffile{memoize.cfg} with:\footnote{The |memoize| subfolder is not
+ obligatory.}
+
+\begin{center}
+ \meta{the relevant texmf tree root}|/tex/|\meta{format}|/memoize/memoize.cfg|
+\end{center}
+
+You can say |generic| for \meta{format} if you want the configuration file to
+be accessible by all formats, otherwise \meta{format} should be one of the
+formats supported by Memoize: |plain|, |latex| or |context|. The texmf root
+directory depends on the distribution, here's how to figure out what it is:
+
+\begin{tcboxedraster}
+ [raster columns=1, raster valign=top, raster force size=false]
+ {title=The roots of TEXMF trees}
+\begin{tcolorbox}[title={\hologo{TeX} Live\hfill\url[white](https://){tug.org/texlive}}]
+ \begin{description}[itemsep=0pt]
+ \item[user-wide]
+ |tlmgr conf texmf TEXMFHOME|
+ or |kpsewhich -var-value TEXMFHOME|\\
+ the default (on Linux): |/home/|\meta{username}|/texmf|
+ \item[system-wide]
+ |tlmgr conf texmf TEXMFLOCAL|
+ or |kpsewhich -var-value TEXMFLOCAL|\\
+ the default (on Linux): |/usr/local/texlive/texmf-local|
+ \end{description}
+
+ \smallskip
+ Don't forget to run |texhash| or |mktexlsr| after creating \reffile{memoize.cfg}.
+\end{tcolorbox}
+\begin{tcolorbox}[title={MiK\hologo{TeX}\hfill\url[white](https://){miktex.org}}, before upper={\parskip0.3\baselineskip plus 2pt\relax},]
+ Open the MiK\hologo{TeX} Console, select the ``Settings'' page and then the
+ ``Directories'' tab.
+
+ If there is a folder marked with the ``Generic'' purpose with attribute
+ ``User'' (for a user-wide \reffile{memoize.cfg}) or ``Common'' (for a system-wide
+ \reffile{memoize.cfg}), that's the folder you are looking for. Otherwise, create a
+ folder following MiK\hologo{TeX}'s instructions and add it to the list.
+
+ Don't forget to click ``Refresh file name database'' (in the ``Tools'' menu
+ of the MiK\hologo{TeX} Console) after creating \reffile{memoize.cfg}.
+\end{tcolorbox}
+\end{tcboxedraster}
+
+Note that a directory config file will override the user config, and the user
+config will in turn override the system-wide one. This should not concern you
+too much, because you will probably only want to use the user-wide config
+anyway,\cprotect\footnote{If you want to have a directory-wide configuration
+ based on (rather than overriding) the user-wide configuration, your could
+ write down the real user-wide config in, say, |memoize.user.cfg| (located
+ user-wide), and then |\input| this file by both the user-wide and the
+ directory-wide \reffile{memoize.cfg}. Of course, the same logic can be used to base
+ a user-wide config on the system-wide one.} which might look something like
+this:
+
+\ExampleName{memoize}
+\makeexample{\examplename.cfg.c1}
+\tcbinputexample[.cfg]{listing only}
+
+I recommend including \refmmz{memo dir} in your \reffile{memoize.cfg},
+as shown in the first line. It reduces the clutter in the document
+directories; see section~\ref{sec:tut:memodir} for details.
+
+The \refmmz{extract} line concludes the story on ``permanently'' selecting the
+extraction method, started in chapter~\ref{sec:setup}. As the final note,
+observe that key \refmmz{extract} only makes sense as a package option or as a
+\refcmd{mmzset} key in \reffile{memoize.cfg}. It will have no effect as a
+\refcmd{mmzset} key in the document, because the extraction happens while the
+package is loaded.
+
+
+
+\section{Your first memoized documents}
+\label{sec:tut}
+
+\subsection{Let's see if it works!}
+\label{sec:tut:test}
+
+\ExampleName{test}
+\noprint{\refcmd{tikz}\refenv{tikzpicture}\refenv{forest}}%
+
+Take example file \texttt{\examplename.tex},\footnote{Where can you find
+ the example files? For one, they are integrated into this manual, so if your
+ PDF viewer supports attachments, you can simply click on the paperclip icon
+ on the top right of the example box (even if you're offline). Otherwise,
+ visit the |examples| subdirectory of wherever you found this document
+ \Smiley. Online, the Memoize documentation can be found at CTAN:
+ \url{https://ctan.org/pkg/memoize}; and if your \hologo{TeX} installation
+ includes the documentation, you should also find it in directory \meta{the
+ root of your \hologo{TeX} installation}|/doc/generic/memoize|.
+
+ Incidentally, while we present a full example document in this section, many
+ code listings will only present the parts of the file relevant for the
+ discussion, for brevity. The example \emph{files}, however, will remain
+ full, compilable documents, including the document preamble etc.} or some
+simple document containing a \TikZ picture or a Forest tree, add
+\EmphVerbatim{\usepackage{memoize}} to the preamble,\footnote{Memoize likes to
+ be loaded early. If you get the error \texttt{Extern extraction from
+ document \meta{jobname}.pdf was unsuccessful}, move
+ \cs{usepackage}\bracestt{memoize} up the preamble; see
+ section~\ref{sec:loading-order} for details.} and compile it twice.
+
+\begin{itemize}
+\item The first compilation of the example should produce a three-page PDF.
+ The first two pages are the \emph{extern pages} holding the externalized
+ graphics, while the final page is the (sole page of the) real document. Note
+ that you can see each extern twice: first on a page of its own, and then
+ wherever it belongs to in the real document.
+\item At the second compilation, the extern pages should have disappeared from
+ the PDF, meaning they were successfully extracted into extern files, which
+ are now embedded into the main document.
+\end{itemize}
+
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside,
+ comment={\centering
+ \includeexamplepdf[extern page,left=2mm,right=2mm]{page=1,trim=1in 1in 1in 1in}\quad
+ \includeexamplepdf[extern page,left=2mm,right=2mm]{page=2,trim=1in 1in 1in 1in}\\[2ex]
+ \includeexamplepdf[document page]{page=3}
+ },
+}
+
+You might want to play with this example a bit now.
+For example, if you reverse the order of the \TikZ picture and the Forest
+tree, you should notice that the externs don't get recompiled. You won't see
+any extern pages again until you change the actual code of the picture or the
+tree --- or until you add some other picture or tree, of course.
+
+If you \emph{don't} want to automatically memoize \TikZ pictures and/or Forest
+trees, you can switch off their \emph{automemoization} using key
+\Emph{\refmmz{deactivate}}. This key takes a list of command and environment
+names. As you can see below, the command and the environment must be
+deactivated separately.
+
+\begin{tcblisting}{listing only}
+\mmzset{
+ deactivate={\tikz, tikzpicture}, % deactivate automemoization of all TikZ pictures
+ deactivate=\tikz, % deactivate only the command
+ deactivate=tikzpicture, % deactivate only the environment
+}
+\end{tcblisting}
+
+
+\subsection{Memoizing by hand}
+\label{sec:tut:memoize}
+
+In the previous section, we have compiled our very first document which used
+Memoize. In that document, we only had to load the package, as Memoize knows
+how to externalize \TikZ pictures and Forest trees without any help from the
+author. But what if you want to externalize some other code? The manual way of
+doing this is by surrounding the code by a \Emph{\refenv{memoize}} environment,
+or by making it the argument of the \Emph{\refcmd{mmz}} command. The only
+difference between the two is that the environment, but not the command,
+ignores any spaces surrounding the given code.
+
+\ExampleName{manual}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.528,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\hfill
+ \includeexamplepdf[extern page]{page=2,trim=1in 1in 1in 1in}
+ },
+}
+
+Both the \refenv{memoize} environment and the \refcmd{mmz} command take a
+configuration keylist as the optional argument, so their full syntax is
+\cs{begin}\marg{\refenv{memoize}}\oarg{keylist}\meta{code to be
+ externalized}\cs{end}\marg{\refenv{memoize}} and and
+\refcmd{mmz}\oarg{keylist}\marg{code to be externalized}. The keys given in
+this optional argument take precedence over the keys set by \refcmd{mmzset}.
+Note that \refcmd{mmznext} does not apply to manual memoization.
+
+Manual memoization is great for one-shot memoizations, but you can use it
+within your own macros as well. For example, assume that you don't want to
+externalize \TikZ pictures in general (so you have \refmmz{deactivate}d
+automemoization of the \cs{tikz} command, as explained at the end of
+section~\ref{sec:tut:test}), but that you want to easily memoize selected
+pictures. You could define a memoized variant of the \cs{tikz} command, as shown
+below (and similary for the environment). (Note the |%| comment characters in
+the definition of |\mmztikz|. The definition was intentionally broken into
+several lines to remind you that the spaces around the argument of \refcmd{mmz}
+matter.)
+
+\ExampleName{mmztikz}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}
+ \quad
+ \includeexamplepdf[document page]{page=2}
+ },
+}
+
+\clearpage
+\subsection{Memoizing automatically}
+\label{sec:tut:automemoization}
+
+Out of the box, Memoize automatically externalizes \TikZ pictures and Forest
+trees. Let us see how other commands and environments can be submitted to this
+\emph{automemoization} process.
+
+We start with the simpler case of environments (fortunately, externalizing
+environments also makes sense more often than externalizing commands). You can
+submit an environment to automemoization by writing
+\EmphTT{\refmmz{auto}=\marg{environment name}\braces{\refmmzauto{memoize}}} (as
+a key in \refcmd{mmzset}). The natural (but not the only possible) location
+for this instruction is the preamble. Below, we automemoize environment
+\env{circuitikz} of package \pkg{circuitikz}, used for drawing electronic
+circuits.\footnote{In section~\ref{sec:tut:test}, we learned that
+ automemoization can be switched off using key \refmmz{deactivate}. Memoize
+ also offers key \refmmz{activate}, but you probably won't have to use it, as
+ an \refmmz{auto} declaration automatically activates the submitted command.}
+
+\ExampleName{automemoize-environment}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.6,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in,scale=0.8}
+ },
+}
+
+Commands are a bit harder to automemoize, because Memoize cannot possibly know
+how far the arguments of a command extend (in contrast, the end of an
+environment is clearly marked). With commands, we must inform Memoize about
+their argument structure, which we achieve using key \refmmzauto{args} in the
+second argument of key \refmmz{auto}:
+\EmphTT{\refmmz{auto}=\meta{command}\braces{\refmmzauto{memoize},
+ \refmmzauto{args}=\marg{argument specification}}}. We can only leave out
+\refmmzauto{args} if the command was defined by \refcmd{NewDocumentCommand} or
+similar; in this case, Memoize can retrieve the argument specification on its
+own.
+
+And how does the \meta{argument specification} look like? It is a sequence of
+letters, each letter determining an argument type. Memoize recognizes the same
+argument types and their letters as package \pkg{xparse} (which defines
+\refcmd{NewDocumentCommand} and friends), so you should look at (section 1 of)
+the documentation of that package for details, if and when you need them.
+Here, we focus on the two most commonly used types, \docref{xparse:m} and \docref{xparse:o}, and add the
+optional star for good measure:
+\begin{center}
+ \begin{tabular}{lll}
+ \toprule
+ letter & argument type & example\\
+ \midrule
+ \docref{xparse:m} & mandatory argument \\
+ & --- either surrounded with braces & |\foo{arg}|\\
+ & --- or a single token & |\foo a|\\
+ \docref{xparse:o} & optional argument, surrounded with brackets & |\foo[arg]|\\
+ \docref{xparse:s} & optional star & |\foo*|\\
+ \bottomrule
+ \end{tabular}
+\end{center}
+
+Below, we write |args=om| because command \cs{qrcode} (of package \pkg{qrcode})
+takes two arguments: a bracketed optional argument, followed by a mandatory
+argument (in braces).
+
+\ExampleName{automemoize-command}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.603, top=0mm,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\quad
+ \includeexamplepdf[extern page]{page=2,trim=1in 1in 1in 1in}
+ },
+}
+
+This should get you started with automemoization. We'll provide some further
+basic information in sections~\ref{sec:tut:working-on-a-picture}
+and~\ref{sec:tut:verbatim} of the tutorial, but only package writers will
+probably ever need the gory details from
+section~\ref{sec:tut:automemoization-details}. It is my sincere hope that they
+will support Memoize in their packages, where necessary, so that you don't even
+have to write the \refmmz{auto} declarations, but there is one thing you should
+know if you encounter a package supporting Memoize: you should load it
+\emph{after} Memoize!
+
+
+
+\subsection{Working on a picture}
+\label{sec:tut:working-on-a-picture}
+
+
+Memoize automatically recompiles a picture when the code producing the picture
+changes. However, sometimes we can modify a picture without changing its code,
+like when we modify the definition of a command used in the code. In the
+example below, a predefined style |emph| is applied to the node, producing a
+node with a red background. Let's say we compile the document (with
+memoization) and then change this style to set the yellow background.
+Curiously, the node will remain red.
+
+\ExampleName{recompile}
+\makeexample{\examplename.pdf N=3}
+\begin{tcbraster}[raster columns=2, raster valign=top, raster column skip=4mm]
+ \tcbinputexample{
+ after title pre={\ (version~1)},
+ comment={\centering
+ \includeexamplepdf[document page]{page=2}
+ },
+ }
+ \tcbinputexample[.tex][.c2]{
+ no attachment,
+ after title pre={\ (version~2)},
+ comment={\centering
+ \includeexamplepdf[document page]{page=1}
+ },
+ }
+\end{tcbraster}
+
+The curious thing happens (or rather, doesn't happen) because Memoize doesn't
+keep track of how commands and styles are defined; it just uses the extern file
+it created when the old style was in effect. To get a yellow node, we must ask
+Memoize to reexternalize the picture. The simplest way to do that is by using
+the \Emph{\refmmz{recompile}} key; below, we write
+\refcmd{mmznext}\bracestt{\refmmz{recompile}} just before the picture and
+compile the document again (remember from section~\ref{sec:mmzset} that
+whatever keys we provide through \refcmd{mmznext} only apply to the instance of
+automemoization). After the compilation, we may (and should) remove the
+\refmmz{recompile} directive (otherwise, Memoize will produce the extern page
+again and again).
+
+\tcbinputexample[.tex][.c3]{
+ no attachment,
+ after title pre={\ (version~3)},
+ sidebyside, lefthand ratio=0.6,
+ comment={\centering
+ \includeexamplepdf[document page]{page=2}
+ },
+}
+
+It is also common to put (again, for the space of a single compilation)
+\refcmd{mmzset}\braces{\refmmz{recompile}} in the preamble, or to use
+\refmmz{recompile} as the package option. Either will remake all the
+externalized graphics in the document, so you can be sure all of them use the
+latest version of your macros and styles.
+
+We'll revisit the issue of memoized code depending on macros and styles defined
+elsewhere in section~\ref{sec:tut:redefinitions}. In this section, we will
+learn how the issue can be \emph{avoided}, at least to some extent. One idea
+is to turn off memoization for the picture(s) we are currently working on;
+another idea is to let Memoize know which definitions the picture relies on.
+The simplest way to achieve the former is by using key \Emph{\refmmz{disable}};
+by putting it into a \hologo{TeX} group, we can localize its effect to the
+selected pictures.
+
+\ExampleName{disable}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside,
+ lefthand ratio=0.6,
+ top=0mm, % manual top, bottoms and \\[...] to fit the page
+ comment={\centering
+ \includeexamplepdf[extern page,bottom=0.8mm]{page=1,trim=1in 1in 1in 1in}\\[0.5mm]
+ \includeexamplepdf[extern page,bottom=0.8mm]{page=2,trim=1in 1in 1in 1in}\\[0.5mm]
+ \includeexamplepdf[document page,bottom=0.8mm]{page=3}
+ },
+}
+
+\begin{tcolorbox}[warning]
+ As you can imagine, key \refmmz{disable} is complemented by \refmmz{enable},
+ but it is perhaps worth mentioning a problem that can arise if you disable
+ memoization for a part of your document by enclosing it in a pair of
+ \refcmd{mmzset}\braces{\refmmz{disable}} and
+ \refcmd{mmzset}\braces{\refmmz{enable}}. Yes, it might work at the moment,
+ but say you later (e.g.\ when you are preparing the final version of the
+ document) decide to disable memoization for the entire document, and say you
+ try to do this by writing \refcmd{mmzset}\braces{\refmmz{disable}} in the
+ preamble. As shown below on the left, you're in for a surprise: memoization
+ will still be enabled in the part of the document following
+ \refcmd{mmzset}\braces{\refmmz{enable}}! The solution is to always disable
+ memoization for a part of the document by using
+ \refcmd{mmzset}\braces{\refmmz{disable}} in a \hologo{TeX} group (i.e.\ the
+ braces), as shown on the right. (In the examples below, the shaded areas
+ mark the parts of the document where memoization is \emph{disabled}.)
+\end{tcolorbox}
+
+\makeexample{disable-bad.tex.c1}
+\makeexample{disable-good.tex.c1}
+\makeexample{disable-nomemoize.tex.c1}
+\makeexample{disable-nommz.tex.c1}
+\makeexample{disable-auto-cmd.tex.c1}
+\makeexample{disable-auto-env.tex.c1}
+
+\begin{tcbraster}[raster columns=2, raster equal height=rows]
+ \tcbinputexample(disable-bad){
+ listing and comment, bad, mark region={4}{7},
+ comment={\raggedright The upper \refcmd{mmzset}\braces{\refmmz{disable}}
+ does not have the intended effect,
+ i.e.\ it doesn't apply to the whole document!}}
+ \tcbinputexample(disable-good){
+ listing and comment, mark region={4}{10},
+ comment={\raggedright The upper \refcmd{mmzset}\braces{\refmmz{disable}} applies
+ to the entire document, as expected.}}
+\end{tcbraster}
+
+In fact, it might be better to disable memoization using environment
+\Emph{\refenv{nomemoize}} or macro \Emph{\refcmd{nommz}}. I also like these
+commands because it is easy to add and remove prefix |no| to switch manual
+memoization (triggered using environment \refenv{memoize} or macro
+\refcmd{mmz}) off and on.
+
+\begin{tcbraster}[raster columns=2, raster equal height=rows]
+ \tcbinputexample(disable-nomemoize){listing and comment, mark region={2}{2},
+ comment=\raggedright Disable using the dedicated environment.}
+ \tcbinputexample(disable-nommz){listing and comment, mark region={2}{2},
+ comment=\raggedright Disable using the dedicated command.}
+\end{tcbraster}
+
+It is also possible to disable memoization for all occurrences of a selected
+command or environment. In fact, we're already familiar with the procedure
+from section \ref{sec:tut:automemoization}, where we used key
+\refmmzauto{memoize} inside the second argument of \refmmz{auto} to
+automatically memoize all instances of the command or environment given as the
+first argument. All we have to do to auto-disable rather than auto-memoize, is
+substitute \refmmzauto{nomemoize} for \refmmzauto{memoize}. Note that this
+prevents memoization of not only the given command or environment, but also of
+any (manual or automatic) memoization which would otherwise occur during its
+execution; for example, if |\foo| executes \cs{tikz} under the hood,
+autodisabling |\foo| prevents memoization of the inner \cs{tikz}, even though
+that command is normally automemoized.
+
+\begin{tcbraster}[raster columns=2, raster equal height=rows]
+ \tcbinputexample(disable-auto-cmd){
+ listing and comment,
+ mark region={3}{3}, mark region={5}{5},
+ comment=\raggedright Autodisable within a command.,
+ }
+ \tcbinputexample(disable-auto-env){
+ listing and comment,
+ mark region={3}{5},
+ comment=\raggedright Autodisable within an environment.,
+ }
+\end{tcbraster}
+
+All that said, Memoize actually offers a neater way to switch off the
+externalization for the picture I'm currently working on. The
+\Emph{\refmmz{readonly}} key instructs Memoize to use whatever externs it had
+already produced (thereby reducing the document compilation time), but to
+abstain from producing any new externs. In effect, the stuff we are currently
+working on does not undergo memoization and therefore does not produce the
+clutter which can potentially lead to trouble described in the \refmmz{recompile}
+examples above.
+
+What I like to do is load the package using |\usepackage[readonly]{memoize}|,
+work on stuff, and once I'm happy with the most recent pictures, remove
+\refmmz{readonly} from the package options for one compilation.
+
+\ExampleName{readonly}
+\makeexample{\examplename.pdf N=2}
+
+\begin{tcbraster}[raster columns=5, raster valign=top, raster column skip=4mm]
+ \tcbinputexample{
+ raster multicolumn=2,
+ after title pre={\ (work in progress)},
+ comment={\centering
+ \includeexamplepdf[document page]{page=1}
+ },
+ }
+ \tcbinputexample[.tex][.c2]{
+ raster multicolumn=3,
+ no attachment,
+ title={\tt readonly.tex} (the final version),
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\quad
+ \includeexamplepdf[document page]{page=2}
+ },
+ }
+\end{tcbraster}
+
+We're now ready to tackle a completely different way of avoiding the issue, by
+informing Memoize which definitions the externalized picture depends on. We do
+this by appending these definitions to \emph{context} --- when the context of a
+picture changes, Memoize recompiles the picture, same as if the code of the
+picture itself was changed. (We will talk about context in more detail in
+section~\ref{sec:cross-referencing}.)
+
+A command can be added as a dependency using key \Emph{\refmmz{meaning to
+ context}}. Below, we make the following externalized picture depend on the
+definition of macro \cs{answer}; changing this definition will result in the
+recompilation of the extern. In general, \refmmz{meaning to context} accepts a
+comma-separated list of command and environment names, e.g.\
+\code{\refmmz{meaning to context}=\bracestt{\cs{foo},bar}} (note the braces).
+
+Memoize offers several variants of \refmmz{meaning to context}, applicable to
+various types of commands. For example, the easiest way of making the picture
+depend on the definition of a \pkg{pgfkeys} style is to use handler
+\Emph{\refkey{/handlers/.meaning to context}} --- note the dot in the name, and
+observe that \code{emph/.meaning to context} below is executed within
+\cs{tikzset}, not \refcmd{mmzset}; see \PGFmanual{87} to learn about key
+handlers.
+
+\ExampleName{meaning-to-context}
+\makeexample{\examplename.pdf N=2}
+\tcbinputexample{
+ after title pre={\ (version~1)},
+ sidebyside,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}
+ },
+}
+
+\tcbinputexample[.tex][.c2]{
+ after title pre={\ (version~2)},
+ sidebyside,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}
+ },
+ no attachment,
+}
+
+All variants of \refmmz{meaning to context} (see reference
+section~\ref{sec:ref:memoization:basic} for the full list) may be used within
+the externalized picture itself, e.g.\ \code{\cs{node}[emph,
+ emph/\refkey{/handlers/.meaning to context}]\bracestt{...}} is perfectly
+valid --- and also handy when you want to limit the effect of the handler to a
+single picture, as \refkey{/handlers/.meaning to context} cannot be used within
+\refcmd{mmznext}.
+
+
+
+\subsection{Keeping a clean house}
+\label{sec:tut:memodir}
+
+Memoize produces lots of auxiliary files. For each piece of memoized code, it
+produces two \emph{memo} files (we will learn more about these in
+section~\ref{sec:memos}), which will be joined by the extern PDF upon the next
+compilation.\footnote{If you're using the \hologo{TeX}-based extraction, each
+ extern (|.pdf|) is also accompanied by a log file (|.log|) produced during
+ the compilation that extracted the extern.} You can recognize these files
+easily: their names start with the name of your document and include one or two
+long hexadecimal numbers.
+
+\ExampleName{dirty-house}
+\makeexample{\examplename.pdf}
+{
+ \relaxmmzcommands
+ \edef\marshal{%
+ \noexpand\def\noexpand\mynewextern.//\examplename
+ }\marshal.#1-#2.pdf\relax{%
+ \forestset{
+ append={[\examplename.#1.memo\vphantom{p},pointcolor]},
+ append={[\examplename.#1-#2.memo\vphantom{p},pointcolor]},
+ append={[\examplename.#1-#2.pdf,pointcolor]},
+ }%
+ }
+ \tcbinputexample{
+ comment={%
+ \begin{tcolorbox}[reset, left=2mm, bottom=0mm,
+ my boxed title=the folder contents (after two compilations),
+ attach shifted boxed title to top right,
+ ]
+ \begin{forest}
+ before typesetting nodes={for tree={
+ font=\scriptsize\tt, grow'=0, folder, s sep=0}},
+ [\meta{the document folder}, inner xsep=0,
+ TeX={%
+ \def\mmzNewExtern##1##2##3##4##5{\mynewextern##1\relax}%
+ \input{\examplepath.mmz}%
+ },
+ [\examplename.tex]
+ [\examplename.pdf]
+ [\normalsize\dots, no edge]
+ [\examplename.mmz, tikz={\draw[dotted](.east)--+(5em,0ex) node [anchor=south west, yshift=-1ex, align=justify, text width=14em, font=\footnotesize]{This is another auxiliary file produced by Memoize. We will mention it at the end of the section.};}]
+ ]
+ \end{forest}
+ \end{tcolorbox}
+ },
+ }
+}
+
+To top it off, changing the memoized code will produce new memo (and extern)
+files, with the old files staying in place. This is all by design --- the
+first hexadecimal number in these filenames is the MD5 sum of the memoized code
+and that's how Memoize knows which memo belongs to which piece of
+code\footnote{The second hexadecimal number in the memo and extern filenames is
+ the MD5 sum of the \emph{context}. The context is crucial for properly
+ externalizing code containing cross-references, see
+ section~\ref{sec:cross-referencing} for details.} --- but it has the downside
+that the folder containing your document can get quite cluttered (imagine the
+directory listing as above, but for a document with a hundred externalized
+pictures which you have been working on for a month).
+
+\ExampleName{clean-house}
+
+I like to keep a clean house by instructing Memoize to put memos and friends
+into their own directory. This can be achieved by writing
+\refcmd{mmzset}\braces{\Emph{\refmmz{memo dir}}} into the preamble (anytime
+after loading the package).\footnote{The \refmmz{memo dir} key is in fact
+ merely an abbreviation for a sequence of \refmmzpath{dir} and
+ \refmmzpath{prefix} within \refmmz{path}; use these keys if you need more
+ control over the name and location of the auxiliary files. Furthermore, there
+ is also the \refmmz{no memo dir} key, which reverts the configuration back to
+ the dirty default.} This will put the memo and the extern files into folder
+\meta{document name}|.memo.dir| (and it will also omit the \meta{document name}
+prefix in their filenames, because it makes no sense to repeat it there).
+
+\makeexample{\examplename.pdf}
+{%
+ \relaxmmzcommands
+ \edef\marshal{%
+ \noexpand\def\noexpand\mynewextern./\examplename
+ }\marshal.memo.dir/#1-#2.pdf\relax{%
+ \forestset{
+ append={[#1.memo\vphantom{p},pointcolor]},
+ append={[#1-#2.memo\vphantom{p},pointcolor]},
+ append={[#1-#2.pdf,pointcolor]},
+ }%
+ }
+ \tcbinputexample{
+ comment={%
+ \begin{tcolorbox}[reset, left=2mm, bottom=0mm,
+ my boxed title=the folder contents (after two compilations),
+ attach shifted boxed title to top right,
+ ]
+ \begin{forest}
+ before typesetting nodes={for tree={
+ font=\scriptsize\tt, grow'=0, folder, s sep=0}},
+ [\meta{the document folder}, inner xsep=0
+ [\examplename.tex]
+ [\examplename.pdf]
+ [\normalsize\dots, no edge]
+ [\examplename.mmz]
+ [\examplename.memo.dir,pointcolor,
+ % tikz={\draw[dotted](.east)--+(9em,0ex) node [anchor=south west, yshift=-1ex, font=\footnotesize, emphshade=black!5!white, text width=15em, align=justify]{You need to create this directory by hand, or allow Memoize to create it by adding |mkdir| to the list of restricted shell escape commands.};},
+ tikz={\draw[dotted](.east)--+(9em,0ex) node [anchor=west, font=\footnotesize, emphshade=black!5!white]{This directory must be created, somehow.};},
+ TeX={%
+ \def\mmzNewExtern##1##2##3##4##5{\mynewextern##1\relax}%
+ \input{\examplepath.mmz}%
+ },
+ ]
+ ]
+ \end{forest}
+ \end{tcolorbox}
+ },
+ }
+}
+
+\begin{tcolorbox}[title={Why is \refmmz[link color=white]{memo dir} not the default?}]
+ The \code{clean-house} example most likely compiled just fine, and you are
+ wondering why \refmmz{memo dir} is not in effect by default. Well, out of
+ the box, \hologo{TeX} cannot create directories, so it is the fact that
+ Memoize \emph{can} create them (at least under the default settings) which
+ requires explanation. By default, Memoize triggers extraction by executing
+ the Perl extraction script \refscript{memoize-extract.pl}, and it is this
+ script which actually creates the memo directory. However, not everybody
+ will necessarily use this script \dots\ so \refmmz{memo dir} should not be
+ the default.
+
+ The Python extraction script \refscript{memoize-extract.pl}, used when
+ \refmmz{extract}|=|\refmmz{extract=python}, works the same as the Perl
+ variant. With \hologo{TeX}-based extraction
+ \refmmz{extract}|=|\refmmz{extract=tex}, things are different. If you are
+ compiling the document with a full shell escape mode
+ (\docref{-shell-escape}), Memoize successfully creates the directory with the
+ system command |mkdir|.\footnote{|mkdir| is the default value of key
+ \refmmz{mkdir command}, but executing the extraction method
+ \refmmz{extract=perl} or \refmmz{extract=python} overrides this default.}
+ However, if you're using the restricted shell escape mode, the attempt to
+ create the directory won't succeed unless you include |mkdir| among the
+ restricted shell escape commands (see footnote~\ref{fn:shell-escape-commands}
+ on page~\pageref{fn:shell-escape-commands} for how to do this, but note that
+ it is not recommended).
+
+ If you are using external extraction, you have to create directory
+ \texttt{\examplename.memo.dir} by hand, prior to the first compilation of the
+ document (with Memoize). This is the case even if you are performing the
+ extraction using one of the shipped extraction methods, and it is due to the
+ fact that Memoize needs the memo directory to be present even before extern
+ extraction, because it writes the |.memo| files into the same directory.
+ (When Memoize uses the extraction script to create the memo directory, it
+ does so completely independently of extraction, and prior to creating any
+ |.memo| files.)
+\end{tcolorbox}
+
+I actually suggest adding \refcmd{mmzset}\braces{\refmmz{memo dir}} into your
+user-wide \reffile{memoize.cfg} (see section~\ref{sec:memoize.cfg} for details
+on this file). This will keep all your houses clean --- without work! --- as
+Memoize will automatically use the memo directory for any document your create.
+
+It is always safe to delete memos (|.memo|) and externs (|.pdf|s residing next
+to memos), in the sense that you cannot lose data this way.\footnote{The same
+ goes for the extern |.log| files produced by the \hologo{TeX}-based
+ extraction.}
+
+\begin{itemize}
+
+\item Many memos and externs are typically stale anyway, i.e.\ they reflect
+ some previous state of your document and are not needed anymore. These files
+ can be deleted without any repercussions whatsoever (unless you later revert
+ to a previous version of the document, of course). In fact, you might
+ \emph{want} to delete them periodically, or at least once you finish writing
+ the document. As it is hard to figure out which memos/externs are stale,
+ Memoize ships with a clean-up script: writing \refscript{memoize-clean.pl}
+ \meta{document name}\dmmz (replace |.pl| with |.py| if you use Python rather
+ than Perl) into the command line will delete all the \emph{stale} auxiliary
+ files belonging to the document.
+
+\item If you delete a memo or an extern currently in use, you will trigger
+ recompilation of their code --- so deleting a memo or an extern is actually a
+ perfectly legal alternative to using the \refmmz{recompile} key!\footnote{For the
+ users of the \hologo{TeX}-based extraction: deleting the |.log| file does
+ \emph{not} trigger recompilation.}
+
+\end{itemize}
+
+It is also safe to delete the \dmmz file (or any other kind of record file, see
+section~\ref{sec:record-files}) residing next to your document's |.pdf|. The
+\dmmz file contains the information about which externs should be extracted
+from the |.pdf|. Deleting it before this is done (by default, before compiling
+the document again) will prevent the extraction (same as if providing the
+package option \code{\refmmz{extract}=\refmmz{extract=no}}) and ultimately
+result in the recompilation of the externs produced in the previous run.
+Deleting it after the extraction will have almost no effect: it will only only
+prevent the clean-up script from working (the \dmmz file also lists the
+currently active memos and externs, and thereby indirectly informs the clean-up
+script which files are stale). For further information on the \dmmz file, see
+section~\ref{sec:.mmz}.
+
+
+
+\subsection{Writing a book?}
+\label{sec:tut:multifile}
+
+Books and other long documents are usually produced from sources which reside
+in more than a single file, and to speed up the editing process, authors
+usually use some system which allows them to compile each chapter separately.
+Can Memoize --- designed for virtually the same task of speeding up the editing
+process --- work sensibly in this kind of situation? More precisely, can the
+book and the individual chapters share the memos and the externs? Yes they
+can! If we instruct Memoize to use the same memo directory for both the book
+job and the chapter jobs, then we can externalize graphics when compiling a
+chapter and have the externs included when compiling the book (and vice
+versa).\footnote{Package \pkg{docmute} makes \hologo{LaTeX} ignore the preamble of
+ the chapter file when including this file into the main document.} All we
+need to do is use our old friend \refmmz{memo dir} from section~\ref{sec:tut:memodir}
+--- we see now that this setting is good for more than just keeping a clean
+house!
+
+\ExampleName{book}
+\makeexample{\examplename.tex.c1}
+\makeexample{chapters/chapter1.tex.c1}
+
+\begin{tcbraster}[raster columns=2, raster valign=top]
+ \tcbinputexample{listing only}
+ \tcbinputexample(chapters/chapter1){listing only}
+\end{tcbraster}
+
+In the above example, the individual chapters reside in files stored in the
+|chapters| subdirectory, and that's why the |book.tex| preamble uses
+\code{\refmmz{memo dir}=chapters/book} (rather than \code{\refmmz{memo
+ dir}=book} or just \refmmz{memo dir}). However, Memoize has no trouble
+with a situation where the main file and the chapters reside in the same
+folder; the setup is even simpler, as we then say \code{\refmmz{memo dir}=book}
+in both the book and the chapter preamble. The more complicated situation was
+chosen to point out the following potential problem with the setup where the
+chapters reside in a subdirectory.
+
+If you're anything like me, you would first go for having a memo directory
+immediately contained in the project directory (so |examples/book.memo.dir|
+above) and set up \refmmz{memo dir} as shown below. Well, this won't work, or
+at least it won't work with the vanilla \hologo{TeX} Live, because \hologo{TeX}
+will refuse to \emph{write} into (memo) files outside the directory where it
+was executed,\cprotect\footnote{In \hologo{TeX} Live, the \reffile{texmf.cnf}
+ option controlling this behaviour is called |openout_any|. By default, it is
+ set to |p| (paranoid), which ``disallow[s] opening dot files [and]
+ \emph{going to parent directories}, and restrict[s] absolute paths to be
+ under \texttt{\$TEXMFOUTPUT}'' (emphasis mine).} and this is precisely what
+the chapter compilation is asked to do below.
+
+\begin{tcboxedraster}[raster columns=2, raster valign=top]{blankest, bad}
+ \begin{tcblisting}{example title, title=the main file, listing only}
+\mmzset{~memo dir=book~}
+% ...
+\input{chapters/chapter1.tex}
+ \end{tcblisting}
+ \begin{tcblisting}{example title, title=a chapter file, listing only}
+\mmzset{~memo dir=../book~}
+ \end{tcblisting}
+\end{tcboxedraster}
+
+\pagebreak % manual
+
+Section~\ref{sec:tut:working-on-a-picture} presented some ideas on how to work
+on a single picture. Those ideas can be all easily applied to the multi-file
+situation. For example, you could use \refmmz{readonly} on the chapter that you're
+working on (and that chapter only). This way, the preview of the chapter will
+not be tarnished by the extern pages, and if you periodically compile it
+without \refmmz{readonly}, or compile the book (which does not have the \refmmz{readonly}
+set), you will have a reasonably up-to-date set of externs.
+
+\begin{tcboxedraster}[raster columns=2, raster valign=top]{blankest}
+ \begin{tcblisting}{example title, title=the main file, listing only}
+\mmzset{memo dir=chapters/book}
+% ...
+\input{chapters/chapter1.tex}
+ \end{tcblisting}
+ \begin{tcblisting}{example title, title=the current chapter file, listing only}
+\mmzset{memo dir=book, ~readonly~}
+ \end{tcblisting}
+\end{tcboxedraster}
+
+\ExampleName{memoize.cfg._region_}
+\makeexample{\examplename.tex.c1}
+\begin{tcolorbox}[title=For \Emacs users]
+ I often use this \refmmz{readonly} trick myself, but with a twist. As an Emacs user,
+ I don't use a \hologo{TeX}-based mechanism (such as the \pkg{docmute} package) to
+ compile a chapter, but rely on the region compilation feature of Emacs'
+ AUC\hologo{TeX} package. AUC\hologo{TeX} offers a way to compile the current
+ buffer (if you don't know what an Emacs buffer is, read ``file'') or region
+ (roughly speaking, the selected text). It does that by putting the buffer or
+ the region into a file called |_region_.tex| while dressing it up in the
+ preamble of the original document (when I'm working on a multi-file document,
+ it correctly pulls the preamble from the main document). This results in a
+ compilable region file. My trick is to detect whether I'm compiling a region
+ (this is the job of |\ifregion|), and if so, put Memoize into the \refmmz{readonly}
+ mode (an alternative trick would be to \refmmz{disable} it).
+
+ This is the trick in a nutshell, but to make it really work we have to
+ address one further issue: the original document and the region have to share
+ memos and externs. This happens automatically if the original document sets
+ \refmmz{memo dir} explicitly (e.g.\ if a document called |doc.tex| contains
+ \code{\refmmz{memo dir}=doc} in the preamble), but I'm lazy and don't want to
+ write this in every document --- if I have to do that, what's the point of
+ \refmmz{memo dir} I put into my \reffile{memoize.cfg} in
+ section~\ref{sec:tut:memodir}? Fortunately, the region file starts with
+ |\message{ !name(|\meta{original document name}|.tex)}| to indicate the
+ origin. The complicated part of the code below (everything following
+ \refcmd{mmzset}\braces{\refmmz{readonly}} parses this header to extract the
+ \meta{original document name}, which is then fed to \refmmz{memo dir}. Now,
+ the trick works automatically for any document.\footnote{The assumption here
+ is that \refmmz{memo dir} is in effect for the original document. If not,
+ the trick can be adapted to use (\refmmzpath{dir} and) \refmmzpath{prefix}
+ within \refmmz{path}.}
+
+ \tcbinputexample{
+ title=\tt memoize.cfg,
+ attachment name=memoize-region.cfg,
+ listing only,
+ }
+\end{tcolorbox}
+
+
+\subsection{Writing a presentation?}
+\label{sec:tut:beamer}
+
+Memoize ships with built-in support for the most widespread \hologo{LaTeX}
+presentation class, Beamer, in the sense that it can externalize a picture
+which changes from overlay to overlay. Before we learn how to use that
+functionality, however, there's a peculiarity about loading Memoize in Beamer
+to address.
+
+\ExampleName{beamer}
+\makeexample{\examplename.pdf}
+
+\tcbinputexample{
+ comment and listing,
+ listing options app={lastline=2},
+ warning, no attachment, title=,
+ %
+ comment={Beamer opens the document PDF while loading the class, while
+ Memoize requires the PDF from the previous compilation intact in order to
+ extract the externs (when extraction is triggered internally, which is the
+ default setting). The solution is to load Memoize (a package) before
+ Beamer (a class), which can be done by using \cs{RequirePackage} instead of
+ the usual \cs{usepackage}. Easy, if hacky.},
+ %
+}
+
+To memoize a piece of code which produces different results on different
+overlays --- by virtue of containing |\pause|, |\only|, and\slash or related
+commands --- apply key \Emph{\refmmz{per overlay}}. Without this key,
+externalization of the picture will end badly, with a single extern (the final
+one) appearing on all overlays. The key may be invoked either from a prior
+\refcmd{mmznext} command,\footnote{Of course, \refmmz{per overlay} may also be
+ invoked from \refcmd{mmzset}, but I guess this won't make sense often. For
+ example, if you set it for the entire presentation, and the presentation
+ contains static memoized pictures as well, you will compile those pictures
+ more times than necessary: once for each overlay, whereas once per frame
+ would suffice. It might occasionally make sense, however, to use \refmmz{per
+ overlay} as an \refmmz{auto} option --- consult
+ section~\ref{sec:tut:verbatim} to learn what that is.} or executed in the
+memoized code itself. The example below illustrates the latter option, and
+also shows that we may invoke it via its full path,
+\refkeypath{/mmz}|/|\refmmz{per overlay}, when listed among options processed by
+\pkg{pgfkeys}.\footnote{Read section~\ref{sec:per-overlay} to learn how the
+ Beamer support is implemented. The implementation only uses Memoize's public
+ interface, so understanding it should help if you need to support some other
+ presentation package.}
+
+\tcbinputexample{
+ listing options app={firstline=3},
+ middle=1mm,
+ comment={\def\dpwidth{0.27\linewidth}\def\epwidth{0.15\linewidth}%
+ \raisebox{-\height}{\includeexamplepdf[extern page,left=0mm,right=0mm]{width=\epwidth,page=1,trim=1in 1in 0.4in 0.6in}}\hfill
+ \raisebox{-\height}{\includeexamplepdf[document page,left=1mm,right=1mm]{page=2,width=\dpwidth}}\hfill
+ \raisebox{-\height}{\includeexamplepdf[extern page,left=0mm,right=0mm]{width=\epwidth,page=3,trim=1in 1in 0.4in 0.6in}}\hfill
+ \raisebox{-\height}{\includeexamplepdf[document page,left=1mm,right=1mm]{page=4,width=\dpwidth}}%
+ },
+}
+
+\begin{tcolorbox}[warning]
+ If the memoized code changes the value of Beamer's pause counter
+ |beamerpauses|, e.g.\ by issuing a |\pause|, take care that (i) \refmmz{per
+ overlay} is executed prior to any changes of |beamerpauses|, and that (ii)
+ the final value of this counter in the memoized code is the same for all
+ overlays.
+\end{tcolorbox}
+
+
+\subsection{When stuff sticks out}
+\label{sec:tut:padding}
+
+Some constructs --- like plain \hologo{TeX}'s \refcmd{llap} and \refcmd{rlap},
+and, notably, \TikZ overlays --- fool \hologo{TeX} into thinking that the
+``size'' of the typeset material is different than what it actually is. This
+can cause trouble for externalization: a piece of your picture might disappear!
+In a sentence, the solution is to manually set the \emph{padding} of the
+externs, but let's slow down a bit.
+
+The \TikZ picture in the following example consists of node with a pin on the
+right, but let's say we want to horizontally center this picture so that only
+the node rather than the entire picture (including the pin) will be centered.
+This can be achieved by adding key \refkey{/tikz/overlay} to the pin (actually,
+we need to add it to both the pin and its edge). \TikZ normally updates the
+extents (called the bounding box) of the picture every time it puts something
+in it; when \refkey{/tikz/overlay} is in effect, however, these updates are
+temporarily disabled. In effect, the \refkey{/tikz/overlay} key on the pin
+below will fool \hologo{TeX} into thinking that the node is all there is to the
+picture, so centering will work as desired.
+
+\ExampleName{overlay}
+\makeexample{\examplename.pdf N=4}
+\tcbinputexample{
+ after title pre={\ (no memoization)},
+ comment={\centering
+ % \includeexamplepdf[document page]{page=1,trim=1.8in 7.4in 1.8in 1.7in}
+ \includeexamplepdf[document page]{page=1}
+ },
+}
+
+What happens when we try to externalize this picture? The example below shows
+what would happen if Memoize had no concept of \emph{padding} --- which we
+simulate by setting \code{\refmmz{padding}=0pt}.\footnote{Unlike in the rest of
+ the manual, the extern pages in this section are shown without trimming the
+ whitespace.} Along with the rest of \hologo{TeX}, Memoize would be fooled
+into thinking that the picture comprises of the node only, so the pin would
+never make it into the extern. You would end up with a document missing the
+pin!\footnote{On the first compilation, the document page containing the figure
+ without padding looks fine, as it uses the result of the compilation rather
+ than the extern file. But on the second compilation, when Memoize actually
+ uses the extern, the pin disappears.}
+
+\tcbinputexample[.tex][.c2]{
+ after title pre={\ (memoization without padding)},
+ attachment name=\examplename-no-padding.tex,
+ sidebyside, lefthand ratio=0.3,
+ comment={\centering
+ \includeexamplepdf[size=minimal,boxrule=0.5mm,extern page,
+ attach boxed title to top right={xshift=1.5mm,yshift=-1mm},
+ ]{page=1}
+ },
+}
+
+
+By default, Memoize puts an inch of space around (what it thinks is) the
+externalized picture, and if the overlayed parts of the picture fit into this
+inch of space, you will find them in the extern and therefore also in the
+document. In our example, however, the default padding is not enough --- the
+pin is only partially visible.\footnote{You might wonder why I didn't make the
+ default padding much bigger, like 10 inches. \hologo{TeX} wouldn't be
+ bothered (unless the resulting extern size exceeded its maximum dimension),
+ but you might be, because with such a large default padding, all the externs
+ would be huge, most often bigger than the document pages, and remember that
+ the externs are first dumped into the document, where they can bother you.}
+
+\tcbinputexample[.tex][.c3]{
+ after title pre={\ (memoization with default padding)},
+ attachment name=\examplename-default-padding.tex,
+ listing and comment,
+ middle=0.9mm,
+ comment={\centering
+ \includeexamplepdf[extern page,size=minimal,boxrule=0.5mm]{page=1}
+ },
+}
+
+The solution is to set the padding manually. Below, I used \refmmz{padding
+ right} to only increase the padding on the right side (clearly, we also have
+\refmmz{padding left}, \refmmz{padding top} and \refmmz{padding bottom}), but
+if you're not bothered by a large extern, you can just use
+\Emph{\refmmz{padding}}, which sets all four sides at once. By the way, having
+too much padding (almost) never hurts, and as you see, you can use (simple)
+arithmetics in the value of these keys.
+
+\tcbinputexample[.tex][.c4]{
+ after title pre={\ (memoization with extra padding)},
+ attachment name=\examplename-extra-padding.tex,
+ listing and comment,
+ middle=0.9mm,
+ comment={\centering
+ \includeexamplepdf[extern page,size=minimal,boxrule=0.5mm]{page=1}
+ },
+}
+
+\enlargethispage{1ex} % manual
+Incidentally, the \refmmz{padding} keys only change how
+the externalized picture is \emph{stored}. Memoize remembers the size of the
+extern as seen by \hologo{TeX} (e.g.\ the bounding box of the picture as
+reported by \TikZ, with overlayed parts of the picture protruding out of it),
+and it uses that size when integrating the extern into the document --- so
+everything works as it should!
+
+
+
+\subsection{The verbatim mode}
+\label{sec:tut:verbatim}
+
+Not all code will peacefully submit to memoization. In particular, this is the
+case for environments which process the environment body verbatim (or perform
+some other kind of \refcmd{catcode} magic). A simple environment of this kind is the
+standard \hologo{LaTeX} \refenv{verbatim}, but let us illustrate the issue with
+\refenv{tcblisting}, which typesets a code listing alongside its compiled effect.
+(This environment is defined by the |listings| library of package \pkg{tcolorbox}
+and was used extensively during the production of this manual.) To manually
+memoize a \refenv{tcblisting} environment, we enclose it in a \refenv{memoize}
+environment with a \Emph{\refmmz{verbatim}} key in the optional argument ---
+without this key, the example below would produce nothing but
+errors.\footnote{Memoize also offers a \emph{partial} verbatim mode, triggered
+ by key \refmmz{verb}; in this mode, the braces retain their usual category
+ codes. Also note that the effect of \refmmz{verbatim} can be ``undone'' by
+ key \refmmz{no verbatim}.}
+
+\ExampleName{verbatim-manual}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\\[1ex]
+ \footnotesize
+ (The document page is the same as for the \texttt{verbatim-auto} example below.)
+ },
+}
+
+Using \refmmz{verbatim} from \refcmd{mmzset} or \refcmd{mmznext} works just as
+well, and the latter can be very useful with automemoization, when some
+environment (say, \env{tcolorbox}) generally does not require the verbatim mode,
+but a specific occurrence does (say, because it contains some verbatim
+construction such as \verb!|!\meta{verbatim text}\verb!|! of the \pkg{ltxdoc}
+class).
+
+However, for an environment such as |tcblisting|, it makes the most sense to
+declare it verbatim in general, so that all instances of the environment will
+be processed in the verbatim mode. This is simple to do: add \refmmz{verbatim}
+to the \refmmz{auto} keylist.
+
+\ExampleName{verbatim-auto}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside, % lefthand ratio=0.62,
+ comment={\centering
+ \footnotesize
+ (The extern page is the same as for the \texttt{verbatim-manual} example above.)\\[1ex]
+ \includeexamplepdf[document page]{page=2}\\
+ },
+}
+
+In fact, you can add any \refkeypath{/mmz} key to the \refmmz{auto} keylist,
+and the key will be applied to all occurrences of the command or the
+environment. For example, adding \refmmz{recompile} to the declaration of
+|tcblisting| above would recompile all and only the |tcblisting| environments;
+and as an \refmmz{auto} declaration only updates (rather than completely
+replaces) a previous declaration, you can also say things like
+\code{\refmmz{auto}=\refcmd{tikz}\braces{\refmmz{recompile}}} to recompile all
+\TikZ pictures produced by the \cs{tikz} command (handy, as you don't know how
+automemoization for \cs{tikz} was declared unless you've read
+section~\ref{sec:tut:automemoization-details} or looked at the Memoize's source
+code).
+
+
+\subsection{The final version of your document}
+\label{sec:tut:final}
+
+Bluntly put, you might want to disable Memoize when compiling the final version
+of your document, at least if you intend to distribute it in electronic form,
+for two reasons:
+\begin{itemize}
+\item An externalized picture cannot contain hyperlinks. Any hyperlinks (or
+ hyperlink anchors) contained in the original picture will silently disappear
+ during the production of the extern.
+\item When the document contains many externs, the size of the resulting PDF
+ can be several times the size of the PDF compiled without externalization.
+\end{itemize}
+
+Below, we list several ways of fully disabling Memoize. You're of course
+already familar with the first two ways, but what's this \refpkg{nomemoize}
+package? The rationale behind this package is that if you want to be
+absolutely sure that there is no trace of memoization in your document (for
+example, see the \refmmz{disable} -- \refmmz{enable} pitfall in
+section~\ref{sec:tut:working-on-a-picture}), the best thing to do is to not
+load the package at all. However, you have all those \refcmd{mmzset}s etc.\ in
+your source, so the document won't compile without
+\cs{usepackage}\braces{\refpkg{memoize}}, right? Right, but wrong. Enter
+\Emph{\refpkg{nomemoize}}, a dummy package which accepts all the commands that
+Memoize does, but does nothing. In effect, your document will compile, but you
+can be sure that not a single memo or extern was loaded or produced.
+
+\begin{tcbraster}[raster columns=3, raster force size=false, raster valign=top]
+ \begin{tcblisting}{listing only, add to width=2.4em, enhanced}
+\usepackage[~disable~]{memoize}
+ \end{tcblisting}
+ \begin{tcblisting}{listing only, add to width=-1.6em, enhanced}
+\usepackage{memoize}
+\mmzset{~disable~}
+ \end{tcblisting}
+ \begin{tcblisting}{listing only, add to width=-0.8em, enhanced}
+\usepackage{~no~memoize}
+ \end{tcblisting}
+\end{tcbraster}
+
+There is one issue you might need to resolve manually before package
+\refpkg{nomemoize} works as intended, though. If you have used any
+\refkeypath{/mmz} keys outside \refcmd{mmzset}, you need to list them in
+\refcmd{nommzkeys}. For example, if you used \refmmz{per overlay} in the manner
+illustrated in section~\ref{sec:tut:beamer}, i.e.\ as
+\refkeypath{/mmz}|/|\refmmz{per overlay} among the \TikZ keys, you need to
+write \refcmd{nommzkeys}\braces{\refmmz{per overlay}} into the document
+preamble.
+
+Another thing you might want to do once you have produced the final version of
+the document (in fact, just before you disable Memoize for good) is clean up.
+As we saw in sections~\ref{sec:tut:memodir} and~\ref{sec:tut:redefinitions},
+Memoize produces a lot of auxiliary files (memos and externs) and it keeps the
+old versions around! Once your document is prepared, you can reduce the
+clutter (and save some disk space) by deleting memos and externs belonging to
+the work-in-progress versions of your document, and keep only those used in the
+final version.
+
+You could achieve this by deleting all the memos and externs (if you're using
+the \refmmz{memo dir} directive, this amounts to the entire contents of the
+memo directory) and compiling your document for the final couple of times.
+However, there is an easier (but \hologo{TeX}-external) way: on the command
+line, change into the directory containing your (main) document and write
+\EmphTT{\refscript{memoize-clean.pl}} \meta{document name}\dmmz (substitute
+|.py| for |.pl| to use Python rather than Perl). The script will inspect the
+contents of the \dmmz record file to see which memos and externs were used in
+the final compilation, and delete all other memos and externs belonging to the
+given document.
+
+\begin{tcolorbox}[warning]
+ Deleting memos and externs is never an irreversible operation, as you can
+ always recreate them, but it is still wise to be cautious when cleaning up.
+ For one, avoid cleaning up after a compilation which produced errors; a
+ failed compilation can lead to an incomplete \dmmz file, which can in turn
+ lead to over-deletion. Another bad idea is cleaning up after disabling
+ Memoize for a part of a document, for the same reason.
+
+ All that said, Memoize takes some precautions itself. It will cowardly
+ refuse to perform the clean-up when the \dmmz file is missing the
+ end-of-file marker (|\endinput|), assuming that this indicates a fatal error
+ in the previous compilation. It will do the same in case the \dmmz file is
+ absent or empty. The latter is assumed to be a result of a globally
+ \refmmz{disable}d memoization, but note that clean-up will be performed if
+ memoization was disabled using package \refpkg{nomemoize}: that package does not
+ touch the \dmmz file, so cleaning up should work as intended.
+\end{tcolorbox}
+
+As the final note, memos and externs (cleaned-up or not) may be copied (along
+the document source) to another directory or machine, where they should be
+picked up by Memoize. There is no need to copy the \dmmz file (assuming that
+the document PDF contains no extern pages waiting for extraction).
+
+
+\section{Digging deeper}
+\label{sec:potential-pitfalls}
+
+
+
+\subsection{Good to know}
+\label{sec:tut:good-to-know}
+
+
+\paragraph{Line- and page-breaking} An extern can't be broken across lines or
+pages.
+
+Externalization of a chunk of code produces a PDF, which is included into the
+document at subsequent compilations as a picture --- an unbreakable object (a
+horizontal box) with fixed width and height. Therefore, the original code
+should produce an unbreakable object as well. For example, this means that you
+cannot externalize some text and expect \hologo{TeX} to break it across lines
+or pages on subsequent compilations. If you try, the compilation will succeed
+--- without an error! --- but your externalized text will end up in a single
+line, as shown below.
+
+\ExampleName{no-linebreaking}
+\makeexample{\examplename.pdf N=2}
+\tcbinputexample{
+ bad,
+ comment={\centering
+ \includeexamplepdf[extern page,to be continued on right]
+ {page=1,trim=1in 1in 14in 1in}\\[1ex]
+ \includeexamplepdf[document page]{page=2}\\[1ex]
+ \includeexamplepdf[document page,title=the expected document page]
+ [\examplepath.c2.pdf]{page=1}
+ },
+}
+
+That said, you \emph{can} externalize a paragraph or some other vertical mode
+material using \refmmz{capture}|=|\refmmz{capture=vbox}, but beware that the
+vertical spacing between the memoized material and its surroundings might
+change.
+
+
+\paragraph{\env{remember picture}}
+\TikZ pictures using this key cannot be externalized.
+
+Memoize will silently refuse to externalize any \TikZ picture using
+\refkey{/tikz/remember picture} (see \PGFmanual{17.13}). Such pictures
+interact with the outside world --- they either reference or are referenced by
+other pictures --- and are as such unsuitable for externalization. For
+example, while the colored boxes in this manual are generally externalized ---
+out of principle \Smiley\ --- the title page illustration is not, and it cannot
+be, because of the arrows connecting the various \TikZ pictures composing that
+illustration. Some packages use the \refkey{/tikz/remember picture} mechanism
+under the hood, and are thus subject to this limitation; one example is package
+\pkg{todonotes}, but in general, any package dealing with absolute positions on the
+page will be limited in this way.
+
+How does Memoize deal with this situation? Well, by cowardly refusing to
+externalize any code which uses \refkey{/tikz/remember picture} or a similar
+mechanism for dealing with absolute positions. Luckily, any such mechanism
+eventually boils down to the \hologo{TeX} primitive \refcmd{savepos}, so
+Memoize hacks --- or as we will say in this manual, \emph{advises} --- this
+primitive to abort any ongoing memoization. Initializing and then aborting the
+memoization takes some time, to be sure, but the overhead is negligible,
+especially in the light of the fact that \emph{not} aborting wreaks real havoc.
+
+Memoize actually provides a user interface for aborting memoization.
+Memoization can be aborted either manually, by executing \refcmd{mmzAbort}, or
+automatically. The latter is a generalization of the automemoization idea: a
+command such as \refcmd{savepos} can be advised to abort memoization by
+\refmmz{auto}|=|\refcmd{savepos}\bracestt{\refmmzauto{abort}}. In Memoize,
+commands take your advice seriously, so memoization will be aborted whenever
+the advised command or environment is encountered.
+
+
+\paragraph{Indirectly embedded environments} Such environments cannot be
+memoized.
+
+Read this if you got an error message such as |Environment "tikzpicture" ended
+as "foo"|.
+
+Some environments are defined so that they embed another environment using the
+idiom shown on the left: the begin-code of the outer environment opens the
+inner environment, and the end-code of the outer environment closes the inner
+environment. While this is a fine, and common, idiom, it messes up the
+memoization of the inner environment. In the example on the right, trying to
+\emph{auto}memoize a \env{minipage} environment (not recommended at all!) causes
+trouble with package \pkg{sectionbox}.\footnote{This is a \texttt{Package
+ collargs Error} because Memoize outsources the actual work of collecting
+ the environment body to the auxiliary package CollArgs, described in
+ section~\ref{sec:collargs}.}\fncomma\cprotect\footnote{Why does this happen?
+ As mentioned in section~\ref{sec:tut:memodir}, Memoize keeps track of memos
+ and externs by the MD5 sum of the memoized code. But to compute that sum for
+ an environment, Memoize has to \emph{grab} the environment body, meaning it
+ has to collect the body in advance. This presents no problem when
+ \refcmd{end}\meta{environment name} is already present in the input stream at the
+time \refcmd{begin}\meta{environment name} is executed, like when you use the
+ environment normally in your document, or when some macro expands so that it
+ produces both \cs{begin}\meta{environment name} and \cs{end}\meta{environment
+ name} simultaneously --- so there would be no problem above if
+ |\end{minipage}| occured in the beginning code of \env{sectionbox}. The idiom
+presented above is problematic for memoization because at the time \hologo{TeX}
+executes |\begin{sectionbox}|, putting |\begin{minipage}| into the input
+ stream, |\end{sectionbox}| is not yet executed and remains as it is. The
+ input stream therefore contains a pair of |\begin{minipage}| and
+ |\end{sectionbox}|. In the normal, non-memoizing course of events this
+ would not be a problem, because |\end{sectionbox}| would eventually expand to
+|\end{minipage}|. During memoization, however, this \emph{is} a problem,
+because, as we said, Memoize needs to grab the environment body: upon
+encountering |\begin{minipage}|, it looks in the input stream for
+ |\end{minipage}| --- but there is no |\end{minipage}| in the input stream,
+there is only |\end{sectionbox}|, and this results in the |Environment
+"minipage" ended as "sectionbox"| error.}
+
+\begingroup
+\ExampleName{sectionbox}
+\makeexample{\examplename.tex.c1}
+\mmzset{disable}
+\begin{tcbraster}[raster equal height]
+\begin{tcblisting}{listing only, bad, valign=center}
+\newenvironment{foo}% ... args
+{% the begin-code of foo
+ % ...
+ \begin{tikzpicture}
+ % ...
+}
+{% the end-code of foo
+ % ...
+ \end{tikzpicture}
+ % ...
+}
+\end{tcblisting}
+\tcbinputexample{
+ bad,
+ comment={\small\tt
+ ! Package collargs Error: Environment\\"minipage" ended as "sectionbox".
+ },
+ }
+\end{tcbraster}
+\endgroup
+
+What are your options in this kind of a situation?
+\begin{enumerate}
+\item The only way to perform any memoization here is to memoize the
+ \emph{outer} environment --- if that makes sense.\footnote{This avoids the
+ error because Memoize grabs and memoizes the outer environment, and while
+ it is memoizing it, further memoization is switched off.} You can do this
+ either on a case-by-case basis, by enclosing it in the \refenv{memoize}
+ environment, or automemoize it: \code{\refmmz{auto}=\marg{outer
+ environment}\braces{\refmmzauto{memoize}}}.
+\item But what if memoizing the outer environment is out of the question?
+ Then, the only way to avoid the error is to prevent the automemoization of
+ the inner environment.
+ \begin{enumerate}
+ \item If you are facing a single occurrence of the problem, it is perhaps
+ easiest to use key \refmmz{disable} just before the start of the outer
+ environment.
+ \item Otherwise, you can automatically disable memoization for the span of
+ each occurrence of the outer environment: \code{\refmmz{auto}=\marg{outer
+ environment}%
+ \braces{\refmmzauto{nomemoize}}}.
+ \item To deactivate the automemoization of the inner environment for the span
+ of the outer environment, but otherwise allow for memoization inside the
+ outer environment: \code{\refmmz{auto}=\marg{outer environment}%
+ \braces{\refmmzauto{noop}, \refmmz{deactivate}=\meta{inner
+ environment}}}. Key \refmmzauto{noop} does nothing but apply the
+ given options (in this case, \refmmz{deactivate}=\meta{inner environment})
+ to the advised command or environment.
+ \end{enumerate}
+\end{enumerate}
+
+\subsection{Extraction methods and modes}
+\label{sec:extraction}
+
+Remember that in Memoize, externalization is a two-step process. First,
+externs are typeset on separate pages of the main document, called extern
+pages. Then, these extern pages are extracted out of the main document PDF
+into extern files. The process is illustrated on the title page.
+
+Memoize is flexible in terms of which piece of software is used to perform
+extern extraction. It ships with three \emph{extraction methods}:
+
+\begin{description}
+\item[\refmmz{extract=perl}] A Perl script, \refscript{memoize-extract.pl}.
+ This method is the default because it is fast and because Perl is usually
+ already installed on a system running \hologo{TeX}. However, you will most
+ likely still need to install two pieces of software that the script depends
+ on: Perl libraries \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} and
+ the \hreftt{https://metacpan.org/pod/Path::Class}{Path::Class}, the
+ installation guidelines can be found in section~\ref{sec:install}.
+\item[\refmmz{extract=python}] A Python script, \refscript{memoize-extract.py}.
+ This method is even faster than the Perl script, though not by much. Try it
+ out if you have problems installing Perl or the required libraries, or if the
+ Perl script chokes on your document (see section~\ref{sec:troubleshooting}
+ for the list of known issues). Besides Python ($\geq 3.8$), you will also
+ need the Python library \hreftt{https://pypi.org/project/pdfrw/}{pdfrw} or
+ \hreftt{https://pypi.org/project/pdfrw2/}{pdfrw2}. For the installation
+ guidelines, see section~\ref{sec:install}.
+\item[\refmmz{extract=tex}] \hologo{TeX}-based extraction requires no
+ additional software, but it is much slower than the scripts. As \hologo{TeX}
+ can only produce a single PDF per compilation, an instance of \hologo{TeX}
+ (loading the entire document PDF) has to be invoked for each extern, and this
+ takes time (although the entire process is still much faster than the
+ venerable \TikZ externalization library).
+\end{description}
+
+Memoize is also flexible in terms of how extern extraction is triggered,
+providing two \emph{extraction modes}:
+
+\begin{description}
+\item[internal]\label{item:setup:who} By default, extern extraction is
+ triggered internally, i.e.\ by Memoize during the compilation of the
+ document; more precisely, any externs produced in a compilation are extracted
+ during the next compilation. To choose an extraction method other than the
+ default Perl script, load Memoize with the package option
+ \EmphTT{\refmmz{extract}=\meta{extraction method}}.
+
+\item[external] Loading Memoize with with package option
+ \EmphTT{\refmmz{extract}=\refmmz{extract=no}} instructs Memoize to \emph{not}
+ trigger the (internal) extraction. When instructed to use extraction
+ ``method'' \refmmz{extract=no}, Memoize expects you to trigger the extraction
+ yourself, in any way that is convenient to you: manually from the command
+ line, or automatically through your editor, a Makefile, etc. --- all Memoize
+ cares about is that the extraction takes place before the next compilation of
+ the document.
+\end{description}
+
+Summing up, the extraction mode and method are selected by providing the
+appropriate value to package option key \refmmz{extract}; the possible values
+are listed in the table below. Note that this key can only be used as a
+package option, or in \refcmd{mmzset} within \reffile{memoize.cfg}. In
+particular, it is disabled in the document preamble, because Memoize performs
+extraction while it is loaded.
+
+\medskip
+\begin{center}
+ \begin{tabular}{lll}
+ \toprule
+ extraction method&external program&Memoize invocation\\
+ \midrule
+ \refmmz{extract=perl}&\refscript{memoize-extract.pl}&\refcmd{usepackage}\braces{\refpkg{memoize}}\footnotemark\\
+ \refmmz{extract=python}&\refscript{memoize-extract.py}&\refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=python}}\braces{\refpkg{memoize}}\\
+ \refmmz{extract=tex}&|pdftex|&\refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=tex}}\braces{\refpkg{memoize}}\\
+ \refmmz{extract=no}&none (external extraction)&\refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=no}}\braces{\refpkg{memoize}}\\
+ \bottomrule
+ \end{tabular}%
+ \footnotetext{Or
+ \refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=perl}}%
+ \braces{\refpkg{memoize}}. This is useful if you have changed the default
+ using \reffile{memoize.cfg}.}%
+\end{center}
+\smallskip
+
+For internal extraction, \hologo{TeX} must be allowed to execute the external
+program implementing the chosen extraction method. Both |memoize-extract|
+scripts should be listed among restricted shell escape mode commands in your
+\hologo{TeX} distribution; their execution should therefore be allowed under
+the default, restricted shell escape mode. However, the |pdftex| program,
+executed by extraction method \refmmz{extract=tex}, is not listed there, nor
+should it be. If you are forced to use this fallback method, I suggest you
+compile documents loading Memoize under the full shell escape mode, by adding
+command-line option \docref{-shell-escape} (on \hologo{TeX}Live) or
+\docref{--enable-write18} (on MiK\hologo{TeX}) to the invocation of the
+\hologo{TeX} program. The answers linked from question
+``\href{https://tex.stackexchange.com/q/598818/16819}{How can I enable
+ shell-escape?}'' on \href{https://tex.stackexchange.com}{\hologo{TeX}
+ StackExchange} will tell you how you can ask your editor to do this for you.
+
+You may use any extraction method to perform external extraction. The simplest
+option is to use the Perl or the Python script. Supposing you are doing this
+manually from the command line, change into the directory containing your
+document, which should contain the auxiliary \dmmz file produced by Memoize,
+and execute:
+
+\begin{enumerate}[(a)]
+\item \refscript{memoize-extract.pl} \meta{document name}\dmmz \hfill (for
+ the Perl script)
+\item \refscript{memoize-extract.py} \meta{document name}\dmmz \hfill (for
+ the Python script)
+\end{enumerate}
+
+See sections~\ref{sec:.mmz} and \ref{sec:ref:extraction-perl-python} for
+further details on the \dmmz file and the extraction scripts.
+
+Things are a bit more complicated if you want to use the \hologo{TeX}-based
+extraction method externally, because an instance of |pdftex| needs to be
+invoked for each extern (and these have unwieldy names and can be many in
+number), but Memoize can help you here by producing a shell script or a
+makefile, executing which will extract all the externs at once. To have Memoize
+produce a shell script, use package option
+\code{\refmmz{record}=\refmmz{record=sh}} (or
+\code{\refmmz{record}=\refmmz{record=bat}} on Windows); package option
+\code{\refmmz{record}=\refmmz{record=makefile}} will make a makefile. By
+default, these files are named |memoize-extract.|\meta{document name} plus the
+|.sh|, |.bat| or |.makefile| suffix. If neither a shell script nor a makefile
+works for you, you can also define your own kind of \emph{record file}, to be
+processed by the external tool of your choice (and implementation) in order to
+extract the externs; see section~\ref{sec:new-record-file} to learn how to do
+this.
+
+
+\subsection{From cross-references to the context}
+\label{sec:cross-referencing}
+
+Cross-referencing presents a challenge to externalization, because without
+special provisions, the ``communication channel'' between the \cs{label} and the
+\cs{ref} is broken once we start utilizing the extern.
+
+One direction of the issue occurs when a \refcmd{label} within the memoized
+code is referenced by a \cs{ref} on the outside. Without the (built-in)
+workaround, the \cs{label} command would only be executed when the extern is
+being produced, but not on subsequent compilations of the document, when it is
+merely included. Memoize addresses this problem by generalizing
+externalization (which can only produce a picture, the extern) to memoization
+(which can additionally produce arbitrary code). When Memoize is externalizing
+code which contains a \cs{label}, it automatically replicates it into the
+\emph{memo}, which is input into the document on subsequent compilations. In
+effect, the memo--extern team will continue to produce the label even when it
+is utilized rather than compiled. As far as the author is concerned, \cs{label}s
+in memoized code ``just work,'' without any observable differences to the
+situation without memoization. This is why we will not discuss this direction
+of the issue here; a reader interested in how precisely the system works is
+invited to read section~\ref{sec:memos}.
+
+The other direction of the issue occurs when a \refcmd{ref} within the memoized
+code references \cs{label} on the outside. In this situation, the extern
+should be recompiled when the value of the label it refers to changes. Again,
+Memoize addresses this problem in full generality, by associating with each
+extern a \emph{context}, and recompiling the extern whenever the value of the
+context changes.\footnote{The dependency of an extern upon prior definitions
+ and such can also be addressed in a more \emph{ad hoc} manner, by recompiling
+ manually; we have already touched upon this subject in
+ section~\ref{sec:tut:working-on-a-picture}, and will revisit it in
+ section~\ref{sec:tut:redefinitions}.} All that needs to be done for \cs{ref}
+and friends, specifically, is to advise them to add their reference keys to the
+context.
+
+As we shall see presently, for the author, the only difference between a
+non-memoized and a memoized \cs{ref} is that the latter will take one more
+compilation cycle to ``stabilize'' the resulting document. (More precisely,
+the memoized situation will take one more cycle if the reference is undefined
+on the first compilation.) Then, we will show how we can teach Memoize about
+cross-referencing commands other than \cs{ref} and \cs{pageref}. Finally, we will
+learn about key \refmmz{context}, the backbone of the cross-referencing support
+in Memoize. (The inner workings of the context are further explained in
+section~\ref{sec:c-memos}.)
+
+\ExampleName{ref}
+\makeexample{\examplename.pdf N=7}
+
+When the memoized code contains a \cs{ref} referring to a label given in another
+part of the document, the code is recompiled when (and only when) the reference
+changes. Let us look at the following example, jumping in at the point where
+it was already compiled enough times that the resulting PDF had stabilized into
+a single (document) page with correct references. (Environment
+\refenv{nomemoize} disables memoization
+of \href{https://ctan.org/pkg/tikzlings}{Ti\emph{k}Zlings}, so that their
+externs don't disturb us, and we can focus on the \cs{tikz} command, which does
+get externalized and contains a \cs{ref}.)
+
+\tcbinputexample[.tex][.c3]{
+ after title pre={\ (with stable output after three compilations)},
+ middle=1mm,
+ comment={\centering
+ \includeexamplepdf[document page]{page=1}
+ }
+}
+
+Let us add an owl in front of the penguin. In the next compilation, neither
+the ``normal'' nor the memoized reference is yet updated, as expected --- in
+this compilation, the new value of the penguin label only makes it into the
+|.aux| file.
+
+\tcbinputexample[.tex][.c4]{
+ after title pre={\ (after the first compilation with the added owl)},
+ no attachment,
+ comment={\centering
+ \includeexamplepdf[document page]{page=1}
+ }
+}
+
+During the following compilation, the \refcmd{ref}s pick up the new value of the
+penguin label, and the \cs{ref} inside the automemoized \cs{tikz} command
+forces recompilation of the extern (\emph{how} this is done will be explained
+later).
+
+\tcbinputexample[.tex][.c5]{
+ after title pre={\ (after the second compilation with the added owl)},
+ comment only, no attachment,
+ comment={\centering
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\quad
+ \includeexamplepdf[document page]{page=2}
+ }
+}
+
+In the next compilation, the resulting PDF is finally stabilized, as the
+updated extern is (extracted and) included into the document.
+
+\tcbinputexample[.tex][.c6]{
+ after title pre={\ (after the third compilation with the added owl)},
+ comment only, no attachment,
+ comment={\centering
+ \includeexamplepdf[document page]{page=1}
+ }
+}
+
+The message to take home? When some memoized code contains a reference and
+that reference changes, it will take three compilation cycles (so, one more
+cycle than without memoization) for the resulting document to ``stabilize.''
+
+Out of the box, Memoize supports the standard \hologo{LaTeX} cross-referencing
+commands \cs{ref} and \refcmd{pageref}. To automatically recompile code
+containing some other cross-referencing command, like \refcmd{vref} of package
+\pkg{varioref}, we use the advising framework implemented by package Advice.
+This framework is a generalization of automemoization: we use the familiar
+\refmmz{auto}, but with advice offered by \Emph{\refmmzauto{ref}} rather than
+\refmmzauto{memoize}.
+
+{\ExampleName{vref}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing only}}
+
+Key \refmmzauto{ref} only works for commands which operate on a single
+reference key. However, that single key (which must be enclosed in braces) may
+be preceded by optional argumen(s) of any kind. Extensions to \refcmd{ref},
+e.g.\ the \pkg{hyperref}'s variant, which accepts an optional |*|, work out of
+the box. Furthermore, Memoize offers support for cross-referencing commands
+which work on multireferences and reference ranges, such as \pkg{cleveref}'s
+\refcmd{cref} and \refcmd{crefrange}. Those commands should be advised by
+\refmmz{auto} keys \refmmzauto{multiref} and \refmmzauto{refrange},
+respectively.
+
+We have jumped into first example of this section with the assumption that it
+had already been compiled several times, allowing the resulting PDF to
+stabilize. Let us now take a look at what happens at the very first, fresh
+compilation of our original example (the one without the owl). (Removing the
+|.aux| file before compiling the example again will start afresh.) The curious
+thing is that we don't get the extern page containing
+\tikz[baseline]\node[draw=red,thick,fill=yellow,anchor=base,font=\bf]{??};.
+This is so because by default, Memoize aborts a memoization containing an
+undefined reference.
+
+\tcbinputexample[.tex][.c1]{
+ after title pre={\ (after the fresh compilation of the original example)},
+ comment only, no attachment,
+ comment={\centering
+ \includeexamplepdf[document page]{page=2}
+ }
+}
+
+Now sometimes you might want to produce an extern even if it contains an
+undefined reference --- for example, you might intend to write the code
+containing the \cs{label} much later but enjoy the speed-up offered by Memoize
+until then. In that case, apply the \refmmz{auto} key \Emph{\refmmzauto{force
+ ref}} to \cs{ref}.
+
+\tcbinputexample[.tex][.c7]{
+ after title pre={\ (after the fresh compilation with \refmmzauto{force ref})},
+ attachment name=\examplename-force.tex,
+ comment={\centering
+ \includeexamplepdf[extern page][\examplepath.c1.pdf]{page=1,trim=1in 1in 1in 1in}\quad
+ \includeexamplepdf[document page][\examplepath.c1.pdf]{page=2}
+ }
+}
+
+However, note that when you use \refmmzauto{force ref}, \hologo{LaTeX} will
+\emph{not} complain about the undefined reference once the extern containing it
+is included (unless that reference also occurs in some non-memoized piece of
+code). Using \refmmzauto{force ref} is therefore a tiny bit dangerous, and
+this is why \refmmzauto{ref}, with the abortion mechanism, is the default
+handler for \cs{ref} and \refcmd{pageref}.
+
+As already noted in the previous section, \refcmd{ref} works by appending the
+cross-reference to the \emph{context}, the change of which triggers
+recompilation. Memoize initializes the context to contain the four
+\refmmz{padding}s --- as a result, an extern recompiles if we change the
+padding --- but we can append stuff to the context by ourselves, as well.
+Below, we use key \Emph{\refmmz{context}} to append the font size (we'll talk
+about the value given to this key a bit later); as a result, the picture is
+recompiled whenever the font size changes. Below, we change the font size
+using command |\small|; changing the default size with a class option such as
+|12pt| works as well.
+
+\ExampleName{fontsize}
+\makeexample{\examplename.pdf N=2}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.7, after title pre={\ (the first version)},
+ comment={
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}
+ }
+}
+
+\tcbinputexample[.tex][.c2]{
+ sidebyside, lefthand ratio=0.7, after title pre={\ (the second version)},
+ no attachment,
+ comment={
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}
+ }
+}
+
+How does this work? Key \refmmz{context} appends the given tokens to the
+\emph{context expression}. When creating an extern or trying to use it,
+Memoize (fully) expands this expression and computes the MD5 sum of the
+expansion. This \emph{context MD5 sum} then serves as a part of the extern's
+filename (see sections~\ref{sec:tut:memodir} and~\ref{sec:memos}). In effect,
+Memoize will only find (and utilize) the extern if \emph{the context MD5 sum
+ computed during (attempted) utilization matches the one computed during
+ memoization}.
+
+As revealed by looking at the \hologo{LaTeX} source code, \hologo{LaTeX} holds
+the current font size in macro |\f@size|, and above, we have effectively added
+the contents of this macro to the context. Now, why didn't we simply write
+\refmmz{context}|=\f@size|? First, we used |\csname ... \endcsname| because we
+were under the normal \hologo{LaTeX} catcode regime, where |@| cannot be a part
+of the command name. Of course, we could have temporarily changed the catcode
+of |@| using |\makeatletter| and |\makeatother|, but I would advise against
+that, because the approach does not work in general: it fails when key
+\refmmz{context} is used \emph{within} memoized code (we will explain why in
+section~\ref{sec:memos}). Another reason why I recommend the |\csname
+... \endcsname| approach is that it does not result in an error when the
+control sequence is not defined (|\csname ... \endcsname| will expand to
+|\relax| then); this behaviour is handy for undefined cross-references, for
+example. Second, why did I write |fsize={...}| around the control sequence?
+Well, because I'm being paranoid, really. Writing \refmmz{context}|={\csname
+ f@size\endcsname}| would work just as well, but I like to explicitly
+``announce'' the value to prevent any possibility of a conflict with an
+alternative context. Imagine that we don't use the ``announcements'' and we
+decide to add some other dimension instead of the font size to the context.
+Now if that dimension happened to have the same value as the font size, Memoize
+would incorrectly pick up the ``font size extern'' instead of producing a new
+one.
+
+It bears emphasizing that whatever you add to the context expression must be
+fully expandable, and also not merely declared as robust. So writing
+\code{\refmmz{context}=\cs{ref}\marg{key}}, for example, would be unwise, since
+it would not work as intended when package \pkg{hyperref} is loaded. (This
+package declares \refcmd{ref} as robust, so it won't expand to the
+cross-reference value.) You have to look up where the cross-references are
+stored internally; the cross-reference for \meta{key} turns out to be stored in
+the internal control sequence |\r@|\meta{key}, so it is |\csname
+r@|\meta{key}|\endcsname| that the \refmmzauto{ref} handler actually appends to
+the context.
+
+The padding and font-size contexts are useful quite generally. However, the
+context can be pretty command-specific, as well. Consider the \pkg{skak}
+package used for typesetting chess games. The board is drawn using command
+|\showboard|, but this command has no arguments, because it draws the state of
+the board that is reached by the moves given by command |\mainline|. Memoizing
+|\showboard| as such will therefore yield the wrong result --- all the boards
+will be one and the same board! The solution is to provide the correct
+context: we dig into the \pkg{skak} sources and realize that the current
+board is stored in macro |\csname chessgame.skak.mainline\endcsname|.
+
+\ExampleName{skak}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.48,
+ comment={
+ \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in,scale=0.45}\quad
+ \includeexamplepdf[extern page]{page=2,trim=1in 1in 1in 1in,scale=0.45}
+ }
+}
+
+If you remove \code{\refmmz{context}=\bracestt{...}} from the code above, you
+will end up with a document where the final board drawn takes place of all the
+boards. This is so because in that case, all externs are written into the same
+file, so the final extern overwrites the previous ones, but note that you will
+only observe this after the second compilation, when the externs are actually
+used.
+
+
+
+\subsection{More on redefinitions and stale externs}
+\label{sec:tut:redefinitions}
+
+In this subsection, we elaborate on an issue touched upon at the beginning of
+section~\ref{sec:tut:working-on-a-picture}: what happens if the memoized code
+depends on some macro or style which gets redefined? The answer was
+``nothing,'' and one solution was to \refmmz{recompile} the code. Let us take
+the example from that section a bit further. We will propose no new solution
+or workaround, but deepen our understanding of the issue.
+
+\ExampleName{redefinitions}
+\makeexample{\examplename.pdf N=6}
+\tcbset{
+ recompile step/.style={
+ sidebyside, lefthand ratio=0.74, title=,
+ comment={\includeexamplepdf[blankest][\examplepath.c\theenumi.pdf]{#1}},
+ /utils/exec={\addtocounter{enumi}{1}},
+ enhanced, overlay app={\node[at=(frame.north west), font=\scriptsize, circle, fill=black!80!white, text=white, inner sep=1pt]{\theenumi};},
+ },
+}
+\begin{tcboxedraster}[raster columns=1]{%
+ title=Working on \texttt{\examplename.tex}, enhanced, breakable}
+ \setcounter{enumi}{0}%
+ \tcbox[blankest]{I like red. My emphasized nodes will have red background.}
+ \tcbinputexample[.tex][.c1]{recompile step={page=2}}
+ \tcbox[blankest]{Hmm, this particular node is really important,
+ let me put the text in italics as well!}
+ \tcbinputexample[.tex][.c2]{recompile step={page=2}, no attachment}
+ \tcbox[blankest]{You know what? Perhaps yellow background would work better
+ --- in general.}
+ \tcbinputexample[.tex][.c3]{recompile step={page=1}, bad, no attachment}
+ \tcbox[blankest]{How come my node is still red?! Oh yes, I changed the
+ style, so I have to recompile the extern!}
+ \tcbinputexample[.tex][.c4]{recompile step={page=2}, no attachment}
+ \tcbox[blankest]{Ahh, yellow background, that's much better. But you know
+ what, this double emphasis won't do after all, let me go back to the
+ upright shape.}
+ \tcbinputexample[.tex][.c5]{recompile step={page=1}, bad, no attachment}
+ \tcbox[blankest]{Red???!???!? Ok, I know that recompiling will help, but what
+ happened here?}
+ \tcbinputexample[.tex][.c6]{recompile step={page=2}, no attachment}
+\end{tcboxedraster}
+
+What happened is that the externs from steps~1 and~5 share the very same code.
+In step~1, this code was compiled when the red |emph| style was in effect, and
+that extern lingered and was eventually picked up again in step~5, Memoize
+having no idea that it is including an extern produced with the obsolete
+definition of the style.
+
+There are two points to this story. First (and forgetting for a moment about
+the context, which we started discussing in
+section~\ref{sec:cross-referencing}), Memoize identifies externs (and memos) by
+the code that produced them --- or more precisely, by the MD5 sum of the code,
+as each piece of code has a unique (well, unique enough) MD5 sum. Each extern
+is saved in a file whose name contains this MD5 sum; see
+section~\ref{sec:tut:memodir} for illustration. Generally, this is a very
+useful feature. You can move your picture to another location in the document,
+insert some other (externalized) picture in front of it, and so on, all without
+triggering recompilation of the extern(s). (None of this is possible with
+\TikZ's externalization library, which identifies the externs by the order in
+which they appear in the document.)
+
+The downside of the MD5 sum approach is the potential pitfall illustrated
+above, and the downside comes about because of the second point of the story:
+Memoize does not attempt to delete the ``old'' externs. (However, as described
+in section~\ref{sec:tut:memodir}, stale memos and externs can be easily removed
+using the \refscript{memoize-clean.pl} script.) That would be not only
+dangerous (as any deletion inherently is) but also potentially wasteful: what
+if you have only temporarily removed some code, or compiled only a portion of
+the document --- you surely wouldn't want your hard-won externs to disappear in
+such a situation!
+
+The pitfall described above applies to any command which depends on parameters
+which can be set prior to the invocation of the command, like \TikZ pictures,
+which depend on the settings given in \cs{tikzset}. After customizing the
+settings, you will have to recompile the externs:
+\refcmd{mmznext}\braces{\refmmz{recompile}} is useful when you only have to
+recompile a single extern; use \refcmd{mmzset}\braces{\refmmz{recompile}}, or
+the package option \refmmz{recompile}, to recompile all externs in the
+document; and there is also the middle road: if you have changed only Forest's
+settings, you can write
+\code{\refmmz{auto}=\braces{forest}\braces{\refmmz{recompile}}} to recompile
+all and only the Forest trees.
+
+Above, we have seen the ``same code, same extern'' issue manifested ``through
+time,'' i.e.\ Memoize was (incorrectly) reusing externs produced in previous
+compilations, but the issue can also manifest ``through space.'' This can
+happen if the same code appears twice in the same document --- but, crucially,
+with some parameters which it depends on changed from one occurrence to the
+next. Observe what happens in the following example, where the settings for
+|\progressbar| are changed by |\progressbarchange|. After the first
+compilation, everything looks fine. But as both extern pages were produced by
+the same code, they will be stored into the same file, the second one
+overwriting the first one. The second compilation pulls in the externs --- or
+rather, the single extern --- resulting in the document containing the second
+progressbar in the place of the first one as well.
+
+\ExampleName{progressbar}
+\makeexample{\examplename.pdf N=2}
+\tcbinputexample{
+ bad, float,
+ comment={
+ \begin{tcbitemize}[raster columns=3,raster equal height,halign=center,valign=center]
+ \tcbitem[title=After 1\textsuperscript{st} compilation]
+ \includeexamplepdf[extern page,remember as=extern1]{page=1,trim=1in 1in 1in 1in}\\
+ \includeexamplepdf[extern page,remember as=extern2]{page=2,trim=1in 1in 1in 1in}\\
+ \includeexamplepdf[document page]{page=3}
+ \tcbitem[title=After extern extraction\vphantom{p\textsuperscript{nd}}]
+ \includeexamplepdf[my boxed title=the extern file,attach shifted boxed title to top right,remember as=externfile]{page=2,trim=1in 1in 1in 1in}
+ \tcbitem[title=After 2\textsuperscript{nd} compilation]
+ \includeexamplepdf[document page,remember as=doc][\examplepath.c2.pdf]{page=1}
+ \end{tcbitemize}
+ \begin{tikzpicture}[remember picture,overlay]
+ \draw[->, thick, red] (extern1.east) to[out=east, in=west] ([yshift=0.5ex]externfile.west);
+ \draw[->, thick, red] (extern2.east) to[out=east, in=west] ([yshift=-0.5ex]externfile.west);
+ \draw[->, thick, blue] (externfile.east) to[out=east, in=west] (doc.west);
+ \end{tikzpicture}
+ },
+}
+
+The same ``extern duplication'' can arise due to how a particular command is
+implemented. Say we deactivate automemoization of Forest trees
+(\code{\refmmz{deactivate}=forest}), but keep on automemoizing \TikZ pictures.
+Forest uses \refenv{tikzpicture}\noprint{\refenv{forest}} under the hood (a
+lot); in particular, the tree itself is typeset as a \env{tikzpicture}
+environment. But the code that typesets it is the same for all trees,
+regardless of their content (the actual content of the tree is hidden in
+various macros and boxes, rather than ``pasted'' into the \env{tikzpicture}).
+Consequently, the final tree of the document will overwrite all other trees in
+the document, just as the second (and thus final) progress bar overwrote the
+first one above.\footnote{That is assuming that \hologo{TeX} doesn't simply
+ spew a bunch of errors. This can happen as well. In the interest of full
+ disclosure, compiling a Forest tree in the situation described above would
+ actually also produce --- but only in the first compilation --- a number of
+ small empty extern pages, one for each node of the tree. A promise: Forest
+ will soon fully support Memoize and (among other things) avoid this pitfall.
+ But the principle will remain.} Ouch!
+
+Generally speaking, this final sort of extern duplication issue can arise
+whenever we have an ``outer'' command that we don't want to (auto)memoize which
+uses an ``inner'' command that we \emph{do} want to automemoize. The solution
+is to use the \refmmz{auto} key \refmmzauto{nomemoize} on the outer command;
+remember that this key disables memoization for the space of the command or
+environment. For example, the correct way to ``deactivate'' automemoization of
+\env{forest} environments (but keep automemoizing \TikZ pictures) is
+\code{\refmmz{auto}=\bracestt{forest}\braces{\refmmzauto{nomemoize}}}.
+
+
+
+
+\subsection{Supporting Memoize in your package}
+\label{sec:tut:package}
+
+\subsubsection{Loading Memoize?}
+\label{sec:loading-memoize}
+
+So you want to support Memoize in your package? That's great!
+
+What form precisely this support will take of course depends on your package.
+For some commands, a simple \refmmz{auto} declaration will suffice; for other
+commands, you might need to write a dedicated \emph{memoization driver}, as
+explained in section~\ref{sec:memoization-drivers}. However, one thing is
+clear: you \emph{don't} want to require Memoize's presence by
+\cs{RequirePackage}\braces{\refpkg{memoize}} in your package. That would
+trigger memoization, but triggering memoization should be left at the sole
+discretion of the author. The question is, if you're not allowed to load
+Memoize, how can you even issue the \refmmz{auto} declaration?
+
+Well, it's not that you really want to \emph{memoize} anything; you want to
+make the commands of your package \emph{memoizable}. So:
+\cs{RequirePackage}\braces{\Emph{\refpkg{memoizable}}} --- and note that in
+`memoizable', the final `e' of `memoize' is dropped, apparently this is the
+correct way to spell it.
+
+Loading \refpkg{memoizable} does nothing if Memoize is already loaded, and
+behaves like package \refpkg{nomemoize} otherwise --- remember from
+section~\ref{sec:tut:final} that \refpkg{nomemoize} is a dummy package which
+accepts all the commands that Memoize does, but does nothing.
+
+I have decided to require that Memoize must be loaded before any package that
+supports it. Allowing for an arbitrary loading order would complicate the
+implementation (and possibly even turn out to be problematic), and furthermore,
+Memoize likes to be loaded early anyaway, because it needs to be loaded before
+the document PDF is opened if it is to perform the embedded extern extraction.
+I don't think the ordering requirement will cause any problems --- let me know
+if it does! --- but perhaps it is wise to inform the author about it in the
+documentation of your package (I did so at the end of
+section~\ref{sec:tut:automemoization}). Anyway, I have enforced the
+requirement by raising an error and refusing to load the package in case
+Memoize detects \refpkg{memoizable} to be loaded.
+
+Note that the loading order requirement implies that you can use
+|\@ifpackageloaded{memoize}| to specifically react to the presence Memoize, if
+necessary.
+
+
+\subsubsection{Memoizable design}
+\label{sec:memoizable-design}
+
+Many commands and environments can be submitted to externalization with a
+single-line \refmmz{auto} declaration, as illustrated in
+section~\ref{sec:tut:automemoization}, perhaps requiring an addition to the
+context (section~\ref{sec:cross-referencing}), or some pre- or post-memoization
+code (section~\ref{sec:tut:beamer}). In some situations, however, these simple
+approaches won't work. Most often, this will happen when the extern must be
+integrated into the document in some special way. For example, a command might
+internally create floating material, or surround the core typeset material with
+some stretchable space.\footnote{Commands and environments of package
+ \pkg{tcolorbox} exhibit both these issues (see \pkg{tcolorbox} options |float|,
+ |before| and |after|), and were in fact the inspiration for several technical
+ details of Memoize.} None of these behaviours can be replicated by merely
+including the extern; with respect to the stretchable space, remember that an
+extern, being a picture, has fixed size, so if our extra space ended up in the
+extern, it would lose the stretchability.
+
+The key to successful memoization of problematic commands is their design. In
+a nutshell, the idea is to \emph{break up the command's definition into two
+ parts, the outer command and the inner command, and only submit the inner
+ command to automemoization}. We will illustrate this with a simple
+environment --- |poormansbox| --- which produces a potentially framed box of
+the given width, and surrounds this box with some configurable material --- by
+default, this material will be stretchable vertical space, and this will be the
+source of our memoization problem. (In terms of user experience, the solution
+in this section will leave something to be desired, but we will revisit the
+example in section~\ref{sec:memoization-complex-single-driver} and make things
+right.)
+
+Let us first take a look at a document using our to-be-developed box
+environment. The |poormansbox| environment takes one optional argument, a
+keylist of options, which can also be set with the |\pmbset| command. This
+being a \textbf{p}oor \textbf{m}an's \textbf{b}ox, it doesn't recognize many
+options. One can set the |width| of the box, or request that it occurs in a
+|frame|, and the surrounding material can be configured using keys |before| and
+|after|. As we will see later in the listing of the package, the box is
+|\linewidth| wide by default, has no frame, and is surrounded by vertical glue
+|\vskip 2ex plus 1ex minus 1ex| (|2ex| of natural vertical space which may both
+stretch and shrink for |1ex|); furthermore, the default value of |before|
+contains |\centering| to center the box horizontally (centering is of course
+only observable when we change the width of the box).
+
+\ExampleName{poormansbox}
+\makeexample{\examplename.sty}
+\makeexample{\examplename.pdf}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.482,
+ comment={\centering
+ \includeexamplepdf[document page,left=0pt,right=0pt]
+ {page=1,scale=0.5,trim=0mm 3mm 0mm 3mm}
+ },
+}
+
+You might want to play with the example to see that the surrounding vertical
+space is indeed stretchable. The example is set up so that the surrounding
+space is shrunk a bit to fit all the material onto one page. But if you remove
+the final |\lipsum[144]|, the natural amount of all vertical space can be
+accommodated on the page, so you should observe an increase of vertical
+spacing.
+
+You might have noticed that the example contains nested |poormansbox|es: the
+second box (the one which contains |\lipsum[66]|) is nested within the first
+one (between |\lipsum[101]| and |\lipsum[75]|). This is intentional: when we
+will revisit the |poormansbox| example in
+section~\ref{sec:memoization-complex-single-driver}, the implementation will
+have to pay special attention to nesting (which presents no problem to the
+implementation in this section).
+
+As you can see in the package listing below (\texttt{\examplename.sty}), the
+implementation of our environment is straightforward. We first define the
+configuration command |\pmbset| and the option keys (we're using
+\pkg{pgfkeys}), and set the option defaults. Then, we move on to the
+environment itself: we apply the given options, execute the pre-code, typeset
+the box (which is a |minipage| of the given width, potentially wrapped in a
+|\fbox|), and execute the post-code.
+
+\tcbinputexample[.sty]{listing only, float}
+
+\ExampleName{poormansbox-memoizable}
+Now let's make our |poormansbox| externalizable (\texttt{\examplename.sty}). As
+announced above, the idea is to split the definition of the environment into
+the outer part (below, the user-level environment |poormansbox|), which
+(applies the options and) executes the pre- and the post-code, and the inner
+part (below, the macro |\@poormansbox|), which typesets the actual box. If we
+then then submit |\@poormansbox|, rather than |poormansbox|, to
+automemoization, the outer part will be executed at every compilation (giving
+us stretchable space if we request it), while the inner command will be
+executed (and memoized) at the first compilation, and substituted for the
+extern (the fixed-size box) at subsequent compilations.\cprotect\footnote{You
+ might have wondered why our definition of the |poormansbox| environment grabs
+ the body into an argument (|+b|, yielding |#2|), necessitating the use of
+ |\NewDocumentEnvironment| over the venerable |\newenvironment|. One reason
+ was that having the environment body as an argument simplifies wrapping the
+ |\fbox| around the |minipage|, but there is a more important reason. If we
+ did not grab the environment body, we would have to implement the internal
+ part of the definition as an environment (|@poormansbox|) as well, and embed
+ it into the user-level environment using the following idiom:
+ |\newenvironment{poormansbox}[2][]{...\begin{@poormansbox}}{\end{@poormansbox}...}|.
+ However, as illustrated in section~\ref{sec:tut:good-to-know}, automemoizing
+ an environment indirectly embedded in such a way produces an error, because
+ Memoize is prevented from collecting the environment body.}
+
+\makeexample{\examplename.sty}
+\makeexample{\examplename.pdf}% just to know if it compiles fine
+\tcbinputexample[.sty]{listing only, float}
+
+Looking at the definition of the internal |\@poormansbox| command, it might
+strike you as weird that we have equipped this command with an optional
+argument (|#1|) it never uses. However, this optional argument is crucial for
+memoization. It will become a part of the memoized code (note
+\code{\refmmzauto{args}=om} in the \refmmz{auto} declaration) and thereby
+ensure that Memoize will produce separate externs for invocations of
+|\@poormansbox| with the same environment body but different options; or in
+other words, it will ensure that changing the options recompiles the
+extern.\cprotect\footnote{Of course, this only holds for options given in the
+ optional arguments; if the user changes an option value using a prior
+ \cs{pmbset} (and that option does not occur in the optional argument),
+ Memoize won't detect the change. But the end-user knows about this issue, as
+ it was addressed in sections~\ref{sec:tut:working-on-a-picture}
+ and~\ref{sec:tut:redefinitions}, and she is also aware of two workarounds:
+ manual recompilation, or setting the context
+ (section~\ref{sec:cross-referencing}).
+
+ While we're on the subject of the context, note that it is also possible to
+ deploy context to trigger recompilation of the inner command upon change of
+ parameters it depends on. We could simply omit the optional argument of
+ \cs{@poormansbox} and add
+ \refmmz{context}|={width=\pmb@width,frame=\ifpmb@frame true\else false\fi}|,
+ to the \refmmz{auto} declaration. The advantage of such an approach is that
+ Memoize reacts to the change of parameters regardless of whether they are set
+ using the optional argument or \cs{pmbset}. However, the approach is
+ unfeasible for commands depending on many parameters: can you imagine listing
+ all the \TikZ options in the context? Not to mention that a particular
+ picture usually only depends on a small subset of these options --- by and
+ large, \TikZ externs would get recompiled too often if the context contained
+ all \TikZ options.}\footnote{I have toyed with the idea of
+ splitting (using \pkg{pgfkeys} key filtering) the given options into outer
+ options, relevant for the outer command, and inner options, relevant for the
+ inner command, and only passing the inner options to the inner command. The
+ thought was that would (i) avoid recompiling the extern when only outer
+ options change, as these options don't affect the inner command, and (ii)
+ avoid applying the inner options when utilizing the extern, as these options
+ don't affect the outer command. However, it then hit me that the end-user
+ might define a style which incorporated both inner and outer options --- I
+ know I do this with my |tcolorbox|es.}
+
+The downside to automemoizing an internal command is that this might be
+counter-intuitive for the author. For example, to deactivate automemoization
+of |poormansbox|, the author will have to write
+\refcmd{mmzset}\bracestt{\refmmz{deactivate}=\cs{@poormansbox}} (note the
+|\@|), but they will have no clue they have to do this unless they have
+carefully read |poormansbox|'s documentation. Even worse, the above
+\refcmd{mmzset} command will not work unless surrounded by |\makeatletter| and
+|\makeatother|, as it refers to an internal control sequence containing |@|.
+Well, Memoize offers \refmmz{auto csname}, \refmmz{activate csname} and
+\refmmz{deactivate csname}, so that |@| catagory code manipulations can be
+omitted by writing \refcmd{mmzset}\bracestt{\refmmz{deactivate
+ csname}|=@poormansbox|}, but still.
+
+Another downside could occur when you use the same (automemoized) internal
+command in service of several user interface commands. For the sake of
+illustration, assume we have also defined an UI-macro |\pmb| which again relies
+on |\@poormansbox|. How is the author to deactivate automemoization of |\pmb|
+but leave the |poormansbox| environment intact? This is how:
+\refcmd{mmzset}\bracestt{\refmmz{auto}=\cs{pmb}\bracestt{\refmmzauto{args}=m,
+ \refmmzauto{nomemoize}}}. Again, counter-intuitive; the author expects
+\refcmd{mmzset}\bracestt{\refmmz{deactivate}=\cs{pmb}} to work.
+
+One other consequence of this approach is that the code included in the c-memo
+(if \refmmz{include source in cmemo} is in effect) will not faithfully reflect
+the source: as shown in the c-memo listing below, it will contain
+|\@poormansbox{...}| instead of |\begin{poormansbox}...\end{poormansbox}| ---
+even if this might actually count as an advantage, as the discrepancy will at
+least inform the author who refuses to read the fine material accompanying our
+|poormansbox| that something funky is going on.
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCMemo#1{% fetch the last c-memo filename
+ \def\mycmemo{#1}%
+}
+\input{\examplepath.mmz.c1}
+\sed{%
+ s/[]]\lbrace/]\n\space\space\space\space\space\space\space
+ \space\space\space\space\space\space\space\lbrace/;
+}{\exampledir\mycmemo}
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\mycmemo,
+ example title,
+ title=the c-memo of the last \texttt{poormansbox} environment,
+ left=0.5em, right=0em,
+}
+\endgroup
+
+In a nutshell, automemoizing an internal command might be counter-intuitive for
+the author. But the core idea --- to support memoization of a resistant
+command by splitting its definition into the outer and the inner command --- is
+sound, and we will elaborate on this idea in
+section~\ref{sec:memoization-complex-single-driver}, where we will revisit our
+|poormansbox| example and develop a variant of this environment which is both
+memoizable and user-friendly.
+
+
+\section{Under the hood}
+\label{sec:under-the-hood}
+
+This chapter is written for three audiences: a curious user who wants to
+know how Memoize does what it does; a package writer who wants to support
+Memoize in a tricky situation; and myself, lest I forget why I made the design
+decisions that I made.
+
+\subsection{The entry point}
+\label{sec:Memoize}
+
+
+From the author's perspective, the functionality of this package is entered
+either through the manual memoization commands (macro \refcmd{mmz} and
+environment \refenv{memoize}), or via automemoization. And while that is
+correct, those user interface entry points merely determine what code is
+submitted to memoization, and set any options specific to the upcoming
+memoization. The real fun starts with command \Emph{\refcmd{Memoize}}, which
+is eventually executed by both manual and automatic memoization.
+
+Not every call to \refcmd{Memoize} results in memoization. Calling this macro
+has three possible outcomes. It can result in \emph{memoization}, which
+produces the memos and externs; in \emph{utilization} of the result of an
+earlier memoization (which boils down to inputting the memos); or in
+\emph{regular compilation}, whereby the code is compiled
+(almost)\footnote{\label{fn:regular-compilation-almost}This is absolutely true
+ for memoized code which is ``contained'' in the sense of not peeking into the
+ input stream following the memoized code. In general, code which fails to
+ satisfy this containment requirement is most likely simply not memoizable;
+ but there are borderline cases. For example, \refcmd{ignorespaces} at the
+ end of some code will have the expected effect in the absence of Memoize, but
+ no effect when executed either during memoization or regular compilation
+ under Memoize, simply because it will hit some code belonging to Memoize
+ rather than the continuation of the document. Memoize offers the
+ \refmmz{ignore spaces} provision to work around this specific problem.} as if
+Memoize was not there. Which outcome obtains depends on several factors. The
+decision logic is depicted below, and note that you can \refmmz{trace} the
+action on the terminal.
+
+\begin{center}
+ \begin{forest}
+ yes/.style={edge=->,edge label={node[font=\scriptsize,pos=0.4,left,#1]{yes}}},
+ no/.style={edge=->,edge label={node[font=\scriptsize,pos=0.4,right,#1]{no}}},
+ use/.style={content=utilization\\(of the cc-memo)\vphantom{dj},fill=orange,align=center},
+ memoize/.style={content=memoization\vphantom{dj},fill=green},
+ compile/.style={content=regular compilation\vphantom{dj},fill=emphcolor},
+ for tree={
+ l sep*=1.5,
+ if n children={0}{}{align=center},
+ child anchor=north,
+ },
+ [Is Memoize enabled?\\(\refcmd{ifmemoize}),
+ [Are we currently undergoing memoization?\\(\refcmd{ifmemoizing}), yes
+ [,compile, yes]
+ [Is the\\\refmmz{recompile}\\mode in effect?, no
+ [,memoize, yes]
+ [Do the relevant\\memos and externs exist?, no
+ [,use, yes]
+ [Is the\\\refmmz{readonly}\\mode in effect?,no
+ [,compile, yes]
+ [,memoize, no]
+ ]
+ ]
+ ]
+ ]
+ [,compile, no]
+ ]
+ \end{forest}
+\end{center}
+
+As the memoization options were already set by the user interface entry points,
+you might expect, quite reasonably, that \refcmd{Memoize} takes a single
+argument, the code submitted to memoization. After all, what more does it
+need? Clearly, executing this code is what produces the typeset material, and
+to detect whether the code has ``changed'' (in order to recompile the memos and
+externs), we compute the MD5 sum of this very code, don't we? Well, the
+reality is a bit more complicated. When it comes to automemoized commands, the
+code which the MD5 sum is computed off of (and which is displayed in the c-memo
+if \refmmz{include source in cmemo} is in effect) is not exactly the same as
+the code we compile (during either memoization or regular compilation). We'll
+see what the difference is in section~\ref{sec:tut:automemoization-details};
+what matters here is that we must provide \refcmd{Memoize} with both and that
+this macro therefore takes two arguments: the \emph{identification code}, which
+the MD5 sum is computed off of, and the \emph{executable code}, which, well, is
+the code that gets executed during memoization (or regular compilation).
+
+Let's illustrate this with an example which is probably entirely useless (but
+don't worry, we'll get to a realistic example in
+section~\ref{sec:tut:automemoization-details}). We first memoize some text
+manually, using command \refcmd{mmz}, and then do something very stupid: we use
+this very text as the identification code for the following \refcmd{Memoize},
+even if the executable code of that command is completely different. The
+second line of the typeset output should convince you that the first argument
+to that command was really used to produce the extern; and one further
+compilation should convince you that the first argument was indeed used to
+identify the extern: the extern produced by \refcmd{mmz} was overwritten by the
+extern produced by \refcmd{Memoize}, in the fashion of the |progressbar|
+example from section~\ref{sec:tut:redefinitions}.
+
+\ExampleName{memoize-internal}
+\makeexample{\examplename.pdf N=2}
+\tcbinputexample{
+ comment={%
+ \includeexamplepdf[document page,
+ after title pre={\ (after the first compilation)}
+ ]{page=3}\hfill
+ \includeexamplepdf[document page,
+ after title pre={\ (after the second compilation)}
+ ][\examplepath.c2.pdf]{page=1}
+ },
+}
+
+The example above also illustrates a(nother) peculiar feature of
+\refcmd{Memoize}. \refcmd{Memoize} does not open a new \hologo{TeX} group, but
+it \emph{expects a group to be opened prior to calling it}, as it will issue an
+|\endgroup| at some point. Specifically, the memoization group will be closed
+before regular compilation or utilization, but after memoization. If you want
+to know why, read the boxed text below.
+
+\begin{tcolorbox}[title=\string\Memoize\ and grouping, enhanced, breakable]
+ One important desideratum behind the design of Memoize was that using the
+ package should disrupt the original, Memoize-less compilation as little as
+ possible. In particular, if the memoized code contains local assignments
+ whose effect (in the original compilation) persists into the rest of the
+ document (until the end of the surrounding \hologo{TeX} group, of course),
+ wouldn't one want these local effects to persist when Memoize is around, as
+ well? Fortunately, most memoized code does not have persistent local effects
+ (at least for me, it is usually environments, like \env{tikzpicture}s, that I
+ want to memoize, and environments introduce a group anyway) --- fortunately,
+ because there are design reasons for enclosing memoization in a \hologo{TeX}
+ group (or two), and this enclosure will of course cancel the effect of local
+ assignments in the memoized code.
+
+ For one, the user interface memoization commands, such as \refcmd{mmz} and
+ automemoized commands, allow for options specific to a particular piece of
+ memoized code (the options given as the optional argument to manual
+ memoization, the next-options and the auto-options), and to delimit their
+ effect, it makes most sense to apply them in a group. I have toyed with the
+ idea of working around the introduction of a group by manually saving and
+ restoring all the options, but I quickly gave up on this line of thought.
+ For one, manually saving and restoring the options would be cumbersome and
+ error-prone, and probably also slower than using the group. But even worse,
+ all that work would not really solve the problem of the persistence of local
+ effects, because memoization itself introduces a group, as well: during
+ memoization, the typeset material is collected into a box, and opening a box
+ introduces a group. In some particular situations, this could be avoided by
+ typesetting the memoized code as-is and collecting the resulting material
+ using |\lastbox|, but this approach cannot work in general. In general,
+ memoization will take place in a group, so the issue of local effects must be
+ addressed in some other way. Memoize offers the following workaround: during
+ memoization, the memoized code can (globally) add code to the \refmmz{after
+ memoization} hook, which gets executed immediately after closing the
+ memoization group.
+
+ Does this mean it would be best if the user interface memoization commands
+ straightforwardly surrounded \refcmd{Memoize} by |\begingroup| and
+ |\endgroup|? For example, \refcmd{mmz} would open the memoization group, let
+ \refcmd{Memoize} do its work, and then close the group. Not really.
+ Remember that memoization is not the only possible outcome of calling
+ \refcmd{Memoize}. Perhaps we can at least retain the local effects of a
+ regular compilation, and of utilization?
+
+ We can, by finely tuning the timing of the memoization group closure within
+ \refcmd{Memoize}. This command is designed to close the memoization group
+ after memoization, but before regular compilation and utilization. Closing
+ the group after memoization makes sure that the given options are in effect
+ during this process. By closing the group prior to regular compilation,
+ regular compilation of the memoized code (which takes place when Memoize is
+ disabled, for example) is guaranteed to have (almost, see
+ footnote~\ref{fn:regular-compilation-almost}) exactly the same effect as the
+ compilation of that code in absence of Memoize; in particular, the effect of
+ any local assignments will persist into the rest of the document. Finally,
+ closing the group before utilization simplifies the construction of the memo
+ in the cases where we need to replicate local effects of the memoized code
+ --- the group closed, there is no need to smuggle local assignments out of a
+ memo.
+\end{tcolorbox}
+
+\subsection{Memos}
+\label{sec:memos}
+
+Up until now, we have pretended that there is a single kind of a memo file. In
+truth, there's two kinds: \emph{code memos}, or \emph{c-memos} for short; and
+\emph{code--context memos}, or \emph{cc-memos} for short. In this section, we
+will learn what they are for, and how they look like --- and also a bit on how
+they are produced, even if the details on that will have to wait until
+section~\ref{sec:memoization-drivers}.
+
+We will see that when Memoize utilizes memos, c-memos are processed first. But
+conceptually, cc-memos are more important, so we will start the discussion with
+these.
+
+\subsubsection{Cc-memos (and extern inclusion)}
+\label{sec:cc-memos}
+
+When it is input, a cc-memo replicates the effect of the memoized code. This
+includes the reproduction of its visual output, which takes the form of
+inclusion of any externs produced by memoization. And yes, you got the
+implication right: a cc-memo can have any number of associated externs,
+including zero, even if the most common case is that of exactly one extern per
+cc-memo. The number of externs mostly depends on the memoization driver (see
+section~\ref{sec:memoization-drivers}); the default driver always produces
+exactly one extern.
+
+A cc-memo is located in the directory given via subkey \refmmzpath{dir} (and
+\refmmzpath{relative}) of key \refmmz{path}. You can recognize it by its filename,
+which has the following form (\meta{prefix} is set via subkey \refmmzpath{prefix}):
+\begin{center}
+ \code{\meta{prefix}\meta{code md5sum}-\meta{context md5sum}.memo}
+\end{center}
+
+In fact, this is how Memoize recognizes --- or rather, searches for --- a
+cc-memo as well: Memoize will utilize a cc-memo when the code and the context
+MD5 sum computed during an attempted utilization match the code and the context
+MD5 sum computed during some previous memoization (for details on the context
+MD5 sum, see section~\ref{sec:c-memos}). In detail, a cc-memo is created at
+the end of memoization, at which point Memoize computes the MD5 sum of the
+memoized code and the MD5 sum of the context, and writes the results of
+memoization into the cc-memo identified by (the prefix and) these two MD5 sums.
+And when Memoize, on a subsequent compilation, encounters a piece of memoized
+code, it again computes the MD5 sum of that code and the MD5 sum of the
+context, and tries to input the cc-memo identified by (the prefix and) these
+two MD5 sums. If the inputting is successful, we have utilized the cc-memo
+(which in the typical case amounts to including the one associated extern); if
+the cc-memo cannot be found, Memoize starts the memoization process, which
+creates the memos and the externs.
+
+Let us take a look at the contents of a cc-memo in detail. Here's a typical
+cc-memo (it belongs to the titlepage penguin):
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCCMemo#1{% fetch the first cc-memo filename
+ \def\myccmemo{#1}%
+ \endinput
+}
+\input{\exampledir titlepage.mmz.c1}
+\sed{%
+ s/\cmd{quitvmode} \cmd{mmzIncludeExtern}/\cmd{quitvmode}\n\cmd{mmzIncludeExtern}/;
+ s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/;
+}{\exampledir\myccmemo}
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\myccmemo,
+ example title=\myccmemo,
+}
+\endgroup
+
+A cc-memo begins by listing the externs which the memo will (actually, might)
+attempt to include into the document. When the cc-memo is input, each
+\refcmd{mmzResource} command checks if the given extern exists. If some
+existence check fails, Memoize enters the memoization mode, same as if the
+cc-memo itself did not exist. If all the resources pass the existence check,
+Memoize inputs the core of the cc-memo, i.e.\ everything following the
+\refcmd{mmzMemo} marker.
+
+The core might contain arbitrary code, but most often, it will consist of only
+two commands. The first one is \refcmd{quitvmode} and it is included if the
+extern was \refmmz{capture}d into a horizontal box (which is the usual
+situation). The second one is \refcmd{mmzIncludeExtern}, and it is this
+command which actually includes the extern into the document upon inputting the
+cc-memo. The core code is executed without introducing any groups, i.e.\ the
+effect of any local assignments in the cc-memo will persist into the code
+following the memoized code.
+
+Command \refcmd{mmzIncludeExtern} takes nine parameters. The first is the
+sequential number of the extern associated with the cc-memo, starting with 0;
+usually, this is simply 0 as most memos are associated with a single extern.
+The second one is a \refcmd{hbox} or \refcmd{vbox}, noting the type of the box
+the memoized code was externalized into. The next three numbers are the
+expected width, height and the depth of the extern. Finally, we have the four
+\refmmz{padding} amounts (left, bottom, right and top). We should arrive at
+the expected size after trimming the extern PDF by the
+padding amounts; Memoize will complain if we don't.
+
+Let's look at a more interesting cc-memo. Using the advising framework,
+described in section~\ref{sec:tut:automemoization-details}, Memoize hacks
+\refcmd{label} to support \cs{label}s inside memoized code --- the following
+code ``just works.''
+
+\ExampleName{label}
+\makeexample{\examplename.pdf N=3}
+\tcbinputexample{
+ comment={\centering
+ \includeexamplepdf[document page, after title pre={\ (compilation 1)},
+ left=1.5mm, right=1mm]{page=2}\quad
+ \includeexamplepdf[document page, after title pre={\ (compilation 2)},
+ left=1.5mm, right=1mm][\examplepath.c2.pdf]{page=1}\quad
+ \includeexamplepdf[document page, after title pre={\ (compilation 3)},
+ left=1.5mm, right=1mm][\examplepath.c3.pdf]{page=1}
+ },
+}
+
+Everything seems normal --- after the first compilation, we get ``\textbf{??}''
+because the label has not made it into the |.aux| file yet, but in subsequent
+compilations, we learn where the penguin lives --- but it is far from normal
+under the hood. If we de-hacked \cs{label} by writing
+\refcmd{mmzset}\bracestt{\refmmz{deactivate}=\cs{label}}, the third compilation
+(and subsequent compilations) would revert to ``\textbf{??}''. Why would that
+happen? The memoized code containing the \cs{label}s is only executed in the
+first compilation; in the subsequent compilations, we're simply inputting the
+cc-memo, so the memoized code, including any \cs{label}s in contains, is not
+compiled, and the labels don't get into the |.aux| file anymore.
+
+The \cs{label} hack deploys Memoize's ability to put arbitrary code into the
+cc-memo. During memoization, the memoized code may add arbitrary code to
+register \refcmd{mmzCCMemo}, and the contents of this register at the end of
+the memoization form the free-form part of the cc-memo.\footnote{This is also
+ how the above-described code containing \refcmd{mmzIncludeExtern} gets into
+ the cc-memo. The code is produced by \refcmd{mmzExternalizeBox} and appended
+ to \refcmd{mmzCCMemo} by the default memoization driver
+ \refcmd{mmzSingleExternDriver}; see section~\ref{sec:memoization-drivers} for
+ details.} When the hacked \cs{label} is encountered during memoization, it
+appends \refcmd{mmzLabel}\marg{label name}\marg{current label value} to
+\refcmd{mmzCCMemo}, so this command winds up in the cc-memo. It is then a
+simple job for \refcmd{mmzLabel}, executed when the cc-memo is input at
+subsequent compilations, to temporarily store \meta{current label value} (i.e.\
+the contents of \refcmd{@currentlabel} at the time the \cs{label} was invoked) back
+into \cs{@currentlabel} and to execute \cs{label}\marg{label name}. In effect, any
+\cs{label} command contained within the memoized code is executed at every
+compilation, even if the memoized code itself is not compiled.
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCCMemo#1{% fetch the first cc-memo filename
+ \def\myccmemo{#1}%
+ \endinput
+}
+\input{\examplepath.mmz.c1}
+\sed{%
+ s/~//g;
+ s/\cmd{quitvmode} \cmd{mmzLabel}/\cmd{quitvmode}\n\cmd{mmzLabel}/;
+ s/\(\marg\)\cmd{mmzIncludeExtern}/\1\n\cmd{mmzIncludeExtern}/;
+ s/\(\cmd{mmzLabel}\) *\(\marg\marg\) */~\1\2~\space/g;
+ s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/;
+}{\exampledir\myccmemo}
+\tcbinputlisting{float,
+ listing only, right=1.5mm,
+ listing file=\exampledir\myccmemo,
+ example title=\myccmemo,
+}
+\endgroup
+
+We will continue the discussion of \refcmd{label} in section~\ref{sec:label+} using
+a funkier example.
+
+
+\subsubsection{C-memos (and context)}
+\label{sec:c-memos}
+
+As explained in the previous section, a cc-memo belonging to a piece of
+memoized code is identified by two MD5 sums: the MD5 sum of the memoized code,
+and the MD5 sum of the associated context. However, when Memoize encounters
+some code submitted to memoization, the context expression is not yet fully
+known, as it may be adjusted by the memoized code itself during memoization ---
+and this potential adjustment is crucial for \cs{ref} and friends to work as
+advertised (see section~\ref{sec:cross-referencing}). Upon being invoked,
+Memoize therefore cannot immediately attempt to input the cc-memo; it needs to
+first learn about the context adjustments. Here's where c-memos enter the
+picture: \emph{the primary job of a c-memo is to store the context adjustments
+ made by the memoized code}. Let's see how this works in detail.
+
+Same as cc-memos, c-memos are located in the directory given via subkey
+\refmmzpath{dir} (and \refmmzpath{relative}) of key \refmmz{path}. However, a c-memo
+belonging to some memoized code is identified by the MD5 sum of that code
+alone; its filename has the following form, where \meta{prefix} is again set
+via subkey \refmmzpath{prefix}:
+\begin{center}
+ \code{\meta{prefix}\meta{code md5sum}.memo}
+\end{center}
+
+The c-memo is created at the end of the memoization process. At that time, the
+context expression is fully known, as the memoized code was already processed.
+Even more, Memoize keeps track of both the state of the context expression
+prior to memoization, stored in token register \refcmd{mmzContext}, and of the
+\emph{additions} to the context expression made by the memoized code, which are
+stored in token register \refcmd{mmzContextExtra}. (Incidentally, key
+\refmmz{context} automatically adapts to the situation by appending to
+\refcmd{mmzContext} outside memoization and to \refcmd{mmzContextExtra} during
+memoization.) The complete context expression is the concatenation of the
+contents of these two registers, but it is only the context expression
+additions, i.e.\ the contents of \refcmd{mmzContextExtra}, which Memoize stores
+into the c-memo, with the idea that during subsequent compilations, the initial
+context (\refcmd{mmzContext}) will be set up again via ``normal'' compilation,
+while inputting the c-memo will restore the additions, jointly reconstructing
+the complete context expression associated with a piece of memoized code to
+what it was at the end of memoization.
+
+We can now complete the picture of a utilization attempt started in
+section~\ref{sec:cc-memos}. Memoize begins by trying to input the c-memo; this
+can be done as the c-memo can be identified based solely on (the MD5 sum of)
+the memoized code. If the c-memo does not exist, Memoize starts the
+memoization process, which will produce the memos and the externs. But if it
+does exist, inputting it reconstructs the context expression to the state at
+the end of memoization. Therefore, as the MD5 sum of the \emph{expansion} of
+the context expression \emph{at the end of memoization} is baked into the
+cc-memo filename, trying to load the cc-memo identified by (the prefix, the
+code MD5 sum and) the MD5 sum of the \emph{expansion} of the context expression
+\emph{at attempted utilization} will succeed precisely when the context
+remained unchanged from memoization to attempted utilization.
+
+All this might have sounded very complicated, but in the end, most c-memos are
+quite boring, the titlepage penguin's c-memo shown below being no exception. A
+c-memo starts with the \refcmd{mmzMemo} marker, which is always followed by a
+(global) assignment to token register \refcmd{mmzContextExtra}, holding the
+context expression additions. As promised, the c-memo below is boring: it
+assigns an empty token list to this register, leaving the context expression
+as-is. Next comes the free-form part of the memo. Below, it is boringly empty
+as well (just the percent sign), but in principle, it will contain any code
+gathered in register \refcmd{mmzCMemo} during memoization; see
+\ref{sec:per-overlay} for an example. A c-memo is concluded by an optional
+part consisting of the \refcmd{mmzSource} marker, followed by the memoized
+code. The source code section is not used by Memoize in any way and can be
+switched off by \code{\refmmz{include source in cmemo}=false}; it is included
+by default so that an interested user can know which code produced which memo,
+which can be useful if one wants to trigger recompilation of an extern by
+deleting the corresponding memo. Incidentally, any newlines in the source code
+are lost in the c-memo replica (unless \refmmz{verbatim} is in effect), but we
+will only see this once we arrive at the \pkg{beamer} example below.
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCMemo#1{% fetch the first c-memo filename
+ \def\mycmemo{#1}%
+ \endinput
+}
+\input{\exampledir titlepage.mmz.c1}
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\mycmemo,
+ example title=\mycmemo,
+}
+\endgroup
+
+A c-memo of code containing a cross-reference will prove more interesting. The
+following c-memo was produced by the |ref| example from section
+\ref{sec:cross-referencing}. As we know from that section, when a \refcmd{ref} (as
+hacked by Memoize's \refmmzauto{ref} key) occurs in some memoized code, it
+appends the cross-reference to the context. In the c-memo below, this is
+reflected by the (global) assignment of an expression containing the
+cross-reference macro to token register \refcmd{mmzContextExtra}, holding
+the context expression additions.
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCMemo#1{% fetch the first c-memo filename
+ \def\mycmemo{#1}%
+ \endinput
+}
+\input{\exampledir ref.mmz.c1}
+\sed{%
+ s/~//g;
+ s/\cmd{global}.*\marg/~\0~/;
+}{\exampledir\mycmemo}
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\mycmemo,
+ example title=\mycmemo,
+}
+\endgroup
+
+
+\subsubsection{More on \texorpdfstring{\cs{label}}{\textbackslash label}}
+\label{sec:label+}
+
+A \refcmd{label} inside memoized code works out of the box in the usual situation
+when label value is fully determined by the memoized code, as in the example in
+section~\ref{sec:cc-memos}, where the memoized code contained the outermost
+(and only) \env{enumerate} environment. However, the out of the box approach does
+not work if the label value is (fully or partially) determined outside the
+memoized code. To illustrate the problem, and some potential solutions, we
+define two very simple enumeration environments, |listi| and |listii|, which
+use counters |counti| and |countii|, and which are intended as the outer and
+the inner environment, respectively. Our interest here is in the inner
+environment, |listii|. While it prefixes each item by an indented
+|\thecountii)|, the label is a composite of both counters:
+|\thecounti\thecountii|. The label is stored into \refcmd{@currentlabel}, so
+referencing works as usual. However, problems arise when we automemoize the
+inner environment.
+
+\ExampleName{label+}
+\makeexample{\examplename.tex.c1 N=6}
+\makeexample{\examplename.pdf N=2}
+\tcbinputexample{
+ sidebyside, lefthand ratio=0.53,
+ comment={\centering\includeexamplepdf[document page][\examplepath.c2.pdf]{page=1}},
+}
+
+While the result looks fine at first, changing the order of |listii|
+environments, for example by moving ``pets'' below ``domestic'', will result in a
+problem: the reference at the bottom will remain unchanged. This is so because
+the reference text is baked into the cc-memo, as shown below.
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCCMemo#1{% fetch the first cc-memo filename
+ \def\myccmemo{#1}%
+ \endinput
+}
+\input{\examplepath.mmz.c1}
+\sed{%
+ s/~//g;
+ s/\cmd{mmzLabel} \marg\marg/~\0~/;
+ s/\(\marg\)\(\cmd{mmzIncludeExtern}\)/\1 \2/;
+ s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/;
+}{\exampledir\myccmemo}
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\myccmemo,
+ example title=\myccmemo,
+}
+\endgroup
+
+How can we remedy this? The manual option is to force the recompilation of the
+extern by putting an (invisible) reference to the outer item into the inner
+item: add |\label{item:pets}| to item ``pets'' and refer to it at ``dog'' by
+\refcmd{mmzNoRef}|{item:pets}|.%
+\attachexample[\examplename mmzNoRef.tex][\examplepath.tex.c3.attachment]
+
+An automatic variant of the recompilation solution is to add \cs{@currentlabel}
+to the context upon memoizing |listii|. This can be achieved by adding
+\refmmz{context}|={@currentlabel={\csuse{@currentlabel}}}| to the \refmmz{auto}
+declaration for |listii|. The downside of this approach is that every |listii|
+will get reexternalized upon movement, whether it actually contains a label or
+not.\attachexample[\examplename context.tex][\examplepath.tex.c4.attachment]
+
+In fact, given that the externs produced by the inner environment do not
+contain the value of the outer counter, it seems wasteful to recompile any
+extern just to change the reference. And indeed, it is possible to avoid this,
+but the approach unfortunately requires adapting the inner environment code
+(and this is why I have not illustrated the problem using an environment of an
+elaborate package like \pkg{enumitem}). The idea is to ``unbake'' the
+reference to the outer item in the cc-memo. We can achieve this by changing
+|listii| to define \cs{@currentlabel} to be |\unexpanded{\thecounti}\thecountii|.
+Under this definition, the cc-memo will contain |\mmzLabel
+{item:dog}{\thecounti a}|, and rearranging |listii| environments will produce
+(upon two compilations, of course) the correct reference without recompiling
+the extern. Note again, however, that this solution can only work when the
+value of the outer counter does not appear in the extern, i.e.\ it would not
+work the ``dog'' item was prefixed by |1a)| rather than simply |a)|. In those
+cases, one should deploy one of the other solutions.%
+\attachexample[\examplename listii.tex][\examplepath.tex.c5.attachment]
+
+The final solution, presented below, is an elaboration on the second one.
+Rather than append \cs{@currentlabel} to the context immediately upon beginning
+to memoize environment |listii|, we will at that point redefine \cs{label} to do
+that. In effect, changing the location of |listii| will only recompile it if
+it contains a \cs{label}.
+
+At announced, we redefine \cs{label} once the memoization of |listii| begins,
+so within \refmmz{at begin memoization}.\footnote{Another generally good
+ location for such redefinitions is among the auto-options of |listii|. We
+ could include an \refmmz{auto}\cs{label}\marg{...} there, or a |/utils/exec|
+ with \refcmd{AdviceSetup}. However, in this particular case this would be
+ wasteful, as it would be applied regardless of whether memoization will take
+ place or not, whereas we only need the redefined \cs{label} when memoizing.}
+However, we do not redefine \cs{label} directly, as Memoize advises this
+control sequence out of the box (see
+section~\ref{sec:tut:automemoization-details} for details). What we redefine
+is the command which the advising framework executes instead of \cs{label} ---
+its so-called \refmmzauto{outer handler} --- and we do this by calling
+\refcmd{AdviceSetup}, the low-level variant of the familiar key
+\refmmz{auto}.\footnote{We could have also used \refmmz{auto}, but we don't,
+ because (a) \refcmd{AdviceSetup} is faster, (b) it is easier to prepend
+ material to a handler using the low-level interface, and (c) I wanted to
+ showcase \refcmd{AdviceSetup}.} The first argument of \refcmd{AdviceSetup}
+is the installation path (|/mmz|), the second one the command or environment we
+are submitting to the framework (\cs{label}), and the third one the setup
+\emph{code} --- here lies the biggest difference between \refmmz{auto} and
+\refcmd{AdviceSetup}: the former expects a keylist, and the latter \hologo{TeX}
+code which directly manipulates settings macros like
+\refcmd{AdviceOuterHandler} (for the full list, see
+section~\ref{sec:tut:automemoization-details} or~\ref{sec:ref:advice}).
+
+\tcbinputexample[.tex][.c6]{listing only, float,
+ attachment name=\examplename auto.tex,
+}
+
+Within \refcmd{AdviceSetup}, we prefix (using macro \cs{preto} of package
+\pkg{etoolbox}) the original outer handler \refcmd{AdviceOuterHandler} by code
+which causes \cs{outerlabeltocontext} to be executed at the end of memoization
+(by globally appending this macro to \refcmd{mmzAtEndMemoizationExtra};
+``Extra'' because we're appending during memoization). It is
+\cs{outerlabeltocontext} which then appends \refcmd{@currentlabel} to the
+context (\refcmd{mmzContextExtra}; again, ``Extra'' because we're appending
+during memoization),\footnote{As a courtesy, we clear out macro
+ \cs{outerlabeltocontext} once it did it's job, so that multiple \cs{label}s
+ do not include multiple \cs{@currentlabel}s into the context. But the code
+ would work even without this addendum, can you see why?} and it is crucial
+that this happens at the end of memoization rather than when \cs{label} is
+executed. When \cs{label} is executed, we're inside an inner item, and
+\cs{@currentlabel} refers to that item, while at the end of memoization, the
+value of this macro equals the value at the beginning of memoization, namely
+the label of the outer item. While the outer list remains unshuffled, the
+value of \refcmd{@currentlabel} that contributes to the context MD5 sum during
+the utilization attempt will therefore match the value which contributed to the
+context MD5 sum during memoization, resulting in matching MD5 sums and
+therefore in actual utilization of the extern; once the outer list is shuffled,
+this will cease to be the case and the extern will be recompiled.
+
+
+\subsubsection{The Beamer support explained}
+\label{sec:per-overlay}
+
+The implementation of \refmmz{per overlay}, which makes memoization sensitive
+to Beamer overlays, provides an example of a complex interaction between
+various components of memoization. At the core, the Beamer support works by
+adjusting the context, but we will also have the occasion to observe the
+free-form part of the c-memo, add a bit of extra code to the cc-memo, and
+deploy several memoization hooks. We will show the complete Beamer support
+code later on; let us build our understanding of that code step by step.
+(Before you read on, you might want to refresh your memory about the \pkg{beamer}
+example from section~\ref{sec:tut:beamer}, as we will refer to it in the
+present section.)
+
+The core idea behind \refmmz{per overlay} is to append the current beamer
+overlay number to the context:\cprotect\footnote{As we saw in
+ section~\ref{sec:tut:beamer}, it is convenient to execute \refmmz{per
+ overlay} inside memoized code. But remember, from
+ section~\ref{sec:cross-referencing}, that when \refmmz{context} is executed
+ from within the memoized code, its argument winds up in the c-memo. As the
+ c-memo is processed under the normal category code regime, where |@| is not a
+ letter, we have to access |\beamer@overlaynumber| using the |\csname
+ ... \endcsname| construct.} \refmmz{context}|={overlay=\csname
+ beamer@overlaynumber\endcsname}|. This makes Memoize produce a separate
+extern for each overlay. However, only the first of these externs will get
+utilized on subsequent compilations, in general at least. Even worse, we will
+lose each frame whose creation is driven solely by the memoized code. We will
+lose the second overlay in our example (i.e.\ in the \pkg{beamer} example from
+section~\ref{sec:tut:beamer}) as the second overlay was only created because
+Beamer encountered |only={2}{...}| (resolving to |\only<2>{...}| under the
+hood) inside the picture code; once we utilize the extern instead of compiling
+the picture on the first overlay, the |\only| command is not executed anymore,
+so Beamer thinks it is done with the frame.
+
+As the compilation of our picture is substituted by utilization of its
+cc-memos, we have to somehow drive the creation of the necessary overlays from
+these files. An easy way to achieve this is to furnish them with a dummy
+|\only<|\meta{final overlay number}|>{}|,\footnote{`The final overlay' here
+ should be understood as relative to our memoized picture, i.e.\ as the final
+ overlay containing the memoized picture.}\footnote{Actually, putting this
+ \cs{only} command only into the first cc-memo would suffice, but would be
+ harder to implement.} but there is a problem: the final overlay number is
+unknown when we're memoizing our picture --- it is unknown even when we're
+memoizing the picture on final overlay itself (we simply don't know yet that
+this overlay will end up being the final one), let alone during the memoization
+on the first overlay.
+
+The solution exploits the fact that \emph{the c-memo is rewritten at each
+ memoization}: at each memoization of our picture, we store the the
+\emph{current} overlay number to the c-memo; after all memoizations, the c-memo
+will thus contain the number of the \emph{final} overlay containing our
+memoized picture. To access this number from the cc-memo, we store it as a
+macro definition, and then use the defined macro, |\mmzBeamerOverlays|, in the
+overlay specification of the dummy |\only|. Below, you can see all this in
+code, as the argument to \refmmz{at begin memoization}.
+
+\ExampleName{per-overlay-v1}
+\makeexample{\examplename.sty}
+\tcbinputexample[.sty]{
+ listing only,
+ title={The implementation of \refmmz{per overlay} (first attempt)},
+}
+
+A couple of remarks are in order here. First, the definition of
+|\mmzBeamerOverlays| in the c-memo is global, because it will be accessed from
+the cc-memo, but the cc-memo is input after closing the memoize group (which
+the c-memo \emph{is} processed in). Second, using \refmmz{at begin
+ memoization} makes it possible to use \refmmz{per overlay} both outside and
+during memoization: if \refmmz{at begin memoization} is executed outside
+memoization, its argument is (locally) stored into hook
+\refcmd{mmzAtBeginMemoization}, to be called at the beginning of each
+memoization; if the key executed outside memoization, the argument is executed
+immediately. Third, the Memoize keys in the definition of \refmmz{per overlay}
+are prefixed with \code{\refkeypath{/mmz}/}, so that this key can be called from
+\pkg{pgfkeys} option lists of other packages, for example the option list of
+the \env{tikzpicture} environment, as shown in the example in
+section~\ref{sec:tut:beamer}.
+
+I used the above version of \refmmz{per overlay} for quite a while. In
+general, it worked as I expected, but there were glitches. Occasionally, the
+picture would appear on the wrong overlay, or I would get an extra overlay, or
+perhaps lose an overlay. Eventually, I figured out this happens when I play
+with the overlay structure of the frame: when I add or remove a \cs{pause} or
+similar. In hindsight, it is easy to see what was happening. Once the picture
+is memoized, it is fixed, forever, which extern will appear on which overlay.
+I cannot expect the extern--overlay correlation to change just because I added
+a \cs{pause} in front of the picture. Furthermore, the number of overlays the
+memos will drive to be created is fixed as well. If I memoize the picture
+while it follows a \cs{pause}, and the picture creates 10 overlays, the c-memo
+will define |\mmzBeamerOverlays| to 11. So what, if I then remove that
+\cs{pause}! The c-memo will still define |\mmzBeamerOverlays| to 11, and drive
+the creation of 11 overlays --- one too many.
+
+By now, the road ahead is probably clear --- we put the |beamerpauses| counter
+into the context --- but we will see there are still obstacles on the way. The
+issue is that the context is evaluated at the \emph{end} of memoization (so
+that those cross-references from section~\ref{sec:cross-referencing} actually
+get into it). However, the memoized code might contain a \cs{pause} or similar
+itself, and change the value of |beamerpauses|. For one, this means that we
+have to write down the changed value of |beamerpauses| into the cc-memo; below,
+we do this using key \refmmz{at end memoization} (the code given code to this
+key is executed after the driver but before Memoize writes down the memos and
+ships out the extern pages; the key itself may be executed either before or
+during memoization). Furthermore, if the memoized code changes the value of
+|beamerpauses|, the value of |beamerpauses| at the attempted utilization, which
+would nicely match the value from the start of memoization, will never match
+the changed, final value from the end of memoization, in effect preventing our
+hard-won externs from ever getting utilized.
+
+We therefore have to invent a way to get the memoization-\emph{initial} value
+of |beamerpauses| into the context.\footnote{This imposes a requirement on the
+ in-code usage of \refmmz{per overlay}, namely, that it should be executed
+ prior to any changes of |beamerpauses|.} Fine, we store it in a
+macro,\footnote{We must define \cs{mmzBeamerPauses} globally, because
+ \refmmz{per overlay} can be arbitrarily deeply embedded in the memoized
+ code.} |\mmzBeamerPauses|, when we start the memoization (\refmmz{at begin
+ memoization}), and put |\mmzBeamerPauses| rather than |beamerpauses| into the
+context. Will this work? Not yet, because |\mmzBeamerPauses| is undefined at
+utilization. We need to set up the context expression so that it will expand
+to the value of |\mmzBeamerPauses| at (the end of) memoization, and to the
+value of |beamerpauses| at utilization. This leads to the
+|pauses=\ifmemoizing...| part of the context expression in (the final version
+ of) the Beamer support code below.
+
+\medskip % manual, to avoid an orphan
+
+\ExampleName{per-overlay}
+\makeexcerpt{per-overlay}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file,
+ left=0pt, % manual indentation gobble
+ title={The implementation of \refmmz{per overlay}},
+}
+
+Are we done? Almost. The final issue is that once we have introduced support
+for pauses, we have to relativize |\mmzBeamerOverlays| (the final overlay
+number) to |beamerpause|. So instead of a simple |\gdef\mmzBeamerOverlays| in
+the first version, we define |\mmzSetBeamerOverlays|\nohyphen\marg{beamer
+ pauses}\marg{final overlay number}, which sets |\mmzBeamerOverlays| only if
+\meta{beamer pauses} argument matches the value of |beamerpauses| (at its
+invocation in the c-memo). Well, the macro has some other housekeeping to do
+as well: it is self-replicating, so that during potential memoization, the
+|\mmzBeamerOverlays| values belonging to non-current |beamerpauses| values get
+rewritten into the c-memo.\footnote{As replication should only occur during
+ memoization (actually, it \emph{can} only occur then, anyway), the
+ instruction to append to the c-memo is appended to the
+ \cs{mmzAtBeginMemoization} hook (the low-level interface to \refmmz{at begin
+ memoization}). Note that the assignment to this hook must be local (once
+ local, always local), and it \emph{can} be local because of a little
+ implementation detail: while the c-memo is processed in the memoize
+ \hologo{TeX} group, we don't open an additional group to process it; so the
+ local effects from c-memo will persist into memoization (but not into
+ utilization, because remember that the memoize group is closed before
+ inputting the cc-memo).} (Fine, there is another fine detail, regarding
+anti-pollution: the macro also ensures that, relative to \marg{beamer pauses},
+only the instance with the greatest \meta{final overlay number} is replicated.)
+
+We are now truly done, and we can look at the final result, the c-memo and the
+cc-memo belonging to the extern on the first overlay of the example from
+section~\ref{sec:tut:beamer}. Specifically, look at the |\mmzSetBeamerOverlays
+{1}{2}|, which says that the extern chain started when |beamerpauses| equals 1
+should continue up to overlay 2, and at the (expanded) context included at the
+end of the cc-memo, courtesy of \refmmz{include context in ccmemo}, where you
+can see that the cc-memo will be used when on the first overlay (|overlay=1|)
+when preceded by no \cs{pause} command (|pauses=1|).
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCMemo#1{% fetch the first c-memo filename
+ \def\mycmemo{#1}%
+}
+\def\mmzNewCCMemo#1{% fetch the first cc-memo filename
+ \def\myccmemo{#1}%
+ \endinput
+}
+\input{\exampledir beamer.mmz.c1}
+\sed{%
+ s/~//g;
+ s/\cmd{mmzSetBeamerOverlays} \marg\marg/~\0~/;
+}{\exampledir\mycmemo}
+\sed{%
+ s/~//g;
+ s/overlay=[0-9]*/~\0~/;
+ s/pauses=[0-9]*/~\0~/;
+ s/\(\cmd{quitvmode}\) \(\cmd{only}\)/\1\n\2/;
+ s/\rbrace\(\cmd{mmzIncludeExtern}\)/\rbrace\percentchar\n\1/;
+ s/\rbrace\(\cmd{setcounter}\)/\rbrace\percentchar\n\1/;
+ s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/;
+}{\exampledir\myccmemo}
+
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\mycmemo,
+ example title=\mycmemo,
+}
+
+\tcbinputlisting{
+ listing only,
+ listing file=\exampledir\myccmemo,
+ example title=\myccmemo,
+}
+\endgroup
+
+
+\subsection{Record files}
+\label{sec:record-files}
+
+We have seen that externalization is a two-step process in Memoize: as it is
+impossible for \hologo{TeX} to create multiple PDFs during a single
+compilation, the externs are first dumped into the document PDF as special
+extern pages, and only later extracted from the main document into separate PDF
+files. But extraction requires a complete PDF, which is unavailable even at
+the very end of the compilation which produces the externs. The externs can
+therefore only be extracted \emph{after} that compilation (either before or at
+the beginning of the next one), and this necessitates some form of
+communication whereby the memoization step informs the extraction step which
+pages should be extracted from the document PDF and into which (PDF) files they
+should be stored. This communication is implemented through auxiliary files
+called \emph{record files}.
+
+\subsubsection{The \texttt{.mmz} file}
+\label{sec:.mmz}
+
+By default, Memoize records the information needed for the extraction in a file
+named \meta{document name}\dmmz,\footnote{For \hologo{TeX}perts: the
+ \meta{document name} is of course the expansion of \cs{jobname}.} henceforth
+a \dmmz file. In fact, this file contains more than information on externs
+created during the last compilation: it records which memos and externs were
+either used or created during the compilation. The full information contained
+in the \dmmz file is used by the clean-up script \refscript{memoize-clean.pl}
+to safely remove stale memos and externs. Let us take a look at the \dmmz file
+produced by the titlepage illustration. In fact, we have two versions of this
+file, as it changes upon the second compilation.
+
+\ExampleName{titlepage}
+\makeexample{\examplename.pdf N=2}
+\sed{%
+ s/~//g;
+ s/\cmd{mmzNewExtern}/~\0~/;
+}{\examplepath.mmz.c1}
+\tcbinputexample[.mmz][.c1]{
+ listing only, one file, no attachment, float,
+ after title pre={\ (after the first compilation)},
+ listing options app={breakatwhitespace=false,prebreak=\coloredpercentchar},
+}
+\tcbinputexample[.mmz][.c2]{
+ listing only, one file, no attachment, float,
+ after title pre={\ (after subsequent compilations)},
+ listing options app={breakatwhitespace=false,prebreak=\coloredpercentchar},
+}
+
+As you can see, the \dmmz file takes the form of a \hologo{TeX} script (the
+format was chosen because it facilitated the implementation of the internally
+triggered \hologo{TeX}-based extraction). The crucial lines in this file, and
+the only lines used by the extraction script, occur in the first version of the
+file: they contain command \refcmd{mmzNewExtern}, which informs the extraction
+script that it should extract the document page given by the second argument
+into the extern file given by the first argument.\footnote{If you look at the
+ \dmmz file after extracting the externs using \refscript{memoize-extract.pl}
+ without the \refscript{memoize-extract.pl--keep} option, you will find that
+ the \refcmd{mmzNewExtern} commands are commented out; this is to prevent
+ multiple extractions (even if they are harmless).} (The following two
+arguments provide the expected width and height of the extern; the
+extraction script may check whether the extern size conforms to these
+expectations, but this is not crucial, as the extern size is checked every time
+it is included anyway.)
+
+A \dmmz file also contains a record of the memos (both c-memos and cc-memos)
+created in the last compilation; this information is provided by the sole
+argument of commands \refcmd{mmzNewCMemo} and \refcmd{mmzNewCCMemo}. And once
+memos and externs get used in subsequent compilations, the \dmmz file will
+reflect this with \refcmd{mmzUsedCMemo}, \refcmd{mmzUsedCCMemo} and
+\refcmd{mmzUsedExtern}, as shown in the second version of the file above.
+
+Finally, both versions illustrate that a \dmmz file always begins with command
+\refcmd{mmzPrefix} and ends with the |\endinput| marker. The argument of
+\refcmd{mmzPrefix} is the path prefix to the memo and extern files, as
+determined by the invocation of key \refmmz{path} (and its subkeys
+\refmmzpath{relative}, \refmmzpath{dir} and \refmmzpath{prefix}). The initial
+\refcmd{mmzPrefix} line is written to the \dmmz file at the beginning of the
+document, but an additional \refcmd{mmzPrefix} line will occur for every
+invocation of \refmmz{path} in the document body. Finally, the |\endinput|
+marker signals that the \dmmz file is complete.
+
+As mentioned above, the full contingent of \dmmz file commands is only used by
+the clean-up script \refscript{memoize-clean.pl}. By default, this script
+removes all memos and externs with the prefix given by \refcmd{mmzPrefix}
+(relative to the directory hosting the \dmmz file) but those listed by any of
+\refcmd{mmzNewCMemo}, \refcmd{mmzNewCCMemo}, \refcmd{mmzNewExtern},
+\refcmd{mmzUsedCMemo}, \refcmd{mmzUsedCCMemo} and \refcmd{mmzUsedExtern}.
+Furthermore, the clean-up script will cowardly refuse to delete anything if the
+\dmmz file does not end with |\endinput|, as this means that the compilation
+ended prematurely and that the \dmmz file might not mention all memos and
+externs actually used in the document. If given option
+\refscript{memoize-clean.pl--all}, the clean-up script removes even the memos
+and externs mentioned in the \dmmz file, and as this option is intended to
+bring Memoize to a clean slate after any ``disasters,'' the
+\refscript{memoize-clean.pl--all} mode also ignores the potential absence of
+the |\endinput| marker. Incidentally, the \refscript{memoize-clean.pl--all}
+mode is also the raison d'être for \refcmd{mmzPrefix}: while the prefix is
+usually recognizable from \refcmd{mmzNewCMemo} and friends, these commands
+might not make it into the \dmmz file in a fatally failed compilation, but it
+is precisely such compilations that could occasionally require the full
+clean-up.
+
+\subsubsection{Defining a new record type}
+\label{sec:new-record-file}
+
+The \dmmz file is not the only kind of a record file that can be produced by
+Memoize. Out of the box, it can also write down the extraction instructions
+into a makefile or a shell script. These are useful on systems which have to
+employ the \hologo{TeX}-based extraction but cannot trigger it internally.
+Running the \hologo{TeX}-based extraction manually would be painful, as it must
+be done on extern-by-extern basis, so Memoize offers to automate the extraction
+by a makefile or a shell script; here, the record file is named
+\code{memoize-extract.\meta{document name}.\meta{record type}} by default,
+where \meta{record type} is either \refmmz{record=makefile},
+\refmmz{record=sh} (for shell scripts on Linux), or \refmmz{record=bat} (for
+shell scripts on Windows).
+
+To turn on recording of an alternate record type, use key
+\refmmz{record}|=|\meta{record type}. Memoize can record any number of files
+simultaneously, so saying \code{\refmmz{record}=\refmmz{record=sh}} will
+produce the shell script alongside \dmmz (Memoize internally executes
+\code{\refmmz{record}=\refmmz{record=mmz}} to start recording the \dmmz file);
+this should not be a problem, but if you really want to disable the \dmmz file
+production, you can say \refmmz{no record}.
+
+The predefined record types are defined through a generic system open to the
+user. To define an additional record type, one needs to define, using
+\pkg{pgfkeys}, the relevant hooks of the form \refkeypath{/mmz/record/record
+ type}|/|\meta{hook}. The following \meta{hook}s can be defined (the hooks
+not needed for the record file type may be left undefined):
+\begin{itemize}
+\item Key \refmmz{record/record type/begin} will be executed at the beginning
+ of the document; it will receive no argument. Use it to open the record
+ file.
+\item Key \refmmz{record/record type/end} will be executed at the end of the
+ document; it will receive no argument. Use it to close the record file.
+\item Key \refmmz{record/record type/prefix} will be executed at the end of the
+ document and at every invocation of key \refmmz{path} in the document body;
+ it will receive a single argument, the path prefix determined by key
+ \refmmz{path}.
+\item Keys \refmmz{record/record type/new cmemo}, \refmmz{record/record
+ type/used cmemo}, \refmmz{record/record type/new ccmemo} and
+ \refmmz{record/record type/used ccmemo} will be executed after creating or
+ inputting a memo; they will receive a single argument, the full path to the
+ memo.
+\item Key \refmmz{record/record type/used extern} will be executed after an
+ extern was included into the document; it will receive a single argument, the
+ full path to the extern.
+\item Key \refmmz{record/record type/new extern} will be executed after
+ creating creating an extern, more precisely at the end of memoization, right
+ after shipping out the extern page. It will receive a single argument, the
+ full path to the extern, but additionally, Memoize prepares the following
+ macros:
+ \begin{itemize}
+ \item \refcmd{ne:externbasepath} holds the full path to the extern, but (unlike |#1|)
+ without the |.pdf| suffix;
+ \item \refcmd{ne:pagenumber} holds the ``physical'' page number of the extern page in
+ the document (the numbering starts by $1$);
+ \item \refcmd{ne:expectedwidth} and \refcmd{ne:expectedheight} hold the width and
+ the height (total height, i.e.\ the sum of \hologo{TeX}'s height and depth)
+ of the extern page.
+ \end{itemize}
+\end{itemize}
+
+Below, we present two simple examples of a record file. The first type simply
+records the names of all memos and externs used or created by Memoize; the
+resulting file could be included by |.gitignore| to have
+\hreftt{https://git-scm.com}{git} automatically ignore all files produced by
+Memoize. The second type lists the new externs, each preceded by its page
+number in the |.pdf|; this file could be fed to a custom extern extraction
+tool.
+
+\ExampleName{record-files}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing only}
+
+\ExampleName{record-extern-pages}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing only}
+
+Finally, note that (unlike memos and externs) record files are auxiliary files
+and may be deleted at any time after the extraction of the externs produced in
+the final compilation --- actually, even if these externs were not yet
+extracted, deleting the record file(s) will merely force their recompilation.
+
+
+\subsection{The memoization process}
+\label{sec:memoization-drivers}
+
+We now turn to the memoization process itself. The job of memoization is to,
+while compiling the given code in a regular fashion, prepare the cc-memo
+(which, when it is input, will replicate the effect of the given code),
+alongside any externs that the cc-memo will include (these hold the typeset
+material to be replicated). Clearly, merely compiling the code cannot have
+this effect (unless that code was written specifically to support memoization;
+more on this later), and this is why the memoized code is typically wrapped by
+a \emph{memoization driver}, which can be set using key \Emph{\refmmz{driver}}.
+We'll inspect the default memoization driver, \refcmd{mmzSingleExternDriver},
+in the first subsection, and we will learn how to write specialized drivers in
+the remaining subsections. But first, let us say some words about a
+grouping-related \hologo{TeX}nical detail we need to take care about during
+memoization.
+
+During memoization, we have to collect certain information, like build the
+contents of the cc-memo. Some of that information might be contributed by the
+memoized code itself. For example, a \cs{label} ``adds itself'' to the cc-memo
+(by appending to token register \refcmd{mmzCCMemo}); a
+\refkey{/tikz/remember picture} aborts memoization (by issuing
+\refcmd{mmzAbort}); etc. The issue is that the memoized code might open any
+number of \hologo{TeX} groups; we have no idea how deeply embedded the
+\cs{label} or \refkey{/tikz/remember picture} might be. Therefore, we have
+to collect all the information about the ongoing memoization \emph{globally}:
+all assignments to \refcmd{mmzCCMemo} must be global; \refcmd{mmzAbort} sets
+the underlying conditional globally; etc. (Clearly, all these global variables
+are initialized at the start of memoization.)
+
+This was the easy part. An additional complication arises with some options
+which may be set either outside memoization, or during this process. For
+example, you can append the font size to the context expression in the preamble
+(see section~\ref{sec:cross-referencing}), so that the externs will be
+automatically recompiled when the font size changes, and clearly, this context
+adjustment should respect \hologo{TeX} grouping; but a \cs{ref} or some other
+cross-referencing command in the memoized code needs to append to the context
+as well, and as this \cs{ref} occurs \emph{within} the memoized code, the
+assignment must be global, as explained above.
+
+Mixing the local and global assignments to the token register
+\refcmd{mmzContext}, which holds the (in the actual implementation, local)
+context expression, will not do. For one, we \emph{do} want to restore the
+pre-memoization context expression after we have memoized the code, and
+furthermore, mixing local and global assignments to the same variable is not
+recommended for save stack reasons anyway.
+
+Memoize addresses this issue by having \emph{two} context registers,
+\refcmd{mmzContext} and \refcmd{mmzContextExtra} --- when computing the context
+MD5 sum (which happens at the end of memoization), the two registers are
+concatenated (the local one comes first). A package writer should know when to
+use which register, and how. Outside memoization, one should assign to
+\refcmd{mmzContext} --- \emph{locally}. During memoization, one should assign
+to \refcmd{mmzContextExtra} --- \emph{globally}. The user interface key
+\refmmz{context} respects this requirement automatically: it locally appends to
+\refcmd{mmzContext} outside memoization, and it globally appends to
+\refcmd{mmzContextExtra} during memoization. (The same idea is applied to the
+post-memoization hooks \refmmz{at end memoization} and \refmmz{after
+ memoization}.)
+
+
+\subsubsection{The default memoization driver}
+\label{sec:memoization-driver-default}
+
+The default memoization driver, \refcmd{mmzSingleExternDriver}, produces
+exactly one extern, which contains whatever is typeset by the code submitted to
+memoization. The driver compiles the code into a horizontal or vertical box
+depending on the value of key \refmmz{capture}. Let us look at the definition
+of the driver line by line:
+
+\makeexcerpt{single-extern-driver}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file,
+ listing options app={numbers=left, numberstyle=\tiny, numbersep=0.5em},
+ title=The default memoization driver,
+ float,
+}
+
+\begin{enumerate}
+\item Macro \refcmd{mmzSingleExternDriver} (and in fact any memoization
+ driver) takes a single argument, the code to compile. Memoize will call the
+ driver with the code given as the second argument to \refcmd{Memoize}, but
+ wrapped in a macro which re-reads it using \refcmd{scantokens} when
+ \refmmz{verbatim} is in effect.
+\item If we're capturing into a horizontal box
+ (\refmmz{capture}|=|\refmmz{capture=hbox}), we put \refcmd{quitvmode} into
+ the cc-memo --- putting it to the very beginning should make sure that any
+ replicated \cs{label} and \cs{index} commands refer to the correct page.
+\item We compile the given code, storing the typeset material into a box
+ (above, a temporary box called |\mmz@box|). |\mmz@capture| resolves into a
+ box construction command, depending on the value \refmmz{capture}.
+\item Macro \refcmd{mmzExternalizeBox} instructs Memoize to externalize the box
+ given as its first argument. However, this macro does not directly produce
+ an extern page or write any instructions into the cc-memo; the road to this
+ final destination is indirect. \refcmd{mmzExternalizeBox} has two effects.
+ First, it adds the contents of the given box (above, |\mmz@box|) to an
+ internal box dedicated to holding all the externs produced in this
+ memoization (the contents of |\mmz@box| remain as they are) --- it is only at
+ the end of memoization that the contents of this internal box are shipped off
+ to extern pages. Second, \refcmd{mmzExternalizeBox} produces the code which
+ will include the extern into the document on subsequent compilations (this
+ will be a call to \refcmd{mmzIncludeExtern}, potentially prefixed by
+ \refcmd{quitvmode}; see section~\ref{sec:cc-memos} for details). This code
+ is stored into the token register gives as the second argument (above,
+ |\mmz@temptoks|), and it is the responsibility of the driver to include it
+ into the cc-memo. (In the interest of full disclosure,
+ \refcmd{mmzExternalizeBox} also updates the list of externs produced in this
+ memoization. At the end of memoization, this list is written to the
+ beginning of the cc-memo, resulting in the \refcmd{mmzResource} lines
+ preceding the \refcmd{mmzMemo} marker.)
+\item The construction of the cc-memo is indirect as well. In the third line
+ of the definition, we globally append the extern-inclusion code residing in
+ |\mmz@temptoks| to token register \refcmd{mmzCCMemo}. At the end of
+ memoization, the contents of \refcmd{mmzCCMemo} are written into the cc-memo,
+ preceded by the \refcmd{mmzMemo} marker.
+\item We put the typeset material into the document, again preceded by
+ \refcmd{quitvmode} when capturing in a horizontal box.
+\end{enumerate}
+
+You might wonder why the construction of the extern pages and the cc-memo (and
+actually, of the c-memo as well) is indirect, as described above.
+\begin{itemize}
+\item For one, the indirect construction facilitates potential abortion of
+ memoization (see section~\ref{sec:tut:good-to-know}). With the indirect route,
+ aborting is easy --- as nothing was permanently written anywhere yet, Memoize
+ simply skips the final part of the process, where extern boxes are shipped
+ into extern pages and the memo registers written into memo files --- and also
+ clean: if \refcmd{mmzExternalizeBox} immediately shipped out the extern
+ pages, these pages would remain in the document even in the case of abortion.
+\item Even more importantly, the cc-memo filename contains the \meta{context
+ md5sum} (see section~\ref{sec:cc-memos}), but the context expression is not
+ yet fully known when memoization starts --- remember (from
+ section~\ref{sec:cross-referencing}) that a \cs{ref} in the memoized code will
+ update the context! The cc-memo can therefore only be opened at the end of
+ memoization, which necessitates a buffer (i.e.\ the \refcmd{mmzCCMemo}
+ register) for storing its contents during memoization.
+\end{itemize}
+
+
+\subsubsection{Pure memoization}
+\label{sec:pure-memoization}
+
+The default memoization driver discussed above is really an externalization
+driver: it produces a single extern. We now move to examples of drivers with
+other functions, starting with a pure memoization driver, which does not
+externalize any typeset output --- simply because it does not call
+\refcmd{mmzExternalizeBox} at any point --- but rather remembers the result
+of a (pgfmath) computation (let's pretend that the computation is
+time-consuming).
+
+\ExampleName{pgfmathparse}
+\makeexample{\examplename.pdf}
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCCMemo#1{% fetch the first cc-memo filename
+ \def\myccmemo{#1}%
+ \endinput
+}
+\input{\examplepath.mmz.c1}
+\tcbinputexample{%
+ comment={%
+ \tcbinputlisting{
+ listing only, width=.4\linewidth, nobeforeafter,
+ listing file=\exampledir\myccmemo,
+ example title, title=the cc-memo,
+ }\quad
+ \includeexamplepdf[document page]{page=1}
+ },
+}
+\endgroup
+
+Command \refcmd{mmz} above memoizes its mandatory argument with the memoization
+\refmmz{driver} set to the previously defined macro \cs{mmzPgfmathDriver}.
+Just as the default driver above, \cs{mmzPgfmathDriver} first executes the
+given code. However, there is no need to do this in the context of a
+|\setbox|, as the memoized code, which is obviously expected to consist of a
+single \cs{pgfmathparse} call, does not typeset anything: \cs{pgfmathparse}
+evaluates the given expression and stores the result into macro
+\cs{pgfmathresult}. The driver has two jobs: first, it must store this result
+into the cc-memo, to be utilized in subsequent compilations; second, because
+the assignment to \cs{pgfmathresult} (within \cs{pgfmathparse}) is local, the
+driver also needs to somehow smuggle the result out of the \cs{endgroup} issued
+by \refcmd{Memoize} and thereby make it into the following code (the final line
+of the example, which typesets the equation). Both jobs are easy enough: the
+expansion of |\def\noexpand\pgfmathresult{\pgfmathresult}| (in this case,
+|\def\pgfmathresult{42.0}|) is (globally) appended both to the token register
+\refcmd{mmzCCMemo}, which Memoize later writes into the cc-memo, and to the
+macro underlying the \refmmz{after memoization} hook, whose contents are
+executed \emph{after} closing the memoization group.
+
+Let us consider an alternative implementation of the same goal of memoizing the
+result of a pgfmath computation, showcasing a couple of useful tricks.
+
+\ExampleName{pgfmathparse-embellished}
+\makeexample{\examplename.pdf}
+\tcbinputexample{listing only}
+
+For one, this ``embellished'' example reminds us that we can list the
+\refmmz{driver} key among the auto-options (even if I don't really recommend
+automemoizing \cs{pgfmathparse}). But even more importantly, the example shows
+that the driver consist of more than a single control sequence; the only
+requirement is that the given driver code will consume the memoized code. In
+this example, we have developed a generic smuggling driver and applied it to
+\cs{pgfmathresult} in particular --- \cs{pgfmathresult} will become the first
+argument of \cs{mmzSmuggleOneDriver}, and the memoized code will become its
+second argument.
+
+In the first version of the example, we have appended the same code to macro
+\refcmd{mmzCCMemo} and to macro \refcmd{mmzAfterMemoizationExtra} --- no
+surprise here, as we want the effect of memoization and utilization to be the
+same. In the embellished version, we advertise another way to achieve the same
+effect, a way which might be useful for complicated drivers: we simply smuggle
+out the entire cc-memo. The idea works even when memoization procudes externs;
+in that case, however, the driver also has to say \cs{mmzkeepexternstrue} ---
+conditional \refcmd{ifmmzkeepexterns} decides whether Memoize keeps the externs
+around, in memory, even after shipping them out (but they are always gone at
+the start of the next memoization).
+
+Finally, remember that the default context expression contains the
+\refmmz{padding} values. However, these really have no place in the context
+expression of some purely memoized code. We have therefore emptied out the
+context expression using \refmmz{clear context}.
+
+
+\subsubsection{Multiple externs per memo}
+\label{sec:memoization-multiple-externs}
+
+In the next example, we show how to produce multiple externs for a single piece
+of memoized code. The usage case I find most appealing is breaking the typeset
+material, like a table, across pages --- but of course, table-breaking is too
+complicated an example, so we illustrate the idea by defining command
+|\countdown|, which counts down from the given number, typesetting each number
+into its own line. Clearly, if we were to externalize a call to this command
+using the default memoization driver, page breaking would stop working, as the
+entire countdown would be seen as a single, unbreakable box. To externalize it
+properly, the chunks of the countdown that should appear on separate pages must
+be externalized into separate externs, as shown below.
+
+\ExampleName{countdown}
+\makeexample{\examplename.sty N=2}
+\makeexample{\examplename.pdf}
+\tcbinputexample{%
+ listing options app={
+ basicstyle=\ttfamily\footnotesize,
+ },
+ middle=1mm, bottom=0mm,
+ comment={\centering
+ \relaxmmzcommands
+ \def\mmzUsedExtern##1{%
+ \saveexpandmode\fullexpandarg
+ \StrGobbleRight{##1}{4}[\mytemp]%
+ \StrRight{\mytemp}{5}[\mytemp]%
+ \restoreexpandmode
+ \relaxmmzcommands
+ }%
+ \def\mmzNewExtern##1##2##3##4##5{\mmzUsedExtern{##1}}
+ \def\myexternname##1{extern \dots\texttt{\mytemp##1.pdf}}%
+ \input{\examplepath.mmz}%
+ \begin{tabular}{ccc}
+ \includeexamplepdf[extern page,title/.expand once=\myexternname{}]
+ {page=2,trim=1in 1in 1in 1in,scale=0.333}&
+ \includeexamplepdf[extern page,title/.expand once=\myexternname{-1}]
+ {page=3,trim=1in 1in 1in 1in,scale=0.333}&
+ \includeexamplepdf[extern page,title/.expand once=\myexternname{-2}]
+ {page=4,trim=1in 1in 1in 1in,scale=0.333}\\
+ \includeexamplepdf[document page]{page=1,scale=0.333}&
+ \includeexamplepdf[document page]{page=5,scale=0.333}&
+ \includeexamplepdf[document page]{page=6,scale=0.333}
+ \end{tabular}
+ },
+}
+
+To achieve this, we will have to integrate the memoization driver into the very
+code of |\countdown|. This approach contrasts sharply with the standard
+memoization driver, which is simply wrapped around the memoized code. Let's
+say we have implemented a non-memoization-aware variant of |\countdown| as a
+loop which gathers the countdown lines into a vertical box, and periodically,
+when this box holds all the material that will fit onto the page, places it
+into the main vertical list (i.e.\ on the page).\footnote{Of course,
+ implementing \cs{countdown} this way would be idiotic; a sane implementation
+ would simply spit out the countdown lines one by one, and let \hologo{TeX}
+ deal with page-breaking. However, remember that we are pretending that we
+ are typesetting (and page-breaking) some complex material, like a table; in
+ such a case, the loop outlined in the main text would make perfect sense.}
+To have this command support memoization, we have to externalize our box every
+time we're placing it into the main vertical list. This is precisely what we
+do in the definition of |\countdowntypeset| below:\footnote{We omit the
+ definition of the core algorithm of \cs{countdown} in the listing, because it
+ is mostly irrelevant for our discussion, and only show the
+ memoization-related code.} the final line of this macro adds the material to
+the main vertical list, and the preceding lines externalize it (the two lines
+inside \cs{ifmemoizingcountdown} should be familiar from the definition of the
+standard memoization driver; we'll explain about the conditional below); note
+that Memoize automatically deals with the fact that our box is vertical. As a
+result of having our memoization driver integrated into the loop of the core
+command, we can create as many externs as necessary, complete with the code in
+the cc-memo for including each and every one of them on subsequent
+compilations. Each extern eventually makes it into its own extern file, and
+note that the filenames of the non-first externs have their sequential number
+(we start counting at $0$) appended to the basename, as shown in the
+example.\cprotect\footnote{The \refmmz{auto} declaration of |\countdown| adds
+ some relevant parameters to the context (see
+ section~\ref{sec:cross-referencing}). The countdown will be recompiled upon
+ change of either the font size (|f@size|), the text height (|\textheight|),
+ or the height of the material in the main vertical list collected so far
+ (|\pagetotal|). The |\pagetotal| parameter is especially important;
+ including it makes sure that the countdown will be recompiled when it is
+ pushed up or down the page. Also note that we want the context to record the
+ value of |\pagetotal| when the (automemoized) |\countdown| is encountered
+ (rather than at the end of memoization), so we expand it when applying the
+ auto-options.}
+
+\tcbinputexample[.sty]{listing only, after title pre={\ (version 1)}}
+
+Of course, the chunks of the countdown should only be externalized when the
+code is actually being memoized, and not, say, when Memoize is disabled or
+performing regular compilation. (Note that this is a problem that only affects
+integrated drivers and not wrapped drivers such as the default driver.) The
+first thought is to detect whether we're undergoing memoization using
+conditional \refcmd{ifmemoizing}, which Memoize sets to true at the start of
+every memoization. This conditional is used in the run conditions of advice
+for \cs{ref} and \cs{label}, the idea being that they should add stuff to the
+context (\cs{ref}) and the cc-memo (\cs{label}) only when undergoing
+memoization. However, deploying \refcmd{ifmemoizing} in the current example
+would not be exactly right. It would work well with the main document as it
+is, but it would fail if |\countdown| was called from a piece of code that was
+independently submitted to memoization, e.g.\
+\refcmd{mmz}|{\countdown{30}}|.\footnote{Such embedding occurs more often than
+ you might think. For example, \env{forest} calls \env{tikzpicture} under the
+ hood, and both environments are automemoized.} In that case, both the
+\refcmd{mmz} driver and the |\countdown| integrated driver would get executed,
+resulting in the creation (and in subsequent compilations, utilization) of four
+externs: first, the |\countdown| driver would externalize each countdown chunk
+separately, and then, the \refcmd{mmz} driver would externalize them, all
+together, yet again. You can try this out by replacing
+\cs{ifmemoizingcountdown} in \cs{countdowntypeset} by \refcmd{ifmemoizing} (and
+wrapping the \cs{countdown} call in \cs{mmz}).
+
+The solution to the \refcmd{ifmemoizing} problem deployed in the example is to
+declare a new, \cs{countdown}-specific memoization conditional, and set it to
+true in \cs{countdown}'s formal driver, i.e.\ the macro set as the
+\refmmz{driver} in the \refmmz{auto} declaration for \cs{countdown}. In fact,
+Memoize can do most of this for you: when we write \refmmzauto{integrated
+ driver}|=countdown|, Memoize creates the countdown-specific memoization
+conditional and declares the formal driver which sets this conditional to true;
+you only have to access this conditional in your code, and you should do this
+using the \hologo{LaTeX}-style conditional \refcmd{IfMemoizing}, as shown
+below.\footnote{You shouldn't directly use the plain \hologo{TeX}
+ countdown-specific conditional created by \refmmzauto{integrated driver} ---
+ to prevent accidental access, Memoize doesn't actually name it
+ \cs{ifmemoizingcountdown} --- because this conditional is undefined when
+ Memoize is not loaded, i.e.\ when only package \refpkg{memoizable} is in
+ effect. Furthermore, \refcmd{IfMemoizing} addresses a problem faced by
+ integrated drivers of potentially recursive commands; we will talk about this
+ in section~\ref{sec:memoization-complex-single-driver}.}
+
+\tcbinputexample[.sty][.c2]{listing only, after title pre={\ (version 2)},
+ attachment name=\examplename-integrated-driver.sty,
+}
+
+
+\subsubsection{Driver-based memoizable design}
+\label{sec:memoization-complex-single-driver}
+
+In the previous section, we used the integrated driver approach to produce
+memos including multiple externs, but the approach can be useful for one-extern
+memos as well, when the extern must be integrated into the document in some
+special way. We already discussed such situations in
+section~\ref{sec:memoizable-design}, where we suggested to split a
+``difficult'' command into the outer command and the inner command, and only
+submit the inner command to automemoization. However, the vanilla flavour of
+this approach had a negative impact on the user interface to automemoization.
+In this section, we will deploy the memoization driver to overcome the issue.
+
+\ExampleName{poormansbox-driver}
+\makeexample{\examplename.sty}
+\makeexample{\examplename.pdf N=2}
+
+Let us revisit the |poormansbox| example from
+section~\ref{sec:memoizable-design}. Remember that that environment produced
+a potentially framed box of a certain width, surrounded by some pre- and
+post-code, and that the issue was that the pre- and the post-code should not be
+memoized, but rather executed at every invocation of the command, as it was
+primarily intended to put some stretchable vertical space around the box.
+
+The document source\attachexample\ and the resulting PDF of the example are the
+same as in section~\ref{sec:memoizable-design}, so we will not repeat them
+here, but jump directly into a revised definition of the environment. We will
+retain the core idea from the original implementation: the outer command will
+execute the pre- and the post-code, and the inner command will typeset the box.
+But unlike in the original implementation, we will not automemoize the inner,
+internal command (this was the source of the author's discomfort) but the outer,
+user-level command --- and we will equip it with a custom memoization driver.
+The major idea here is to have the driver compose a cc-memo which not only
+includes the extern, but also executes the outer command.
+
+\tcbinputexample[.sty]{listing only, float}
+
+In detail, the implementation (partially shown in the |.sty| listing) is as
+follows. The outer command (|\poormansbox@outer|) first applies the options
+(|#1|) and then wraps the pre-code (|\pmb@before|) and the post-code
+(|\pmb@after|) around some arbitrary code (|#2|). During memoization or
+regular compilation, the outer command is invoked through the |poormansbox|
+environment, and you can see that in the definition of that environment, the
+second argument to |\poormansbox@outer| is a call to the inner command
+(|\poormansbox@inner|; this command takes two arguments, the options and the
+environment body). During utilization, the outer command is invoked from the
+cc-memo,\cprotect\footnote{As you can see, in the cc-memo the outer command is invoked
+ by |\csuse{poormansbox@outer}|. A straight |\poormansbox@outer| would not
+ work because we're in the middle of the document where |@| is not a letter,
+ and including a |\makeatletter| in front of it (and in a group) only works if
+ \refmmz{direct ccmemo input} was in effect. Under the default, indirect
+ cc-memo input regime, the core cc-memo is tokenized before |\makeatletter| can
+ take effect.} and as you can see in the cc-memo listing below, the second
+argument to |\poormansbox@outer| there is a call to \refcmd{mmzIncludeExtern}.
+
+\begingroup
+\relaxmmzcommands
+\def\mmzNewCCMemo#1{%
+ \def\mmzNewCCMemo##1{% fetch the second cc-memo filename
+ \def\myccmemo{##1}%
+ \endinput
+ }%
+}
+\input{\examplepath.mmz.c1}
+\sed{%
+ s/~//g;
+ s/\(\cmd{csuse} *{poormansbox@outer}\) *\({\nobrace*\marg\nobrace*}\)\({.*}\rbrace\)/~\1~\2~\3~/;
+ s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/;
+}{\exampledir\myccmemo}
+\tcbinputlisting{
+ listing only, left=1.5mm, right=1mm,
+ listing options app={basicstyle=\tt\small},
+ listing file=\exampledir\myccmemo,
+ example title, title=the second poor man's box's cc-memo,
+}%
+\endgroup
+
+And how does |\poormansbox@outer| get into the cc-memo, which normally only
+includes a call to \refcmd{mmzIncludeExtern}, you ask? This is the job of the
+memoization driver, which is in this case integrated into the inner command.
+The overall shape of the driver is the same as the shape of the standard
+driver, discussed in section~\ref{sec:memoization-driver-default}: typeset the
+extern material into a box, externalize this box, append the extern-inclusion
+code to the cc-memo, and put the extern box into the document. It is the
+cc-memo part which interests us right now: unlike the standard driver, we don't
+simply append the contents of |\mmz@temptoks|, i.e.\ a
+\refcmd{mmzIncludeExtern} call; we rather append a call to
+|\poormansbox@outer|, which gets the \refcmd{mmzIncludeExtern} call as its
+second argument (and the options as its first argument).
+
+The core part of the driver, which externalizes the box and appends to the
+cc-memo, is embedded inside the true branch of conditional
+\refcmd{IfMemoizing}|[1]{pmb}|. We already used this conditional in
+section~\ref{sec:memoization-multiple-externs}, but without the optional
+argument. Such usage will not work here, because it is not recursion-safe.
+Unlike in the \cs{countdown} situation, one |poormansbox| environment can be
+embedded in another one (and, in our example, it is). If we deployed
+\refcmd{IfMemoizing}|{pmb}| in the inner command, the driver would be executed for
+\emph{both} the outer and the inner instance of the environment, whereas it
+should really be executed only for the outer instance.
+
+When used in a recursion-safe way, i.e.\ with the optional argument,
+\refcmd{IfMemoizing} first tests whether the auxiliary command-specific
+conditional from the previous section is true, and then proceeds to compare the
+current group level (\hologo{eTeX}'s \refcmd{currentgrouplevel}) to the group
+level at the start of memoization (which Memoize stored in
+\refcmd{memoizinggrouplevel}). Only if these group levels match do we know
+that we're working on the outer instance of the environment, and that we should
+therefore execute the memoization driver. Importantly, though, the two group
+levels are compared modulo the offset, given as the optional parameter to
+\refcmd{IfMemoizing}: in our example, the offset is 1, because the driver is
+located inside the |poormansbox| environment, which opens a group --- note that
+0 zero (no offset) is not the default optional parameter; the absence of the
+optional parameter indicates that the non-recursion safe method should be
+used.\footnote{Even this approach is not completely bullet-proof. It will only
+ work when the inner instance of the command is guaranteed to occur in an
+ additional group, i.e.\ when our command opens up a group for any free-form
+ code. I will assume that situations which require externalization of a
+ potentially recursive command which, for some reason, cannot open the group
+ before processing a free-form argument, are rare enough to not warrant a
+ generic solution here.}
+
+
+\FloatBarrier
+
+
+\subsubsection{Shipout}
+
+Memoize is a hypocrite: when it is creating extern pages, it uses
+\refcmd{primitive}\refcmd{shipout} to bypass the regular shipout routine of the
+format, but it is offended if anyone else does that.
+
+Memoize bypasses the regular shipout because the extern pages should really not
+be modified or discarded by a foreign package. But using the primitive
+\refcmd{shipout} means that extern shipouts can't be detected by another
+package, at all. To facilitate peaceful coexistence with a potential package
+which needs to know about our extern pages, we offer public counter
+\refcmd{mmzExternPages} holding the number of externs shipped out so far. And
+if anyone really needs to \emph{do} something at every extern shipout, they can
+always (ab)use \refmmz[show keypath]{record/record type/new extern} as a
+post-extern-shipout hook.
+
+The other side of the story is about Memoize needing to know the ``physical''
+page numbers of its externs in the document PDF --- how else are we to extract
+them? Memoize computes these page numbers by adding the values of several
+counters: \refcmd{mmzRegularPages}, which holds the number of regular shipouts;
+the above-mentioned \refcmd{mmzExternPages}, which holds the number of extern
+shipouts; and \refcmd{mmzExtraPages}, which holds the number of other shipouts.
+The latter counter should be advanced by a package which, like Memoize,
+bypasses the regular shipout routine.
+
+\hologo{LaTeX} and \hologo{ConTeXt} kindly provide the number of regular
+shipouts as publicly a accessible counter, so we define
+\refcmd{mmzRegularPages} as synonymous with their
+\refcmd{ReadonlyShipoutCounter} and \refcmd{realpageno}. In \hologo{plainTeX}, we
+have to hijack the \refcmd{shipout} control sequence and count regular shipouts
+ourselves; as we have to hijack it while it still refers to the
+\refcmd{shipout} primitive, this format provides another reason for preferring
+Memoize to be loaded early.
+
+
+\subsection{Automemoization}
+\label{sec:tut:automemoization-details}
+
+Automemoization is a mechanism that automatically memoizes the result of the
+compilation of certain commands and environments. Writing Memoize, I went to
+great lengths to make it flexible, yet easy to use. This resulted in
+automemoization deploying two specifically developed auxiliary packages:
+package Advice, which provides a generic framework for extending the
+functionality of selected commands and environments, and package CollArgs,
+which provides a command for collection of the arguments conforming to the
+given (slightly extended) \pkg{xparse} argument specification.
+
+This section lists the considerations which went into designing the system,
+followed by short tutorials on both auxiliary packages, which include several
+examples of how Memoize uses the underlying advising framework.
+
+\paragraph{(De)activation}
+Ideally, all commands and environments where memoization makes sense would
+support Memoize (or Memoize would support them) and nothing would ever go
+wrong. In this dream world, memoization would be completely transparent to the
+author. However, things will go wrong, so at the very least, we need to
+offer the author a \emph{simple} way to \emph{selectively} switch automemoization
+on and off. This is achieved by keys \refmmz{activate} and
+\refmmz{deactivate}.
+
+\paragraph{Submission}
+Of course, there will be commands without official support by either Memoize or
+the package which defines them; clearly, at the moment when I write this, all
+commands but \cs{tikz}, \env{tikzpicture} and \env{forest} are such. Or, the
+author might want to automemoize his or her own command. Ideally, submitting a
+new command to automemoization would be as simple as
+|memoize=|{\meta{command}}, and for environments, this is in fact achievable,
+although the actual interface is
+\refmmz{auto}|=|\braces{\meta{environment}}\braces{\refmmzauto{memoize}}. But
+simply submitting the name cannot work for commands, because commands are where
+we encounter the major \hologo{TeX}nical problem with automemoization: we need
+to somehow collect the arguments of the command --- without executing the
+command itself.
+
+\paragraph{Argument collection using CollArgs}
+\hologo{TeX} being \hologo{TeX}, automatically determining the scope of a
+command in general is just plain impossible. Note that inspecting the
+|\meaning| is not enough in general, because the ``real'' and the formal
+arguments of a command can, and quite often do, differ wildly. The author (or the
+package writer) will need to tell Memoize about the argument structure of the
+command. And as there is already a nice and general argument specification on
+the market --- I'm obviously referring to the argument specification of package
+\pkg{xparse}, which was recently even integrated into the core \hologo{LaTeX}
+--- why not use that? Memoize comes with an auxiliary package CollArgs, which
+(given the slightly extended \pkg{xparse}-style argument specification)
+collects the arguments of a command into a single entity. All the user needs
+to write to enable automemoization for a command is thus
+\refmmz{auto}|=|\meta{command}\braces{\refmmzauto{memoize},
+ \refmmzauto{args}|=|\braces{\meta{argument specification}}}. Even simpler,
+when it comes to commands defined by \pkg{xparse}'s \refcmd{NewDocumentCommand}
+or friends, writing \refmmz{auto}|=|\meta{command}\braces{\refmmzauto{memoize}}
+will suffice, as the argument specification of these commands can be retrieved
+by \refcmd{GetDocumentCommandArgSpec}.
+
+\paragraph{Weird commands}
+Not every argument structure can be described using \pkg{xparse}'s argument
+specification, a case in point being \refcmd{tikz} with its totally
+idiosyncratic syntax --- and if Memoize won't support \cs{tikz}, why have it at
+all? The interface to automemoization must be flexible enough to cover even
+the craziest commands, and this is why Memoize allows for arbitrary argument
+collectors. These are defined by the advanced user or package writer and then
+declared to be used for parsing the argument structure of a command by writing
+\code{\refmmz{auto}=\marg{command}\bracestt{...,\refmmzauto{collector}=\meta{argument
+ collector}}}.
+
+\paragraph{Over and above automemoization: handlers}
+The framework facilitating automemoization must cover more than just that. For
+one, it sometimes makes sense to automatically \emph{prevent} memoization
+during the execution of certain commands (as in the \refmmzauto{nomemoize}
+example in section~\ref{sec:tut:redefinitions}). It follows that the action
+performed to an invocation of a command should not be fixed. In the advising
+framework, implemented by the auxiliary package Advice, we assign each
+advised command a handler --- a command which does the real work of
+memoizing or whatever. Crucially, the handler and the collector are
+independent of each other, allowing a single memoization handler to handle
+commands with both standard and non-standard argument structure, and allowing a
+single collector to serve either the memoization or the no-memoization handler.
+
+\paragraph{Over and above automemoization: the outer and the inner handler}
+Second, unlike the memoization handler set by \refmmzauto{memoize}, not all
+handlers work with the entire argument list of the advised command. Some
+handlers don't care about the arguments of the advised command at all:
+\refmmzauto{abort} simply aborts memoization whenever the advised command is
+executed. Other handlers are only intended to advise a single command or a
+small family of commands, and need to inspect specific arguments of the advised
+command: for example, \refmmzauto{ref} needs to append the internal
+cross-reference macro to the context, and it of course constructs the name of
+this macro from the reference key. For all such handlers, it would be plain
+wasteful to first collect the arguments and then tear them apart to inspect
+them (or not). The advising framework therefore recognizes two kinds of
+handlers. The abortion and the cross-reference handler are examples of an
+\emph{outer} handler, which is simply placed in front of the arguments of the
+handled command as they are, without invoking the collector. The memoization
+handler, on the other hand, is an example of an \emph{inner} handler, which
+receives the entire argument list from the collector (as a single argument) ---
+or more precisely, even \refmmzauto{memoize} sets up an outer handler, but this
+outer handler doesn't do much more than invoke the collector, which in turn
+invokes the inner handler.
+
+\paragraph*{Run conditions} are another, if minor, lego piece of the
+advising framework. Using key \refmmzauto{run conditions}, the user can set the
+conditions under which the (outer) handler is executed; for example,
+cross-reference commands are only advised when memoization is underway. And
+the same goes for \refcmd{label}, and for the \refmmzauto{replicate}d
+\refcmd{index}, and for \refcmd{savepos}, upon which memoization must be
+aborted. The bottom-line is that run conditions repeat across handlers, so
+it makes sense to separate them out as an independent component of the
+framework, with the added bonus that the system can make sure that an
+invocation of a advised command which does not satisfy the run conditions
+will incur as litte overhead as possible.
+
+\paragraph{Bailout handler}
+An automemoized command applies the next-options (set by \refcmd{mmznext}), but
+what happens when the run conditions are not satisfied? If nothing happened,
+the existing next-options might apply to the next instance of
+(auto)memoization, which would not be what the author intended. This is why
+Advice introduces the bailout handler, a piece of code executed before the
+original command when the run conditions are not met. Obviously, the bailout
+handler for memoization clears out the next-options (and does not process
+them).
+
+\paragraph{The structure of advice}
+Together, the components mentioned above form a piece of \emph{advice}:
+
+\begin{center}
+ \begin{forest}
+ /tikz/edge node/.style={midway, font=\scriptsize, yshift=0.5ex},
+ for tree={l sep=5ex, % manual, to avoid a page break
+ child anchor=north, s sep+=2em},
+ [activated?
+ [\refmmzauto{run conditions}?,
+ edge=dashed, edge label={node[edge node, left]{yes}}
+ [\refmmzauto{outer handler}\meta{args},
+ edge=->, edge label={node[edge node, left]{yes}},
+ [default:,
+ edge=dashed,
+ [\refmmzauto{collector}\meta{args}, edge=->,
+ [\refmmzauto{inner handler}
+ \textcolor{red}{\bracestt{\textcolor{black}{\meta{args}}}},
+ edge=->
+ ]
+ ]
+ ]
+ [other:\\whatever\rlap\footnotemark,
+ align=center, edge=dashed]
+ ]
+ [\refmmzauto{bailout handler},
+ edge=->, edge label={node[edge node, right]{no}},
+ [\meta{original command}\meta{args}, edge=->]
+ ]
+ ]
+ [\meta{original command}\meta{args},
+ edge=dashed, edge label={node[edge node, right]{no}},
+ ]
+ ]
+ \end{forest}%
+ \footnotetext{The handler may do whatever as long as it consumes all and
+ only the arguments of the original command.}
+\end{center}
+
+
+
+\paragraph{Deferred activation}
+Memoize needs to be loaded early, but activation should take place late, so
+that it can surely override the submitted commands; a case in point,
+\pkg{hyperref} redefines \refcmd{ref} very late. To address the issue, the
+advising framework implements the deferred \refmmz{activation} regime, under
+which (de)activation commands are not executed but collected in a special
+style, \refmmz{activate deferred}. Memoize deploys the deferred activation
+regime throughout the preamble, and executes \refmmz{activate deferred} at the
+latest possible \docref{hook:begindocument} hook; as a bonus, it also offers
+the author a way to avoid automatic activation completely by invoking key
+\refmmz{manual}.
+
+
+\paragraph{Install anywhere}
+Once all this machinery is developed, why not offer it to others as well?
+
+Once I decided to offer Advice (at the time, still called Auto) as a standalone
+package (and I freely admit that the framework got much cleaner once I
+separated its code out of Memoize) it became immediately clear that if it is
+to serve as a generic framework, it should be possible for multiple packages to
+use it without interfering with each other. The package thus allows any number
+of installations into different namespaces, each namespace a \pkg{pgfkeys}
+keypath. The installation is a breeze:
+\cs{pgfkeys}\bracestt{\meta{namespace}/\refkey{/handlers/.install advice}}.
+
+
+\subsubsection{Using package Advice}
+\label{sec:advice}
+
+In this section, we will provide some examples of handler declarations, mainly
+based on how Memoize deploys the advising framework.
+
+\paragraph{\refmmzauto[show keypath]{memoize}}
+
+In section~\ref{sec:tut:automemoization}, the author was instructed to submit a
+command to automemoization by writing
+\code{\refmmz{auto}=\meta{command}\bracestt{\refmmzauto{memoize},...}}. The
+auto-key \refmmzauto{memoize} is a style (defined by Memoize rather than
+Advice) which sets the appropriate components of the automemoization advice.
+Residing in keypath \refkeypath{/mmz/auto}, it is effectively defined as
+follows:
+
+\begin{tcblisting}{listing only}
+\mmzset{
+ auto/memoize/.style={
+ run if memoization is possible,
+ bailout handler=\mmz@auto@bailout,
+ outer handler=\mmz@auto@outer,
+ inner handler=\mmz@auto@memoize
+ }
+}
+\end{tcblisting}
+
+The heart of this advice is its inner handler, which actually triggers
+memoization by executing \refcmd{Memoize}. Remember that the first argument of
+\refcmd{Memoize} is the code which the md5sum is computed off of. This
+argument must therefore be identical to the author's invocation of the
+automemoized command or environment. Given what Advice offers, this is easy to
+construct: \refcmd{AdviceReplaced} holds the code replaced by the advice, and
+the \meta{arguments} of the automemoized command are waiting for us in |#1|.
+The second argument of \refcmd{Memoize} will be similar, but as this is the
+code which will get compiled, we have to execute the original definition of the
+command, followed by the (unbraced!) \meta{arguments} as |#1|; this is a job
+for \refcmd{AdviceOriginal}. (Note that \emph{executing}
+\refcmd{AdviceReplaced} would run the auto-handler again, resulting in an
+infinite loop! Or at least a pile of errors.)
+
+However, the overly simplistic approach shown below won't necessarily work.
+The issue is that the arguments of \refcmd{Memoize} contain
+\refcmd{AdviceReplaced} and \refcmd{AdviceOriginal} themselves, instead of their
+contents, i.e.\ (first) expansions.
+
+\begin{tcblisting}{listing only, bad}
+\long\def\mmz@auto@memoize#1{%
+ \Memoize{\AdviceReplaced#1}{\AdviceOriginal#1}%
+}
+\end{tcblisting}
+
+Regarding the first argument, the problem is that the code md5sum will be
+computed off of the token list \refcmd{AdviceReplaced}\meta{arguments} ---
+exactly as you see it.\footnote{If you inspected a c-memo, you would find
+ \refcmd{AdviceReplaced}\meta{arguments} in the \refcmd{mmzSource} section.}
+This implies that two commands sharing exactly the same \meta{arguments} will
+receive the same (c-)memo. For example, if you automemoized first
+|\textit{foo}| and then |\textbf{foo}|, both would come out as a bold ``foo''
+upon utilization.
+
+The second argument illustrates a general issue about the lifespan of
+\refcmd{AdviceOriginal} and other |\Advice...| commands.\footnote{The list of
+ all commands available only within the handler can be found in the
+ documentation of key \refmmzauto{outer handler} in
+ section~\ref{sec:ref:advice}.} By executing \refcmd{Memoize}, we leave the
+advice and thereby cannot be sure that when expanded, \refcmd{AdviceOriginal}
+will mean what it means at the moment. In general, another piece of advice might be
+triggered until its expansion, or the group might be closed, etc. For example,
+the author may have issued \refcmd{mmznext}\bracestt{\refmmz{at begin
+ memoization}=\cs{label}\marg{key}}, and as the pre-memoization code is
+executed before the memoization driver, the \cs{label}, which is submitted to
+Advice so that any \cs{label}s inside the memoized code ``just work'', would
+execute another piece of advice, redefining \refcmd{AdviceOriginal} and friends.
+Effectively, you'd end up memoizing an invocation of the \cs{label} command.
+
+The bottom line is that while the code following the above template
+\emph{might} sometimes work, Advice offers no guarantees that it will, so I
+advise against using it. The actual definition of the memoization inner
+handler is shown below. In this definition, we expand \refcmd{AdviceReplaced}
+and \refcmd{AdviceOriginal} --- exactly once! --- into the respective arguments
+of \refcmd{Memoize}; of course, as the entire invocation of \refcmd{Memoize} is
+expanded, we have to guard against expanding the collected arguments (|#1|) and
+\refcmd{Memoize} itself.\footnote{As the final touch, the handler also contains
+ \refcmd{ignorespaces} after the invocation of \refcmd{Memoize}, if this was
+ requested using \refmmz{ignore spaces}. Note that this could not be done
+ without pre-expanding the \cs{ifmmz@ignorespaces} conditional, as
+ \refcmd{Memoize} closes the group in which the auto- and the next-options are
+ applied.} The result of the expansion is shown under the code: the first and
+the second line assume we are automemoizing command |\foo| and environment
+|bar|, respectively. Note that \refcmd{AdviceOriginal} expands into an
+invocation of \refcmd{AdviceGetOriginal}, a command which may be safely used
+outside the advice; the first argument of this command is the auto-namespace
+(in our case, \refkeypath{/mmz}), and the second argument is the advised
+command. For a \hologo{LaTeX} environment, the advised command is actually
+\refcmd{begin}, and this is why the call of \refcmd{AdviceGetOriginal} is of
+course followed by the environment name.
+
+\makeexcerpt{_auto-memoize-inner}
+\tcbinputexample[.tex][.excerpt]{%
+ listing and comment, one file, no attachment,
+ title={The implementation of the \refmmzauto{inner handler}
+ for automemoization},
+ comment={%
+ $\rightarrow$ \refcmd{Memoize}\braces{\cs{foo}\Arg1}%
+ \braces{\refcmd{AdviceGetOriginal}\bracestt{/mmz}\bracestt{\cs{foo}}\Arg1}\\
+ $\rightarrow$ \refcmd{Memoize}\braces{\cs{begin}\bracestt{bar}\Arg1}%
+ \braces{\refcmd{AdviceGetOriginal}%
+ \bracestt{/mmz}\bracestt{\cs{begin}}\bracestt{bar}\Arg1}
+ }
+}
+
+Let us now move backwards in time and look at the outer handler installed by
+\refmmzauto{memoize}. It is very simple, but performs an important function of
+applying the auto- and the next-options (in this order), which also
+necessitates opening a group (closed by \refcmd{Memoize}). The final line
+invokes the argument collector, which then calls the inner handler; remember
+that the invocation of \refcmd{AdviceCollector} is the sole function of the
+default outer handler.
+
+\makeexcerpt{_auto-memoize-outer}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment,
+ title={The implementation of the \refmmzauto{outer handler}
+ for automemoization},
+}
+
+Moving even further back in time, we arrive at the run conditions. The
+\refmmzauto{memoize} style invokes \refmmzauto{run if memoization is possible},
+defined as \code{run conditions=\cs{mmz@auto@rc@if@memoization@possible}}, with
+the installed macro as shown below. Indeed, memoization only makes when
+Memoize is \refmmz{enable}d (which we test using \refcmd{ifmemoize}), but we're
+not already ``inside \refcmd{Memoize}'' (which we test using
+\refcmd{ifinmemoize}). The latter condition is true when we're either
+memoizing or regularly compiling some code submitted to memoization (see the
+diagram in section~\ref{sec:Memoize}). Note that it is not necessary to invoke
+\refcmd{AdviceRunfalse} in branches where the run conditions are not satisfied.
+
+\makeexcerpt{_auto-run-if-memoization-is-possible}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment,
+ title={The implementation of
+ \refmmzauto{run if memoization is possible}},
+}
+
+While it is clear that double memoization is a no-no, why should we avoid
+memoizing inside a regular compilation? Imagine that Memoize decides not to
+memoize a Forest tree, perhaps because \refmmz{readonly} is in effect. Under
+the hood, Forest creates many \env{tikzpicture}s. Should all of them be
+(auto)memoized now? Certainly not.
+
+Finally, what happens when the run conditions are not met? Not much, but
+something important nevertheless: by consuming the next-options, the
+\refmmzauto{bailout handler} makes sure they will not erroneously apply to the
+next instance of (auto)memoization.
+
+\makeexcerpt{_auto-memoize-bailout}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment,
+ title={The implementation of the \refmmzauto{bailout handler}
+ for automemoization},
+}
+
+The only component of the automemoization advice not determined by style
+\refmmzauto{memoize} is the argument collector, which allows the user to submit
+a command with a weird argument structure to automemoization simply by setting
+key \refmmzauto{collector} in addition to executing \refmmzauto{memoize}. For
+example, Memoize submits \refcmd{tikz} to automemoization by loading
+\reffile{advice-tikz.code.tex}, which contains Advice's definition of the
+\cs{tikz} collector \refcmd{AdviceCollectTikZArguments}, and issuing the
+following declaration.
+
+\makeexcerpt{_auto-tikz-collector}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment,
+ title={Declaring automemoization of command \cs{tikz}},
+}
+
+\paragraph{\refmmzauto[show keypath]{ref}}
+
+The cross-reference advice presents an example of an outer handler radically
+different from the default outer handler. This outer handler does not invoke
+the collector at all. As shown below, it grabs the argument of \refcmd{ref} (or
+whichever cross-referencing command) on its own --- remember that the outer
+handler receives the arguments of the handled command ``as they are,'' i.e.\
+uncollected. It then asks \refcmd{mmzNoRef} to do the real job of getting the
+reference key into the context, and finally executes the original \cs{ref}.
+
+\ExampleName{_auto-ref}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{%
+ listing only, no attachment,
+ title={\hypercolor{link}{white}A simplified\footnotemark{} definition
+ of \refmmzauto{ref}},
+ % This only works if there is a single footnote in the memoized code.
+ /mmz/context/.expanded={footnote=\numexpr\thefootnote-1},
+}\footnotetext{The real outer handler allows for arbitrary optional arguments of
+ the cross-referencing command, and shares code with \refmmzauto{force
+ ref}.}
+
+The run conditions of this style are agonizingly simple: \refmmzauto{run if
+ memoizing} sets \refmmzauto{run conditions} to a macro defined as
+\refcmd{ifmemoizing}\hyp\refcmd{AdviceRuntrue}\hyp\cs{fi}.
+
+\paragraph{\refmmzauto[show keypath]{abort}}
+
+The advice for aborting memoization is very simple --- it merely executes
+\refcmd{mmzAbort} --- but also very sneaky. Here, the \refmmzauto{run
+ conditions} do the real work of aborting memoization, while the ``real,''
+i.e.\ outer handler, never even gets executed; note the absence of
+\refcmd{AdviceRuntrue}, which implies \refcmd{AdviceRunfalse}, which triggers
+the execution of the original command after the run conditions are ``checked.''
+
+\makeexcerpt{_auto-abort}
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment,
+ title={The definition of \refmmzauto{abort}},
+}
+
+The point here is that executing \refcmd{mmzAbort} (itself a single-liner
+setting an internal conditional) is cheaper than testing for the real run
+conditions (\refmmzauto{run if memoizing}) and aborting only if they are
+satisfied. Of course, the trick only works because (i) the advice doesn't
+need to inspect any arguments of advised command, and because (ii) setting the
+internal abortion conditional outside memoization does no damage.
+
+\paragraph{Advice in chains}
+
+A command may be submitted to several instances of the advising framework,
+i.e.\ instances installed under different keypaths. In the example below, we
+submit |\foo| both to the instance of Advice installed in keypath |/one| and to
+the one installed in keypath |/two|. Under |/one|, the result of |\foo{...}|
+will be boxed (|\fboxWrap|); under |/two|, in will be parenthesized
+(|\parenWrap|). The order in which this happens depends on the order in which
+|\foo| was activated under different keypaths. If we first activate it under
+|/one| with the boxing effect and then under two with the parenthesizing
+effect, the box will appear within parenthesis; if we reverse the activation
+order, the parenthesis will appear inside the box.
+
+\ExampleName{chained-advice}
+\makeexample{\examplename.tex.c1 N=2}
+\tcbinputexample{comment=\input{\examplepath.tex.c2}}
+
+First of all, looking at the code above, you have probably noticed the absence
+of key \refmmz{auto}. This is because by default, \refkey{/handlers/.install
+ advice} defines the \emph{setup key} to be |advice| --- Memoize overrides
+this default by installing the framework with \refkey{/handlers/.install
+ advice}|=|\bracestt{\refkey{/advice/install/setup key}=auto, ...}.
+
+Next, |advice'| is a variant of |advice| which prevents automatic activation
+upon setup (and the same holds for |auto'| vs.\ |auto| in Memoize). We have
+used the bar variant above to make it clear that it is the order of activation,
+rather than declaration by |advice|\slash \refmmz{auto}, which matters in
+determining which handler is applied first.
+
+Finally, note that the deactivation order must be the reverse of the activation
+order. So if we activate |\foo| first in |/one| and then in |/two|, we should
+deactivate it in |/two| first and in |/one| next, otherwise Advice will
+complain.
+
+
+\paragraph{A simple collector}
+
+Let us implement a collector for a command which accepts one (standard
+\hologo{LaTeX}) optional argument and one mandatory argument; in \pkg{xparse}
+terms, a command with argument specification |om|.
+
+Using \cs{NewDocumentCommand}, such a collector is very easy to implement. We
+simply define a command with signature |om| and distinguish two possibilities
+regarding the presence of the optional argument, which we test using
+\cs{IfValueTF}. If the true branch, we pass a \emph{braced} |[#1]{#2}| to the
+inner handler, which we invoke by \refcmd{AdviceInnerHandler}; in the false
+branch, we omit the optional argument, passing it an (additionally) braced
+|{#2}|.
+
+\ExampleName{om-collector-NewDocumentCommand}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing only}
+
+Defining a functionally equivalent collector using \cs{newcommand} would be a
+bit more involved, as \hologo{LaTeX2e} does not offer a standardized way to
+test for the \emph{presence} of the optional argument. Consider the following
+collector, whose optional argument has the same default value as the advised
+command. Is it functionally equivalent to the one above?
+
+\ExampleName{om-collector-newcommand}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing only}
+
+While there will be no visual difference, there is a difference under the hood.
+If you compile both documents, you will see that the first one creates three
+memos\slash externs, while the second one only creates two: |\foo{...}| does
+not have its own memo anymore, but creates and uses the same memo as
+|\foo[green]{...}|.
+
+While the second version might sometimes be preferred, perhaps even in the
+context of memoization, the initial collector, which deploys command
+\refcmd{CollectArguments}, behaves like the \cs{NewDocumentCommand}-defined
+collector above,\footnote{In fact, there is a slight difference after all.
+ While the above-defined collector won't distinguish between the single-token
+ mandatory argument given with or without braces, \refcmd{CollectArguments}
+ will again faithfully replicate the original argument tokens.} as it attempts
+to perfectly replicate the command invocation. Furthermore, this behaviour
+makes it unnecessary for the author to provide the default values of optional
+arguments (and even allows them to replace |O{default}| in the argument
+specification by \docref{xparse:o}).
+
+We now turn to the package CollArgs, which implements the actual argument
+collection; we'll revisit the initial collector of Advice at the end of the
+following subsection.
+
+
+
+\subsubsection{Using package CollArgs}
+\label{sec:collargs}
+
+Automemoization is implemented on top of the framework offered by package
+Advice, and that package in turn couldn't really work as intended without
+package CollArgs. A regular user of Memoize shouldn't need to know anything
+about CollArgs, but a package writer wanting to support Memoize might have to.
+
+The package provides two public commands, \refcmd{CollectArguments} and
+\refcmd{CollectArgumentsRaw}; we'll focus on the former first.
+\refcmd{CollectArguments} takes three arguments: optional \meta{options} in the
+form of a \pkg{pgfkeys} keylist; a mandatory \meta{argument specification} in a
+(slightly extended) \pkg{xparse} format; and the \meta{next-code}:
+\begin{center}
+ \refcmd{CollectArguments}\oarg{options}\marg{argument specification}\marg{next-code}%
+ \textcolor{gray}{\meta{tokens}}
+\end{center}
+Following the three formal arguments of \refcmd{CollectArguments} are some
+\meta{tokens} --- the rest of the document, really --- and the job of
+\refcmd{CollectArguments} is to figure out the extent to which these
+\meta{tokens} conform to the given \meta{argument specification}. In other
+words, \refcmd{CollectArguments} will consume as many of the \meta{tokens} as a
+\meta{command} defined by \refcmd{NewDocumentCommand}\meta{command}\marg{argument
+ specification}\bracestt{...} would. Once these \meta{argument tokens} are
+collected, \refcmd{CollectArguments} executes the \meta{next-code} with the
+\meta{argument tokens} given as a single, braced argument (clearly, the
+\meta{rest} of the \meta{tokens}, i.e.\ the non-consumed tokens, will follow):
+\begin{center}
+ \meta{next-code}\marg{argument tokens}\textcolor{gray}{\meta{rest}}
+\end{center}
+
+In the example below, we define macro |\PrintAndDo|, which takes two arguments,
+a command and the collected arguments of that command, prints out which command
+we're about to execute and with what arguments, and then executes that command
+with those arguments --- |#1#2| at the end of the definition. Note that |#2|
+immediately following |#1| is not braced, so
+|\PrintAndDo\makebox{[5em][r]{text}}| executes |\makebox[5em][r]{text}|.
+
+{\tolerance 1000 Executing |\PrintAndDo\makebox{[5em][r]{text}}| directly would
+ thus yield the first line of the result below --- and in fact, this is
+ precisely what gets executed to yield that line, but in a roundabout fashion.
+ Given the argument specification |oom| (two optional arguments followed by a
+ mandatory argument), \refcmd{CollectArguments} figures out how many tokens
+ following its formal arguments conform to this argument specification ---
+ below, these would be |[5em][r]{text}| following
+ \refcmd{CollectArguments}\hyp|{oom}{\PrintAndDo\makebox}|--- and puts them,
+ braced, behind its \meta{next-code} argument, |\PrintAndDo\makebox|, yielding
+ |\PrintAndDo|\hyp|\makebox{[5em][r]{text}}|.\par}
+
+\ExampleName{collargs-makebox}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing and compile}
+
+Seeing the arguments of |\makebox| without the immediately preceding |\makebox|
+might seem strange, but remember that \refcmd{CollectArguments} is about the
+arguments of a command, not about the command's control sequence. It doesn't
+know or care which command the argument tokens ``belong'' to, as long as they
+conform to the given specification. In the example above, it is only in |#1#2|
+of |\PrintAndDo| that |\makebox| is ``reunited'' with its arguments, but note
+that the reunion is far from obligatory.
+
+CollArgs supports all the argument types (and modifiers) that \pkg{xparse}
+does, including the environment type \docref{xparse:b}, as exemplified below.
+Again, the code below might seem strange, as it features an |\end{minipage}|
+without the matching |\begin{minipage}|, but the logic is similar as for
+ commands: just as \refcmd{CollectArguments} occurs in front of the command
+ arguments, without the command itself, so it occurs in front of the
+ environment body, without the opening of that body. However, while
+ \refcmd{CollectArguments} never needs to know the command name, we need to
+ inform it of the environment name, so that it can find the end of the
+ environment. This can be achieved as shown below, using key
+ \refcollargs{environment} in the optional argument of the command, or by our
+ extension to the \pkg{xparse} argument specification, where the environment
+ argument type \docref{xparse:b} may be followed by a braced environment name.
+ In the example below, we could therefore also invoke argument collection by
+ \refcmd{CollectArguments}\braces
+ {\docref{xparse:+}\docref{xparse:b}\braces{\env{minipage}}} (we have preceded
+ \docref{xparse:b} with a \docref{xparse:+} to allow for an environment body
+ containing paragraph tokens).\footnote{CollArgs automatically adapts to the
+ format, i.e.\ it knows that environments are tagged by \cs{}\meta{name} and
+ \cs{end}\meta{name} in \hologo{plainTeX} and by \cs{start}\meta{name} and
+ \cs{stop}\meta{name} in \hologo{ConTeXt}.}
+
+\ExampleName{collargs-minipage}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{comment=\input{\examplepath.tex.c1}}
+
+You might wonder why didn't we provide \refcmd{CollectArguments} in the
+previous example with argument specification |omb| --- after all, the
+\env{minipage} environment takes an optional and a mandatory argument. While that
+would work, and produce the same result,\footnote{Unless argument processing
+ was in effect; see section~\ref{sec:ref:collargs} for details.} note that
+\refcmd{CollectArguments} is only interested in finding the scope of the
+arguments, and grabbing everything until |\end{minipage}| is the same as first
+grabbing the optional argument, maybe, then the mandatory argument, and finally
+the argument body.
+
+\refcmd{CollectArguments} not only supports \pkg{xparse}'s verbatim argument
+type \docref{xparse:v}, it can grab an argument of \emph{any} type in the
+verbatim mode, triggered by option \refcollargs{verbatim}.\footnote{We refer to
+ the verbatim mode triggered by \refcollargs{verbatim} as the full verbatim
+ mode, where all characters are of category ``other''. There is also the
+ partial verbatim mode, triggered by \refcollargs{verb}, where braces retain
+ their normal category codes.} We illustrate this key below, where we also use
+option \refcollargs{tags}, which makes CollArgs automatically surround the
+grabbed environment body with the begin tag \refcmd{begin}\marg{environment
+ name} and the end tag \cs{end}\marg{environment name}, and use
+\refcmd{scantokens} to execute the grabbed environment. Consult
+section~\ref{sec:ref:collargs} for the full reference on the verbatim mode and
+its limitations.
+
+% A harmless warning:
+% Missing character: There is no ^M (U+000D) in font [lmmono10-regular]:!
+% because \texttt in the example is fed a (verbatim) carriage return
+\ExampleName{collargs-verbatim}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{listing and compile}
+
+Finally, CollArgs extends the \pkg{xparse} specification by modifier
+\docref{xparse:amp}, which allows the user to specify options which apply only
+to the following argument, as opposed to the options given as the optional
+argument of \refcmd{CollectArguments}, which apply to all the arguments. A
+third way to invoke the environment body collection in the above example is
+thus \refcmd{CollectArguments}%
+\bracestt{\docref{xparse:amp}\bracestt{\refcollargs{environment}=minipage}+b}.
+
+Both the single-argument and the common options can be given not only as
+\pkg{pgfkeys} keys, but also in the raw, ``programmer's interface'' format.
+Every option key has a corresponding macro; for example, key
+\refcollargs{environment} is matched by macro \refcmd{collargsEnvironment}.
+The macros are listed alongside their corresponding keys in the reference
+section~\ref{sec:ref:collargs}; here, we merely learn how to use them.
+
+To use raw options for a single argument, double the ampersand in the argument
+specification. Therefore, the fourth way to specify the environment name is
+\code{\docref{xparse:amp}\docref{xparse:amp}\bracestt{%
+ \refcmd{collargsEnvironment}\bracestt{minipage}}\docref{xparse:+}\docref{xparse:b}}.
+
+To set the raw options for all arguments, use \refcmd{CollectArgumentsRaw}, the
+second public command of the package. This command is exactly like
+\refcmd{CollectArguments}, excepts that it expects the options in the raw
+format and as a \emph{mandatory} argument:
+
+\begin{center}
+ \refcmd{CollectArgumentsRaw}\marg{raw options}\marg{argument specification}%
+ \marg{next-code}\textcolor{gray}{\meta{tokens}}
+\end{center}
+
+This leads us to the fifth way to set the environment name (an overkill, I
+know): \refcmd{CollectArgumentsRaw}\hyp
+\bracestt{\refcmd{collargsEnvironment}\bracestt{minipage}}\bracestt{+b}\marg{next-code}.
+Furthermore, you can use a mixture of raw and key--value options: the raw
+option commands include \refcmd{collargsSet}, which applies the given option
+keylist. The idea here (incarnated by both Auto and Memoize) is that the
+package will provide CollArgs with the raw options, for speed, while the
+author can supplement them in the friendly keylist format --- and this leads
+us to the sixth, and thankfully final way to set the environment name:
+\refcmd{CollectArgumentsRaw}\bracestt{\refcmd{collargsSet}%
+ \bracestt{\refcollargs{environment}=minipage}}\bracestt{+b}\marg{next-code}.
+
+
+\paragraph{The initial collector}
+
+As the final example, let us study Advice's initial collector; this is a macro
+which is used as the collector when key \refmmzauto{collector} is not given.
+This macro is not really \refcmd{CollectArguments}, as we sometimes state to
+simplify matters, but a macro which acts as the ``bridge'' between Advice and
+CollArgs, by compiling an invocation of \refcmd{CollectArgumentsRaw} from the
+given advice setup, and executing it.
+
+The bridge macro is shown below in its full glory, but it is really less
+complicated than it might appear at first sight. In line~2, we use
+\refcmd{AdviceIfArgs} to see whether the argument structure of the handled
+command was given by the user. If it wasn't, we assume that the handled
+command was defined using \cs{NewDocumentCommand} or similar, and use
+\refcmd{GetDocumentCommandArgSpec} to retrieve it (line~3; note that
+\refcmd{AdviceName} holds the handled control sequence) and store it into
+\refcmd{AdviceArgs} (line~4), which also receives the argument specification
+when given by the user via key \refmmzauto{args}.
+
+\makeexcerpt{_advice-CollectArgumentsRaw}(../../advice.edtx)
+\tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment,
+ listing options app={numbers=left, numberstyle=\tiny, numbersep=0.5em},
+ title={The definition of the initial collector},
+}
+
+Lines~6--17 are somewhat of an expansion mess, because we have to construct the
+invocation of the CollArgs' collector from the advice setup stored in various
+macros. But once we think away all the (non-)expansion commands, we're left
+with \refcmd{CollectArgumentsRaw} plus the following three arguments:
+\begin{enumerate}
+\item The raw options (lines 8--11):
+ \begin{enumerate}
+ \item In line 8, the advised command's control sequence is designated as the
+ \refcollargs{caller}. The effect is that if the given arguments don't
+ conform to the specification, the error thrown seems to come from the
+ advised command rather than some internal CollArgs macro. The author will
+ be grateful for this little detail.
+ \item In line 9, we add any \refmmzauto{raw collector options} set by Advice
+ (plus the package deploying Advice, like Memoize); user-given options are of
+ course possible, but not really expected here, because:
+ \item In lines 10--11, we add the user-given \refmmzauto{collector options},
+ if there are any, embedded under \refcmd{collargsSet}.
+ \end{enumerate}
+\item The argument specification (line 14).
+\item The \refmmzauto{inner handler} (line 15).
+\end{enumerate}
+
+
+
+\section{Reference}
+\label{sec:reference}
+
+In this section, the extra information about keys, offered at the right of a
+key in parenthesis, may contain the initial value of a key, and also a default
+value of a key. In this context, the terms ``initial'' and ``default'' have
+the meaning employed by the \pkg{pgfkeys} utility. Initial value refers to the
+value that is set by the package. More often, we would call this the default
+or the package-default value, but in the \pkg{pgfkeys} parlance, the default value
+refers to the value that is passed to the key in the absence of the argument.
+Honestly, I only kept to this convention in the reference section; elsewhere,
+I often say ``default'' or ``package-default'' and mean the initial value.
+
+Another convention I kept to in this section is the color-coding of the keys
+and commands. Green background indicates a basic key or command, which any
+user might want to know about. Red background indicates other, more or less
+advanced keys and commands.
+
+
+\subsection{Loading}
+\label{sec:ref:loading}
+\paragraph{\hologo{LaTeX}}
+
+Load Memoize by \cs{usepackage}\braces{\docaux{package}{memoize}} or
+\cs{usepackage}\oarg{options}\bracestt{memoize}. The latter form functions
+almost identically to the former followed by
+\refcmd{mmzset}\bracestt{\meta{options}}, with two exceptions.
+
+First, the \meta{options} as package options may not contain spaces. This is a
+constraint imposed by \hologo{LaTeX} itself. To avoid it for a particular key,
+define a spaceless variant of the key in \reffile{memoize.cfg}. For example,
+to use \refmmz{memo dir} as a package option, put
+\refcmd{mmzset}|{memodir/.style={|\refmmz{memo dir}|={#1}}}| into that file.
+
+Second, key \refmmz{extract} only make senses as a package option, or within
+\reffile{memoize.cfg}. Internal extern extraction can only be performed before
+the output PDF is opened, and to maximize chances of that, Memoize is designed
+to extract as soon as it can: while it is being loaded. Consequently, changing
+the extraction method in the document preamble has no effect.
+
+The necessity of performing extraction before the output PDF is opened is also
+why Memoize prefers to be loaded early with respect to other packages. In
+particular, it must be loaded before \PGF library |fadings| (see
+section~\ref{sec:fadings-problem}) and before the \pkg{beamer} class (see
+section~\ref{sec:tut:beamer}).
+
+If you're familiar with the \TikZ externalization library, you might wonder
+whether Memoize has an equivalent of the \refcmd{tikzexternalize} command. It
+doesn't. Memoize assumes that if you loaded it, you want to use it --- but you
+can always disable it using key \refmmz{disable}, or even by loading package
+\refpkg{nomemoize} in its stead.
+
+In \hologo{LaTeX}, initialization and finalization are completely automatic.
+Memoize defines several initialization and finalization styles ---
+\docaux{key}{begindocument/before}, \docaux{key}{begindocument},
+\docaux{key}{begindocument/end} and \docaux{key}{enddocument/afterlastpage}
+---and executes them at the cognominal \hologo{LaTeX} hooks.
+
+\paragraph{\hologo{plainTeX}}{}
+
+Load Memoize by |\input memoize|. As package options cannot be provided in
+\hologo{plainTeX}, the author must trigger extraction from \refcmd{mmzset}
+using key \refmmz{extract}; I recommend doing this immediately after loading
+the package. This key may be invoked with or without a value. In the latter
+case, Memoize will extract using the package default method
+\refmmz{extract=perl}, unless its has been overriden from
+\reffile{memoize.cfg}.
+
+Furthermore, as \hologo{plainTeX} has no concept of a document body, the text
+must be manually enclosed in \refcmd{mmzset}\bracestt{\docaux{key}{begin
+ document}} and \refcmd{mmzset}\bracestt{\docaux{key}{end document}}; this
+is where the initialization and finalization hooks described above will be
+executed. Note that \refmmz{extract}, when used, must precede this enclosure.
+
+Finally, \hologo{plainTeX} has another reason for preferring the early loading
+of the package. In this format, Memoize must redefine \refcmd{shipout}, at a
+time the meaning of this control sequence is still primitive. In particular,
+this means that Memoize must be loaded before \pkg{atbegshi}.
+
+\begin{tcboxedraster}[raster column skip=1cm]{blankest}
+ \ExampleName{plainTeX}%
+ \makeexample{\examplename.tex.c1}%
+ \tcbinputexample{listing only, title=A minimal \hologo{plainTeX} example}
+ %
+ \ExampleName{ConTeXt}%
+ \makeexample{\examplename.tex.c1}%
+ \tcbinputexample{listing only, title=A minimal \hologo{ConTeXt} example}
+\end{tcboxedraster}
+
+\paragraph{\hologo{ConTeXt}}{}
+
+Load Memoize by \cs{usemodule}\bracketstt{memoize} or
+\cs{usemodule}\bracketstt{memoize}\oarg{options}. Unlike in \hologo{LaTeX},
+spaces are allowed in \meta{options}; the remarks on key \refmmz{extract} and
+loading order are the same as for \hologo{LaTeX}.
+
+In \hologo{LaTeX}, Memoize automatically executes its initialization and
+finalization code when at the beginning and the end of the document body. Due
+to my very limited experience with \hologo{ConTeXt}, and its project structure
+in particular, I don't know what the appropriate place for initialization and
+finalization would be in \hologo{ConTeXt}. I therefore provisionally leave it
+to the author to execute \refcmd{mmzset}\bracestt{\refmmz{begin document}} and
+\refcmd{mmzset}\bracestt{\refmmz{end document}} manually, and hope for advice
+on how to handle this properly.
+
+
+\paragraph{Auxiliary packages}
+
+\begin{doc}{package={name=nomemoize}}
+ Loading this package instead of Memoize completely disables memoization, but
+ does not require removing any Memoize commands from the document (they all
+ become no-ops).
+\end{doc}
+
+\begin{doc}{package={name=memoizable}}
+ This package is a programmer's stub: if Memoize is loaded, it does nothing;
+ otherwise, it provides the no-op variants Memoize commands. See
+ section~\ref{sec:loading-memoize} for details.
+\end{doc}
+
+
+\subsection{Configuration}
+\label{sec:ref:configuration}
+
+
+\begin{doc}{easy,cmd={name=mmzset, par=\marg{options}}}
+
+ Update the Memoize configuration.
+
+ The \meta{options} are a comma-separated list of \meta{key}|=|\meta{value}
+ pairs. They are processed using the \pkg{pgfkeys} utility of PGF/\TikZ (see
+ \PGFmanual{87}), with the default path set to \docaux{key path}{mmz}.
+
+ The changes are local to the current \hologo{TeX} group, except for keys
+ where explicitly noted otherwise.
+\end{doc}
+
+\begin{doc}{easy,
+ cmd={name=mmznext, par=\marg{options}},
+ }
+
+ This command accepts the same \meta{options} as \refcmd{mmzset}, but
+ interprets them as \emph{next-options} --- options which will be applied to
+ the next, and only the next, \emph{auto}memoized command or environment.
+ (Remember that a command or environment is submitted to automemoization by
+ \refmmz{auto}|=|\marg{command or
+ environment}\bracestt{\refmmzauto{memoize},...}; see
+ sections~\ref{sec:tut:automemoization}, \ref{sec:tut:working-on-a-picture}
+ and \ref{sec:ref:advicememoization} for details.)
+
+ Remarks for the author:
+
+ \begin{itemize}
+ \item Key \refmmz{enable} has no effect inside \refcmd{mmznext}.
+ \item If \refcmd{mmznext} is used more than once preceding an automemoized
+ command, only the final invocation takes effect.
+ \item The next-options also apply to commands and environments for which
+ memoization is autodisabled via \refmmz{auto}|=|\marg{command or
+ environment}\bracestt{\refmmzauto{nomemoize},...}.
+ \item It is safe to set the next-options in front of a command submitted to
+ automemoization which does not actually undergo memoization in this
+ particular instance. In other words, the absence of memoization will not
+ cause the next-options to ``leak'' to the next automemoized command.
+ \item Only the linear (execution) order of \refcmd{mmznext} and the
+ automemoized command matters. Key \refcmd{mmznext} will correctly apply to
+ a single following automemoized command even if it occurs outside the group
+ which that command is executed from; and it will apply to the following
+ automemoized command even if it is called within a group closed before that
+ command is executed.
+ \end{itemize}
+
+ Remarks for the programmer:
+ \begin{itemize}
+ \item The next-options are set globally.
+ \item The effect of \refcmd{mmznext} is \emph{not} cumulative. Consequently,
+ \refcmd{mmznext}\braces{} clears the next-options.
+ \item The next-options are applied by executing \refcmd{mmzAutoInit} within
+ the advice. Any piece of advice applying the next options should also clear them
+ when the \refmmzauto{run conditions} are not met. This is streamlined by
+ style \refmmzauto{apply options}, intended for use within \refmmz{auto}
+ declarations. Out of the box, this style is deployed by
+ \refmmzauto{memoize}, \refmmzauto{nomemoize} and \refmmzauto{noop}, but it
+ may be used by any piece of advice. Note that the \refmmzauto{outer handler}
+ declared by this style opens a group (to apply the options in) but leaves
+ it to the (undeclared) \refmmzauto{inner handler} to close that group.
+ \item Key \refmmz{enable} has no effect inside \refcmd{mmznext} because when
+ Memoize is disabled upon encountering an automemoized command, the advice
+ bails out without ever applying the next-options. More generally, this
+ applies to any advised command whose run conditions require
+ \refcmd{ifmemoize} to be true. Key \refmmz{disable}, on the other hand,
+ takes effect, because \refcmd{ifmemoize} is checked within \refcmd{Memoize}
+ as well.
+ \end{itemize}
+\end{doc}
+
+\begin{doc}{easy,file={name=memoize.cfg, desc=file}}
+ The configuration file, loaded just before processing the package options.
+ It will typically contain a \refcmd{mmzset} command, but it may contain any
+ \hologo{TeX} code.
+
+ As for any other file loaded by \hologo{TeX}, the location of the file
+ determines whether it applies system-wide, user-wide or directory-wide.
+
+ This file is also loaded by package \refpkg{nomemoize}, on the off chance it
+ defines some commands other than \refkeypath{/mmz} keys. (It is not loaded
+ by package \refpkg{memoizable}, though).
+\end{doc}
+
+\begin{doc}{cmd={name=nommzkeys, par=\marg{key}}}
+ In package \refpkg{memoize}, this command is a no-op; in packages
+ \refpkg{nomemoize} and \refpkg{memoizable}, it defines key
+ \refkeypath{/mmz}|/|\meta{key} as a no-op.
+
+ As explained in section~\ref{sec:tut:final}, use this command to declare any
+ \refkeypath{/mmz} keys you have used outside \refcmd{mmzset} when switching
+ to package \refpkg{nomemoize}.
+\end{doc}
+
+
+\subsection{Memoization}
+\label{sec:ref:memoization}
+
+\subsubsection{Manual memoization commands}
+\label{sec:ref:memoization:manual}
+
+\begin{doc}{easy,
+ cmd={name=mmz, par=\oarg{options}\marg{code}},
+ env={name=memoize, par=\oarg{options}},
+ }
+ Submit \meta{code} or \meta{environment body} to memoization.
+
+ Prior to memoization, the configuration is locally updated by executing
+ \meta{options} given as the optional argument to this command, i.e.\ the
+ given options take precedence to options previously set via \refcmd{mmzset}.
+ Note that next-options, set by \refcmd{mmznext}, are not applied.
+
+ The effect of the macro and of the environment version of this command is the
+ same, except that the command version memoizes \meta{code} exactly as-is,
+ while the environment version trims away any spaces at the beginning and the
+ end of the code.\footnote{What actually happens is that at the beginning of
+ the environment body, all space tokens will be discarded. At the end of
+ the body, no spaces are actually discarded; Memoize simply issues an
+ \refcmd{unskip}. This should not matter to a regular user who simply
+ writes down the environment.} The space-trimming feature of the environment
+ ensures that you can write |\begin{memoize}| and |\end{memoize}| in separate
+ lines (as shown above), but no extra space will creep into the extern.
+
+ The space-trimming feature of the environment, which trims spaces at the
+ beginning and at the end of the \meta{environment body}, should not be
+ confused with the effect of \refmmz{ignore spaces}, which ignores spaces
+ following the environment end-tag (in \hologo{LaTeX}, |\end{...}|) --- and
+ which does not apply to manual memoization at all!
+
+ The argument of \refcmd{mmz} \emph{must} be enclosed in braces.
+\end{doc}
+
+\begin{doc}{easy,
+ cmd={name=nommz, par=\oarg{options}\marg{code}},
+ env={name=nomemoize, par=\oarg{options}},
+ }
+ Disable Memoize for the span of the compilation of \meta{code} or
+ \meta{environment body}.
+
+ This command consumes the \meta{options} in the same way as
+ \refcmd{mmz}\slash \refenv{memoize} described above. The macro and the
+ environment version of the command exhibit the same space-trimming behaviour
+ as their \refcmd{mmz}\slash \refenv{memoize} counterparts, and the argument
+ of \refcmd{nommz} \emph{must} be enclosed in braces.
+\end{doc}
+
+
+\subsubsection{Basic configuration}
+\label{sec:ref:memoization:basic}
+
+\begin{doc}{easy,
+ key={name=enable},
+ key={name=disable},
+ }
+ Enable or disable the functionality of the package.
+
+ What happens when Memoize is enabled depends on the memoization mode
+ (\refmmz{normal}, \refmmz{readonly}, \refmmz{recompile}) and many other
+ factors. When the package is disabled, it neither creates new memos and
+ externs, nor uses the existing ones; this applies to both manual and
+ automatic memoization. The effect is close to not having Memoize loaded, or
+ to loading NoMemoize, but it is not completely the same; for example, the
+ record file (\dmmz) \emph{is} updated while Memoize is disabled, reflecting
+ the fact that nothing was memoized (or utilized) in the disabled
+ state.\footnote{Cleaning the folder (\S\ref{sec:cleanup-scripts}) after
+ disabling the package for the entire document is thus a bad idea.}
+
+ If these keys are used in the preamble, their effect is delayed until the
+ beginning of the document, to ensure that Memoize is never enabled in the
+ preamble. Other than that, all these keys do is set the \hologo{TeX}
+ conditional \refcmd{ifmemoize}, which you may use in your code to test
+ whether Memoize is enabled. You may also use \refcmd{memoizetrue} and
+ \refcmd{memoizefalse}, as long as you never enable the package in the
+ preamble.
+
+ Key \refmmz{enable} cannot be applied to automemoized commands via
+ \refcmd{mmznext}. It will take effect for manual memoization, though, and
+ key \refmmz{disable} will work for both, as expected.
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=normal, desc=the default mode},
+ key={name=readonly},
+ key={name=recompile},
+ }
+
+ Select the memoization mode.
+
+ Each piece of code submitted to (either manual or automatic) memoization is
+ associated to several files: one c-memo, one cc-memo, and some externs (zero
+ or more, typically one). When Memoize encounters a piece of code submitted
+ to memoization, it takes one of the following actions:
+
+ \begin{description}
+ \item[memoization] The code is compiled in a special way which produces the
+ associated memos and externs.
+ \item[utilization] The code is not compiled. Its effect is replicated by
+ processing the cc-memo; typically, this includes the single extern into the
+ document.
+ \item[regular compilation] The code is compiled as if Memoize was absent or
+ disabled (the memos and externs are neither utilized nor produced).
+ \end{description}
+
+ \begin{minipage}[t]{0.48\linewidth}
+ The action taken depends on the memoization mode and on whether all the
+ memos and externs associated with the code exist, as shown in the table on
+ the right. Note that a single missing memo or extern implies the ``no''
+ column of the table, and that memoization will create \emph{all} the
+ associated memos and externs, even those which already exist.
+ \end{minipage}
+ \hfill
+ \begin{tabular}[t]{@{}lll@{}}
+ \toprule
+ &\multicolumn{2}{c}{Do the memos and externs exist?}\\
+ \cmidrule{2-3}
+ mode&yes&no\\
+ \midrule
+ normal&utilization&memoization\\
+ readonly&utilization&regular compilation\\
+ recompile&memoization&memoization\\
+ \bottomrule
+ \end{tabular}
+
+ The memoization mode only has effect when Memoize is \refmmz{enable}d. Mode
+ selection is orthogonal to enabling\slash disabling the package; for example,
+ if you switch to a new mode while the package is disabled, the new mode will
+ be in effect once the package is enabled.
+\end{doc}
+
+
+\begin{doc}{easy,
+ desc={style},
+ key={name=verbatim},
+ key={name=verb},
+ key={name=no verbatim},
+ }
+ When \refmmz{verbatim} or \refmmz{verb} is in effect, the code submitted to
+ memoization is read verbatim; \refmmz{no verbatim} reverts to the normal,
+ non-verbatim collection of the code. This applies to both manual and
+ automatic memoization.
+
+ The long version, \refmmz{verbatim}, switches to the full verbatim mode,
+ where all characters are assigned category code 12 (other). With the short
+ version, \refmmz{verb}, the braces, |{| and |}|, retain category codes 1 and
+ 2, which can be useful for verbatim collection of optional arguments. For
+ details, see the documentation of CollArgs' \refcollargs{verbatim} in
+ section~\ref{sec:ref:collargs}.
+
+ Under the hood, these keys have two effects. First, they are passed on to the
+ argument collector (typically, \refcmd{CollectArguments} of the auxiliary
+ package CollArgs; for details, see section~\ref{sec:ref:advicememoization}),
+ instructing it to collect the code in the specified fashion, as described
+ above. Second, if the collected verbatim code is eventually compiled (either
+ regularly, or memoized), Memoize first rescans it using \refcmd{scantokens}.
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=padding left, par=\meta{dimension},
+ desc={no default, initially |1| |in|}},
+ key={name=padding right, par=\meta{dimension},
+ desc={no default, initially |1| |in|}},
+ key={name=padding top, par=\meta{dimension},
+ desc={no default, initially |1| |in|}},
+ key={name=padding bottom, par=\meta{dimension},
+ desc={no default, initially |1| |in|}},
+ }
+ Set the left/right/top/bottom padding of the extern in the extern PDF.
+
+ Without padding, the (PDF) page holding the extern would tightly fit the
+ bounding box of the extern. These keys enlarge the extern page by the given
+ amounts, so that any parts of the extern lying outside the bounding box will
+ be correctly included when using the extern. See
+ section~\ref{sec:tut:padding} for details.
+
+ \meta{dimension} is evaluated with \hologo{eTeX}'s |\dimexpr|, and may
+ contain control sequences \docaux{cmd}{width}, \docaux{cmd}{height} and
+ \docaux{cmd}{depth}, which will refer to the dimensions of the extern.
+ \refcmd{width} and friends behave like dimension registers, so it is ok to write
+ e.g.\ \refmmz{padding right}|=0.5\width|.
+
+ The default padding is what \hologo{pdfTeX} puts around the page anyway, 1
+ inch, but we use |1 in| rather than |1 true in|, which is the true default
+ value of PDF registers \docref{pdfvar:horigin} and \docref{pdfvar:vorigin},
+ as we want the padding to adjust with \refcmd{mag}nification.
+\end{doc}
+
+\begin{doc}{easy,key={name=padding, par=\meta{dimension}, desc={style, no default}}}
+ Set all the above |padding| keys to the given value.
+\end{doc}
+
+\begin{doc}{
+ easy,
+ key={name=context, par=\meta{tokens}, desc={cumulative, no default,
+ initially set by \refmmz{padding to context}}},
+ key={name=clear context},
+ }
+ These keys append the given \meta{tokens} to the \emph{context expression},
+ or clear this expression. Memoized code gets recompiled whenever the
+ expansion of the context expression changes.
+
+ The \meta{tokens} must be fully expandable (modulo protection); in
+ \hologo{LaTeX}, they will be expanded by |\protected@edef| when calculating
+ the md5sum of the context.
+
+ The context expression is evaluated at the end of the memoization, and at
+ utilization attempts after inputting the c-memo (note that the c-memo
+ contains any additions to the context expression accumulated during
+ memoization). At evaluation, the given context expression is fully expanded,
+ yielding the \emph{context value}, whose md5 sum forms the \meta{context md5
+ sum} part of the filename of the cc-memo and the extern.
+
+ These keys may be used both prior to the memoization process, or during
+ memoization. In the former case, their effect is local to the current group;
+ in the latter case, the effect is global, so that the changes surely survive
+ until the end of memoization, when the c-memo, where the context expression
+ is stored, is written into a file.
+
+ Under the hood, these keys manipulate token registers
+ \docaux{cmd}{mmzContext} and \docaux{cmd}{mmzContextExtra}, changing the
+ contents of the former while not memoizing, and the contents of the latter
+ during memoization. These token registers may also be manipulated directly
+ by the user, as long as one keeps to the convention of adjusting
+ \refcmd{mmzContext} locally and only while not memoizing, and adjusting
+ \refcmd{mmzContextExtra} globally and only during memoization.
+\end{doc}
+
+\begin{doc}{
+ key={easy, name=meaning to context,
+ par=\marg{comma-separated list of commands and environment names}},
+ key={name=csname meaning to context, par=\marg{control sequence name}},
+ key={name=key meaning to context,
+ par=\marg{full path to a pgfkeys command key}},
+ key={name=key value to context,
+ par=\marg{full path to a pgfkeys value key}},
+ }
+ These keys append the definition of the given construct to the context.
+
+ Essentially, the ``meaning'' keys append \cs{meaning}\meta{control sequence}
+ to the context, for the appropriate \meta{control sequence}. For example,
+ \refmmz{meaning to context} appends \cs{meaning}\cs{foo} when given \cs{foo}
+ as in item in the list, and it appends the internal environment macros
+ appropriate to the format when given an environment name. Similarly,
+ \refmmz{key meaning to context} resolves \meta{control sequence} to the
+ internal macro holding the key command.
+
+ Key \refmmz{key value to context} should be used on keys which store values,
+ e.g.\ keys initialized by \pkg{pgfkeys} handler \code{.initial}; see
+ \PGFmanual{87.3.4 and \S87.4.5}.
+
+ All the keys prefix the meaning\slash value by the name of the command\slash
+ environment\slash key, in order to prevent ambiguous contexts, see
+ section~\ref{sec:cross-referencing} for details. Furthermore, they all
+ operate through \code{\cs{csname}...\cs{endcsname}} construct, allowing one
+ to safely add internal commands to the context.
+\end{doc}
+
+\begin{doc}{
+ keypath={/handlers},
+ key={easy, name=.meaning to context},
+ key={name=.value to context},
+ }
+ These are the handler variants of \refmmz{key meaning to context} and
+ \refmmz{key value to context}.
+\end{doc}
+
+
+\begin{doc}{key={name=padding to context,desc=style}}
+ This key appends the values of the \refmmz{padding} keys to the context,
+ causing the memoized code to be recompiled whenever the padding values are
+ changed. This key is used to initialize \refmmz{context}, so the author
+ normally shouldn't have to use this key.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzNoRef, par=\marg{reference key}, desc=\hologo{LaTeX} only},
+ cmd={name=mmzForceNoRef, par=\marg{reference key}, desc=\hologo{LaTeX} only},
+ }
+ These macros append the current value of the \meta{reference key} to the
+ context,\footnote{More precisely, it is \meta{reference key}|=|\marg{current
+ value} which is appended.} causing the memoized code to be recompiled
+ when the reference changes.
+
+ If the reference key is undefined, \refcmd{mmzNoRef} aborts memoization,
+ while \refcmd{mmzForceNoRef} uses \cs{relax} as the reference string.
+
+ These commands are deployed in the implementation of \refmmzauto[show
+ keypath]{ref}, \refmmzauto{force ref} and friends. If the
+ cross-referencing commands you are using are advised by these keys, you most
+ likely have no need of these macros.
+\end{doc}
+
+\begin{doc}{easy, key={name=per overlay,desc=style}}
+ This key is only defined in the Beamer class. When in effect, the memoized
+ code will produce a cc-memo (and extern) for each overlay of the frame. For
+ implementation, see section~\ref{sec:per-overlay}.
+\end{doc}
+
+\begin{doc}{
+ key={name=capture, par=\docAux{of=key:/mmz/capture, value={name=hbox}, text=\alt,
+ value={name=vbox,of=key:/mmz/capture}},
+ desc={no default, initially \refmmz{capture=hbox}}}
+ }
+ Select the capture mode. This setting only applies to the default
+ memoization \refmmz{driver}.
+
+ By default, it is assumed that the memoized code should be executed in the
+ horizontal mode, so the default memoization driver captures the output of the
+ memoized code in a \refcmd{hbox} --- and also issues a \refcmd{quitvmode}
+ (both in the document and in the cc-memo), just in case the memoized code
+ occurs at the start of the paragraph.
+
+ Use \refmmz{capture}|=|\refmmz{capture=vbox} to execute the memoized code in
+ the vertical mode: Memoize will capture the output of the memoized code in a
+ \refcmd{vbox}, and avoid issuing \refcmd{quitvmode}. For example, this
+ capture mode is necessary to memoize a \refenv{verbatim} environment.
+\end{doc}
+
+
+\subsubsection{Inside the memoization process}
+\label{sec:ref:memoization:process}
+
+\begin{doc}{easy, cmd={name=mmzAbort}}
+ This command aborts the ongoing memoization.
+
+ The memoization will proceed as usual (i.e.\ the extern boxes and the cc-memo
+ code will be produced), but at the end of this process, no memos will be
+ produced, no externs shipped out to extern pages, and no record files
+ updated.
+\end{doc}
+
+\begin{doc}{easy, cmd={name=mmzUnmemoizable}}
+ This command aborts the ongoing memoization, and marks the submitted code as
+ unmemoizable.
+
+ The ongoing memoization produces a c-memo setting conditional
+ \docaux{cmd}{ifmmzUnmemoizable} to true. Upon utilizing this c-memo, the
+ system switches to regular compilation.
+
+ For example, if you are automemoizing |tcolorbox|es of package
+ \pkg{tcolorbox}, you will want to refrain from memoizing boxes marked as
+ |breakable| or |float|ing. Simply aborting the memoization cannot do the
+ trick here, as memoization compiles the submitted code in a \hologo{TeX} box.
+ Marking a |breakable| or |float|ing |tcolorbox| as unmemoizable (either
+ manually using this macro, or automatically using \refmmz{auto key}) makes
+ sure that after the first compilation when memoization is attempted, the box
+ will be compiled regularly, and will have the intended ability to break
+ across pages, or float.
+\end{doc}
+
+
+\begin{doc}{
+ cmd={name=Memoize, par=\marg{key}\marg{code}},
+ }
+ Depending on various factors, this command either memoizes \meta{code} under
+ key \meta{key}, utilizes the results of a previous memoization, or performs a
+ regular compilation of \meta{code}.
+
+ The outcome of executing this command --- memoization, utilization or regular
+ compilation --- depends upon the Memoize's state (\refcmd{ifmemoize},
+ \refcmd{ifmemoizing}) and mode (\refmmz{normal}, \refmmz{readonly},
+ \refmmz{recompile}), and the existence of the relevant memos and externs.
+ The decision process is depicted in section~\ref{sec:Memoize}.
+
+ This command expects to be executed in a dedicated group, which it will close
+ itself.
+
+ Invoking memoization through \refcmd{Memoize} might be useful for packages
+ which want to save the results of intensive computations, regardless of
+ whether the author loads (and enables) memoization or not. However, this
+ usage is not yet officially allowed, because there is currently no way to
+ load the core memoization routines without loading the entire package,
+ thereby forcing the author to use Memoize.
+\end{doc}
+
+\begin{doc}{
+ key={
+ name=driver, par=\marg{code},
+ desc={no default, initially \refcmd{mmzSingleExternDriver}}
+ },
+ }
+ This key sets \meta{code} as the memoization driver.
+
+ Given some code submitted to memoization, the memoization driver should
+ produce the memos and externs which will replicate the effect of that code
+ (while retaining its regular effect). For details, see
+ section~\ref{sec:memoization-drivers}.
+
+ Typically, the \meta{code} argument of this key will consist of a single
+ control sequence (the driver control sequence), but any amount of tokens is
+ allowed. Memoize executes the driver followed by the code which it is
+ supposed to memoize, in braces, and only cares that the driver consumes that
+ code.
+\end{doc}
+
+
+\begin{doc}{
+ key={name=at begin memoization, par=\meta{code}, desc={cumulative, initially empty}},
+ key={name=at end memoization, par=\meta{code}, desc={cumulative, initially empty}},
+ key={name=after memoization, par=\meta{code}, desc={cumulative, initially empty}},
+ }
+ Use these keys to set up memoization hooks.
+
+ These keys may be used both prior to the memoization process, or during
+ memoization. In the former case, their effect is local to the current group;
+ in the latter case, the code given to \refmmz{at begin memoization} is
+ executed immediately, while the assignment performed by the other two keys is
+ global, so that the changes surely survive until the end of memoization.
+
+ The code given to hook \refmmz{at begin memoization} is kept in macro
+ \docaux{cmd}{mmzAtBeginMemoization}, while the content of the other two hooks
+ resides in two macros per hook: \docaux{cmd}{mmzAtEndMemoization} and
+ \docaux{cmd}{mmzAtEndMemoizationExtra}, and \docaux{cmd}{mmzAfterMemoization}
+ and \docaux{cmd}{mmzAfterMemoizationExtra}. All these macros may be
+ manipulated directly by the user,\footnote{Use \cs{appto}, \cs{eappto},
+ \cs{gappto} and \cs{xappto} of package \pkg{etoolbox} (loaded by Memoize)
+ to easily append code to these macros.} as long as one keeps to the
+ convention of adjusting the macros without ``\texttt{Extra}'' locally and
+ only while not memoizing, and adjusting the macros with ``\texttt{Extra}''
+ globally and only during memoization. The ``\texttt{Extra}'' macros require
+ global assignments as they might be manipulated by code residing within a
+ \hologo{TeX} group of any depth.
+
+ These complications explained, let us take a look at how memoization proceeds
+ to learn when the hooks are used:
+ \begin{enumerate}
+ \item Initialize various conditionals, macros and token registers. (Here is
+ where the ``\texttt{Extra}'' hooks are cleared.) Remember that at this
+ point, we're inside a group opened by \refcmd{Memoize}.
+ \item Execute \refmmz{at begin memoization} hook, i.e.\ the contents of
+ macro \refcmd{mmzAtBeginMemoization}.
+ \item Execute the memoization \refmmz{driver}.
+ \item Execute \refmmz{at end memoization} hook, i.e.\ the contents of macros
+ \refcmd{mmzAtEndMemoization} and \refcmd{mmzAtEndMemoizationExtra} (in this
+ order).
+ \item Write out the memos and ship out the externs to extern pages (unless
+ memoization was aborted).
+ \item Close the memoization group.
+ \item Execute \refmmz{after memoization} hook, i.e.\ the contents of
+ macros \refcmd{mmzAfterMemoization} and \refcmd{mmzAfterMemoizationExtra}
+ (in this order).
+ \end{enumerate}
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzCMemo, desc={token register, global, empty at the start of memoization}},
+ }
+ This token register mediates the construction of the c-memo. During
+ memoization (and only during memoization), arbitrary code may be added to
+ this register; at the end of memoization, Memoize writes out its contents to
+ the free-form part of the c-memo.
+
+ All assignments to this register should be global. Use \refcmd{gtoksapp} and
+ \refcmd{xtoksapp} to easily append tokens to the register.
+\end{doc}
+
+
+\begin{doc}{
+ cmd={name=mmzCCMemo, desc={token register, global, empty at the start of memoization}},
+ }
+ This token register mediates the construction of the cc-memo. During
+ memoization, the memoization driver should append cc-memo code to
+ \refcmd{mmzCCMemo}; at the end of memoization, Memoize writes out its
+ contents to the cc-memo (preceded by the list of produced externs).
+
+ All assignments to this register should be global. Local assignments would
+ not work, because the memoized code may contain commands, like \cs{label} and
+ \cs{ref}, which contribute content to cc-memo as well, but these commands may
+ appear within a \hologo{TeX} group of any depth.
+
+ Use \refcmd{gtoksapp} and \refcmd{xtoksapp} to easily append tokens to the
+ register.
+\end{doc}
+
+\begin{doc}{
+ par=\meta{token register}\marg{tokens},
+ cmd={name=toksapp},
+ cmd={name=gtoksapp},
+ cmd={name=etoksapp},
+ cmd={name=xtoksapp},
+ }
+ These commands append the given \meta{tokens} to the \meta{token register}.
+ \refcmd{etoksapp} and \refcmd{xtoksapp} expand the \meta{tokens} before
+ appending them; \refcmd{gtoksapp} and \refcmd{xtoksapp} perform a global
+ assignment.
+
+ These commands are actually provided by CollArgs, and they are defined only
+ if they don't already exist; in particular, note that \hologo{LuaTeX}
+ provides them as primitives.
+
+ Unlike the \hologo{LuaTeX} primitive variant, these commands require the
+ \meta{token register} to be given by a (|\toksdef|fed) control sequence; it
+ cannot be given as |\toks|\meta{number}.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=ifmemoize},
+ cmd={name=memoizetrue},
+ cmd={name=memoizefalse},
+ }
+ Use the \hologo{TeX}-style conditional \refcmd{ifmemoize} to test whether
+ Memoize is currently enabled. Within the document body, the conditional may
+ be set using \refcmd{memoizetrue} and \refcmd{memoizefalse}, which are then
+ functionally equivalent to \refmmz{enable} and \refmmz{disable}. Do not set
+ the conditional in the preamble of the document (unless you really know what
+ you are doing).
+\end{doc}
+
+\begin{doc}{
+ cmd={name=ifmemoizing,desc={readonly}},
+ }
+ Use this \hologo{TeX}-style conditional to test whether Memoize is currently
+ memoizing. It may be only inspected; you should \emph{never} set this
+ conditional yourself.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=ifinmemoize,desc={readonly}},
+ }
+ Use this \hologo{TeX}-style conditional to test whether Memoize is currently
+ active, in the sense of either memoizing or regularly compiling some code ---
+ so inside a call to \refcmd{Memoize}. The conditional may be only inspected;
+ you should \emph{never} set it yourself.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzSingleExternDriver, par=\marg{code}},
+ }
+ This is the default memoization \refmmz{driver}, producing exactly one extern
+ containing whatever is typeset by the submitted \meta{code}.
+
+ The \meta{code} is compiled either within a horizontal or vertical box,
+ depending on the value of key \refmmz{capture}. In the case of a horizontal
+ capture, the driver makes sure that the horizontal mode is entered prior to
+ both typesetting the resulting box in the document, or utilizing the extern.
+
+ For the implementational details, see
+ section~\ref{sec:memoization-driver-default}.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzExternalizeBox, par=\marg{box}\marg{token register}},
+ }
+ This macro is indended to be called by memoization drivers to produce an
+ extern page. The given \meta{box} is dumped into the document as a separate
+ extern page, while the \meta{token register} receives the cc-memo extern
+ inclusion code.
+
+ The \meta{box} may be given either as a control sequence (declared via
+ |\newbox|), or as box number. The resulting extern page will contain a
+ \emph{copy} of the given box, padded by the \refmmz{padding} values in effect
+ at the time of invocation of \refcmd{mmzExternalizeBox}.
+
+ An implementation detail is that \refcmd{mmzExternalizeBox} does not ship out
+ the extern page immediately. This action is delayed until the end of the
+ memoization process; more precisely, it is carried out (in tandem with
+ writing out the c-memo and the cc-memo) between execution of hooks \refmmz{at
+ end memoization} and \refmmz{after memoization}. This delay guarantees
+ that no extern pages are produced in the event of aborting memoization, even
+ if the abortion is triggered after executing \refcmd{mmzExternalizeBox}.
+
+ The \meta{token register} may be given either as a control sequence (declared
+ via |\newtoks|) or as control sequence |\toks| followed by the register
+ number. The register will receive the code, which, when executed from the
+ cc-memo, includes the extern file into the main document. This code consists
+ of a single invocation of \refcmd{mmzIncludeExtern}. It is the
+ responsibility of the driver to include the code received by \meta{token
+ register} in the register \refcmd{mmzMemo}, whose contents are, unless
+ memoization is aborted, written into the cc-memo. (See
+ \refcmd{ifmmzkeepexterns} and \refmmz{after memoization} to learn about
+ another way to use the code received by \meta{token register}.)
+
+ The invocation of \refcmd{mmzIncludeExtern} in the produced extern-inclusion
+ code is adapted to the type of the box (horizontal or vertical), which is
+ detected automatically --- the memoization driver does not need to inform
+ \refcmd{mmzExternalizeBox} about this type explicitly.\footnote{This does not
+ negate the need for key \refmmz{capture}, which applies to the default ---
+ and therefore generic --- memoization driver. This driver cannot know
+ whether the memoized code would prefer to be compiled in a horizontal or
+ vertical box. It is precisely key \refmmz{capture} which gives the user an
+ opportunity to inform Memoize about this preference. Only once the
+ memoized code is compiled into a box of the appropriate type, it is trivial
+ to detect the type of that box.}
+\end{doc}
+
+\begin{doc}{
+ cmd={name=ifmmzkeepexterns, desc={initially \cs{iffalse}}},
+ cmd={name=mmzkeepexternstrue},
+ cmd={name=mmzkeepexternsfalse},
+ }
+ Setting this conditional to true makes Memoize keep the extern boxes in the
+ global temporary storage even after shipping them out as extern pages. (The
+ temporary storage is emptied at the start of the next memoization.)
+
+ The extern inclusion code received by the \refcmd{mmzCCMemo} when executing
+ \refcmd{mmzExternalizeBox} is primarily meant to be executed by inputting the
+ cc-memo file; i.e.\ when the cc-memo is input, \refcmd{mmzIncludeExtern} is
+ defined to include the extern file into the document. However, it sometimes
+ makes sense to execute the cc-memo contents immediately after memoization;
+ for example, if memoization produces several externs, intricately integrated
+ into the surrouding environment, it might be cumbersome to replicate their
+ typesetting both in the memoizing compilation and in the cc-memo code ---
+ easier to build up the cc-memo code and execute it right after memoization.
+ This is why Memoize, just before executing the contents of \refmmz{after
+ memoization} hook, redefines \refcmd{mmzIncludeExtern} to include externs
+ from the temporary storage rather than from (at that point still
+ non-existing) extern files. However, as this mechanism requires Memoize to
+ keep the externs around even after memoization, it is not enabled by default:
+ it must be enabled by setting conditional \refcmd{ifmmzkeepexterns} to true.
+\end{doc}
+
+\begin{doc}{
+ key={keypath=/mmz/auto, name=integrated driver, par=\marg{name}}
+ }
+ Use this key to easily setup a memoization driver which is integrated into
+ the command itself.
+
+ \begin{tcolorbox}[warning]
+ This is an auto-key residing in keypath \refkeypath{/mmz/auto}.
+ \end{tcolorbox}
+
+ An integrated driver must have a way of telling whether it is memoizing or
+ regularly compiling the code. This key declares a driver-specific
+ conditional which may be inspected, using \refcmd{IfMemoizing}, to determine
+ this. The conditional is set to true by the formal driver of the command
+ (set up by the invocation of this key), executed at the start of memoization;
+ it should never be set elsewhere. See
+ section~\ref{sec:memoization-multiple-externs} for details and an example.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=IfMemoizing, par=\oarg{offset}\marg{name}\marg{true code}\marg{false code}}
+ }
+ This \hologo{LaTeX}-style conditional is meant to be used by the
+ \refmmzauto{integrated driver} with the given \meta{name}. It tests whether
+ this particular driver is currently memoizing some code.
+
+ Potentially recursive commands are supported via the optional argument
+ \meta{offset}. If given, the conditional will only execute the \meta{true
+ code} when the current \hologo{TeX} group level matches the \hologo{TeX}
+ group level at the time of the invocation of the formal driver (held in
+ \refcmd{memoizinggrouplevel}), plus the \meta{offset}. In effect, the inner
+ invocation of the integrated driver will perform a regular compilation. For
+ details, see section~\ref{sec:memoization-complex-single-driver}.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=memoizinggrouplevel,desc={readonly}},
+ }
+ During memoization, this macro holds the \hologo{TeX} group level in effect
+ at the start of the memoization.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzRegularPages, desc=readonly counter},
+ }
+ This counter holds the number of pages shipped out (so far) by the format's
+ regular shipout routine. \emph{Do not change its value!}
+
+ In \hologo{LaTeX}, this counter is synonymous with
+ \refcmd{ReadonlyShipoutCounter}, and in \hologo{ConTeXt}, it is synonymous
+ with \refcmd{realpageno}. Memoize does not touch its value.
+
+ In \hologo{plainTeX}, Memoize hijacks the \refcmd{shipout} control sequence
+ to count (and only to count) regular shipouts. In order for its value to be
+ realistic, Memoize should be loaded before other packages which hack
+ \cs{shipout} --- in particular, before \pkg{atbegshi}.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzExternPages, desc=readonly counter},
+ }
+ This counter holds the number of extern pages Memoize has shipped out (so
+ far). \emph{Do not change its value!}
+
+ A third-party tool may inspect this counter to have a realistic count of
+ shipped-out pages.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzExtraPages, desc=counter},
+ }
+ This counter holds the number of pages shipped out (so far) in a way not
+ tracked by either \refcmd{mmzRegularPages} or \refcmd{mmzExternPages}. It
+ \emph{should} be advanced by any code which performs such shipouts, or
+ Memoize won't work correctly.
+\end{doc}
+
+
+\subsubsection{Tracing}
+\label{sec:ref:memoization:tracing}
+
+\begin{doc}{
+ key={name=trace, conditional=false},
+ }
+ When tracing is on, Memoize shows information about its decision processes on
+ the terminal. You can learn whether the memoized code is being memoized,
+ utilized or regularly compiled; find out the md5sum of the code and which
+ input line it comes from; etc.
+
+ This key has the syntax of a conditional, but there is no underlying
+ \hologo{TeX} conditional. The low-level interface for switching the tracing
+ on and off consists of macros \docaux{cmd}{mmzTracingOn} and
+ \docaux{cmd}{mmzTracingOff}.
+
+ To learn about tracing the ``auto'' part of the automemoization process, also
+ \refcmd{AdviceTracingOn}.
+\end{doc}
+
+\begin{doc}{
+ key={name=include source in cmemo, conditional=true},
+ }
+
+ As a courtesy towards a curious user and a debugging aid, Memoize can include
+ a copy of the memo source in the c-memo. This feature is switched on by
+ default, but as the package itself never uses that information, it can be
+ safely switched off at any time.
+\end{doc}
+
+\begin{doc}{
+ key={name=include context in ccmemo, conditional=false},
+ }
+ When this key is in effect, the expanded context expression is appended to
+ the cc-memo, behind the \docaux{cmd}{mmzThisContext} marker.
+
+ Memoize never uses the context information from the cc-memo; this information
+ is only for tracing purposes.
+\end{doc}
+
+\begin{doc}{
+ key={name=direct ccmemo input, conditional=false},
+ }
+ When this key is set to false, a cc-memo is processed indirectly: it is first
+ read into a token register, and it is the contents of this register which are
+ executed. When the key is set to true, the cc-memo is simply |\input|ted.
+
+ The indirect execution is implemented to facilitate inverse search. Under
+ the direct cc-memo input, inverse search pointed at an included extern will
+ visit the cc-memo, which is not practical; under the indirect regime, the
+ inverse search will work as expected, and this is why the indirect cc-memo
+ input is the default.
+
+ The overhead produced by the default indirect input method seems negligible,
+ but there are other factors which might make the user switch to the direct
+ input. For one, a cc-memo changing some category codes will require direct
+ input (no such cc-memos are ever produced out of the box). Less crucially,
+ sometimes one would like to use the inverse search to figure whether a part
+ of the document was produced by regular compilation or utilization, and which
+ memos\slash externs were utilized if the latter. Figuring this out under the
+ indirect input regime is harder: (i) reading the tracing information shown by
+ \refmmz{trace} is the surest way to learn what's going on, although (ii)
+ visual inspection of the externs and (iii) grepping through the |.memo.dir|
+ folder for particular code often help, as well.
+
+ Both input methods use the same cc-memos; there is no need to
+ \refmmz{recompile} the memos when switching the cc-memo input method. Note
+ that the default indirect input method crucially relies on cc-memos ending
+ with \refcmd{mmzEndMemo}; this macro should not appear in the cc-memo itself.
+\end{doc}
+
+
+
+\subsubsection{Internal memo commands}
+\label{sec:ref:memoization:internal}
+
+The end-user should never have to use these commands. They are not formally
+marked as internal by a |@| in their name only because doing so would
+complicate |\input|ting the memos due to the category code changes it would
+require.
+
+\begin{doc}{
+ cmd={name=mmzMemo},
+ }
+ This macro marks the beginning of a c-memo and a cc-memo core. Without it,
+ utilization of a memo will not work.
+\end{doc}
+
+\begin{doc}{cmd={name=mmzSource}}
+ This macro marks the beginning of the memoized source in the c-memo. That
+ source is not used by Memoize in any way. It's inclusion into the c-memo may
+ be switched off by \refmmz{include source in cmemo}|=false|.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzResource, par=\marg{filename}},
+ }
+ This is an internal command, which only occurs in a cc-memo. It checks
+ whether file \meta{filename} exists and is non-empty, and triggers
+ recompilation of the memoized code if the check fails.
+\end{doc}
+
+\begin{doc}{
+ cmd={
+ name=mmzIncludeExtern,
+ par=\marg{seq}\braces{\refcmd{hbox}\alt\refcmd{vbox}}%
+ \marg{expected width}\marg{expected height}\marg{expected depth}%
+ \marg{padding left}\marg{padding bottom}\marg{padding right}\marg{padding top},
+ }
+ }
+
+ This is an internal command, which only occurs in a cc-memo. It includes the
+ extern identified by the sequential number \meta{seq} into the document as a
+ box of the specified type (horizontal or vertical). The extern is trimmed by
+ the given padding values. After trimming, the command checks whether the
+ size of the resulting box matches the given expectations; if it doesn't, a
+ warning is yielded.
+
+ Before this command is executed, the externs should be listed by a sequence
+ of \refcmd{mmzResource} commands; \meta{seq} refers to the sequential number
+ of an extern in this sequence.
+
+ This command may also be executed by executing the entire contents of
+ \refcmd{mmzCCMemo} after memoization.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzLabel, par=\marg{label key}\marg{label value}}
+ }
+ This is an internal command written into the cc-memo by the auto-handler of
+ \refcmd{label}. It temporarily stores \meta{label value} into
+ \refcmd{@currentlabel} and then executes \cs{label}\marg{label name}.
+\end{doc}
+
+\begin{doc}{
+ cmd={name=mmzEndMemo},
+ }
+ This macro marks the end of a cc-memo. It is used to grab the cc-memo core
+ (everything between \refcmd{mmzMemo} and \refcmd{mmzEndMemo}) under the
+ indirect cc-memo input regime, i.e.\ when \refmmz{direct ccmemo input} is not
+ in effect.
+\end{doc}
+
+
+\subsection{Location of memos and externs}
+\label{sec:ref:dirs}
+
+\begin{doc}{easy,
+ key={name=memo dir,par=\meta{name}, desc={style, default \texttt{\string\jobname}}},
+ }
+ A convenient way to store memos and externs in a dedicated directory (and
+ create this directory in case it does not exist). Without an argument, this
+ key places these files in subdirectory \meta{document name}|.memo.dir| of the
+ current directory. See section~\ref{sec:tut:memodir} for the tutorial.
+
+ This key sets \refmmzpath{relative} to |false|, \refmmzpath{dir} to
+ \meta{name}|.memo.dir|, \refmmzpath{prefix} to empty and \refmmz{mkdir} to
+ |true|. In effect, memos and externs are placed in the subdirectory
+ \meta{name}|.memo.dir| of the directory containing the document; their
+ filenames contain no \meta{name} prefix, as \meta{name} already occurs in the
+ directory name. The latter feature also makes it easy for projects (or parts
+ of a project) to share memos and externs; see section~\ref{sec:tut:multifile}
+ for a typical usage case.
+\end{doc}
+
+\begin{doc}{easy,key={name=no memo dir,desc=style}}
+ A convenient way to undo the effect of \refmmz{memo dir} and revert to the
+ initial settings where memos and externs are located in the current
+ directory. See section~\ref{sec:tut:memodir} for the tutorial.
+
+ This key resets the subkeys of \refmmz{path} to their initial values, and
+ sets \refmmz{mkdir} to |false|.
+\end{doc}
+
+\begin{doc}{
+ key={name=path, par=\meta{keylist}, desc=style},
+ }
+
+ Set the \emph{path prefix} to memo and extern files by executing the given
+ \meta{keylist} in keypath \docaux{key path}{mmz/path}.
+
+ The path prefix contains both the location of the memo\slash extern files
+ (set by \refmmzpath{relative} and \refmmzpath{dir}) and the initial,
+ fixed part of their filenames (set by \refmmzpath{prefix}):
+ \begin{center}
+ \meta{path prefix}=[|./|]\meta{directory}|/|\meta{prefix}
+ \end{center}
+ where ``|./|'' is only present when \refmmzpath{relative} is in effect.
+ Given the \meta{path prefix}, this is how the paths to memos and externs are
+ constructed:
+ \begin{center}
+ \begin{tabular}{r@{ }l}
+ c-memo:&\meta{path prefix}\meta{code md5 sum}|.memo|\\
+ cc-memo:&\meta{path prefix}\meta{code md5 sum}|-|\meta{context md5 sum}|.memo|\\
+ extern:&\meta{path prefix}\meta{code md5 sum}|-|\meta{context md5 sum}-$N$|.pdf|\\
+ &(where ``-$N$'' is only present when $N\neq 0$, i.e.\ for non-first externs)\\
+ \end{tabular}
+ \end{center}
+
+ For example, the default \refmmz{no memo dir} \meta{path prefix} equals
+ \meta{jobname}|.| (note the dot), and after issuing \refmmz{memo dir}, the
+ \meta{path prefix} is \meta{jobname}|.memo.dir|. Executing
+ \refmmz{path}|=|\bracestt{\refmmzpath{dir}=project-memo-dir,
+ \refmmzpath{prefix}=\string\jobname.} would set the memo prefix to
+ |./project-memo-dir/|\meta{jobname}|.|, allowing the author to keep the memo
+ files of all documents compiled from the project directory in the same place.
+
+ The following keys may occur in the \meta{keylist}:
+ \yadocset{keypath=/mmz/path}
+
+ \begin{doc}{
+ key={name=relative, conditional=true},
+ }
+
+ This key determines whether the location is relative to the current
+ directory, i.e.\ the directory where \hologo{TeX} is executed from;
+ usually, this will be the directory where the compiled |.tex| file resides.
+ When set to |true| (the default), the directory set by \refmmzpath{dir}
+ is prefixed by ``|./|''.
+
+ You will probably need to set |openout_any=a| in \reffile{texmf.cnf}
+ to allow writing to an arbitrary directory --- but remember, this might be
+ dangerous!
+ \end{doc}
+
+ \begin{doc}{
+ key={name=dir, par=\meta{name}, desc={no default, initially empty}},
+ }
+
+ Set the \meta{directory} where Memoize will search for memos and externs
+ and\slash or create them in.
+
+ Unless \refmmzpath{relative} is set to |false|, this location is
+ relative to the current directory. Given the empty default, memos and
+ externs are therefore created in the directory holding the source file by
+ default.
+
+ In principle, the given memo directory must already exist, but see
+ \refmmz{mkdir}.
+ \end{doc}
+
+ \begin{doc}{
+ key={name=prefix, par=\meta{name},
+ desc={no default, initially \texttt{\string\jobname.}}},
+ }
+
+ Set the \meta{prefix}, i.e.\ the initial part of the memo\slash extern
+ filename. Initially, it is set to the document name.
+ \end{doc}
+
+ After processing the \meta{keylist}, \refmmz{path} records the new path
+ prefix by invoking \refmmz{record/record type/prefix}, which typically results
+ in a \refcmd{mmzPrefix} entry in the \dmmz file, and attempts to create the
+ \meta{directory} is \refmmz{mkdir} is in effect --- except when \refmmz{path}
+ is executed in the document preamble: then, these actions are only carried
+ out at the beginning of the document, for the final value of the keys.
+\end{doc}
+
+\begin{doc}{key={name=mkdir, conditional=false}}
+ When this key is set to true, Memoize will attempt to create the directory
+ set by \refmmz{path} if it does not yet exist. The directory creation takes
+ place at the beginning of the document and at every subsequent invocation of
+ key \refmmz{path}, using the system command specified by \refmmz{mkdir
+ command}.
+\end{doc}
+
+\begin{doc}{
+ key={name=mkdir command, par=\meta{system command invocation},
+ desc={no default, initially |mkdir "\#1"|}},
+ }
+ Sets the command used to create \refmmzpath{dir} when \refmmz{mkdir} is in effect.
+
+ This is a system command, so an appropriate shell escape mode must be in
+ effect to execute it successfully.
+
+ The default should work on Linux, MacOS and Windows. On Linux systems, it
+ makes sense to change the default (using \reffile{memoize.cfg}) to |mkdir
+ -p "#1"|, which can create parent folders as necessary.
+
+ Note that extraction methods \refmmz{extract=perl} and
+ \refmmz{extract=python} set \refmmz{mkdir command} to
+ \refscript{memoize-extract.pl} \refscript{memoize-extract.pl--mkdir} and
+ \refscript{memoize-extract.py} \refscript{memoize-extract.pl--mkdir},
+ respectively. Unlike system |mkdir|, these commands are safe in the sense
+ that they conform to the paranoid openout regime (|openout_any=p|).
+\end{doc}
+
+\begin{doc}{
+ key={name=output-directory, par=\meta{directory},
+ desc={no default, initially undefined, as package option only}},
+ cmd={name=mmzOutputDirectory, par=\meta{directory}, desc={pre-defineable}}
+ }
+ If the \hologo{TeX} binary was invoked with option |-output-directory|, one
+ should use this key or define this macro to inform Memoize this, as there is
+ no way to learn about it automatically.
+
+ The given \meta{directory} must end with a slash (|/|).
+
+ The key is only allowed as a package option. But I imagine that defining the
+ macro from the command line, prior to inputting the document source, will be
+ more common:
+ \begin{center}
+ |pdftex -output-directory somedir '\def\mmzOutputDirectory{somedir/}\input doc'|
+ \end{center}
+\end{doc}
+
+
+\subsection{Extern extraction}
+\label{sec:ref:externs}
+
+\begin{doc}{easy,
+ key={name=extract,par=\marg{extraction method},
+ desc={preamble-only, initially \refmmz{extract=perl}, default: see below}},
+ }
+ This key selects or executes the extern \meta{extraction method}, i.e. the
+ method which Memoize will use to extract the extern pages out of the document
+ PDF.
+
+ Out of the box, Memoize recognizes the following \meta{extraction method}
+ keywords: \docAux{easy, of=key:/mmz/extract, value={name=perl}, comma,
+ value={name=python}, comma, value={name=tex}, and, value={name=no}}. The final
+ keyword (not available in \hologo{plainTeX}) instructs Memoize to \emph{not}
+ perform to extraction; it should be used when extraction is performed
+ externally (for details, see section~\ref{sec:setup}). Additional methods
+ may be installed by defining key \docaux{key
+ path}{mmz/extract}|/|\meta{extraction method}.
+
+ When invoked from \reffile{memoize.cfg} or used as a package option, this key
+ \emph{selects} the extraction method. In this case, the key has no default
+ value, i.e.\ it is illegal to use it without an argument. The method
+ selected by the package option overrides the method selected in
+ \reffile{memoize.cfg}, which in turn overrides the package-initial value
+ \refmmz{extract=perl}.
+
+ In \hologo{LaTeX} and \hologo{ConTeXt}, the selected method is executed at
+ the end of loading the package. Afterwards, the key is disabled. If you
+ really need to invoke extraction in the preamble, or again, write
+ \refmmz{extract}|/|\meta{method}.
+
+ When invoked from a \refcmd{mmzset} in the document preamble, this key
+ immediately \emph{executes} the given extraction method. In the preamble
+ incarnation, the key may be invoked without a value to execute the previously
+ selected method.
+
+ As we want to allow a \hologo{plainTeX} author to override the extraction
+ method specified by the package (\refmmz{extract=perl}) or in
+ \reffile{memoize.cfg}, Memoize does \emph{not} perform extern extraction
+ while loading the package in this format. In \hologo{plainTeX}, internal
+ extraction can only be triggered by an explicit invocation of
+ \refmmz{extract} in the ``document preamble'' --- i.e.\ between |\input
+ memoize| and \refcmd{mmzset}\braces{\refmmz{begin document}}. In this case,
+ the key does not require an argument; invoking it without the argument will
+ execute either the package-default, \refmmz{extract=perl}, or whatever the
+ user had selected in \reffile{memoize.cfg}.
+
+ Executing extraction method \refmmz{extract=perl} or \refmmz{extract=python}
+ has an additional effect of setting the \refmmz{mkdir command} to the
+ extraction script with option \refscript{memoize-extract.pl--mkdir}. This
+ obviates the need to include |mkdir| among the restricted shell commands if
+ one is using the restricted shell mode.
+\end{doc}
+
+\subsubsection{Perl- and Python-based extraction}
+\label{sec:ref:extraction-perl-python}
+
+\begin{doc}{
+ key={name=perl extraction command, par=\meta{system command},
+ desc={no default, initially \refscript{memoize-extract.pl}}},
+ key={name=perl extraction options, par=\meta{options},
+ desc={no default, initially: see below}},
+ key={name=python extraction command, par=\meta{system command},
+ desc={no default, initially \refscript{memoize-extract.py}}},
+ key={name=python extraction options, par=\meta{options},
+ desc={no default, initially: see below}},
+ }
+ These keys determine the system calls used for invoking the extraction
+ scripts \refscript{memoize-extract.pl} and \refscript{memoize-extract.py}.
+ All the details below apply both to the Perl and the Python version.
+
+ Use |perl|\slash|python extraction command| to set the name of the extraction
+ script. If necessary, include the full path to the scrip, or |perl|\slash
+ |python| plus the path to the script. Whatever you set here must be allowed
+ by the shell escape mode.
+
+ Use |perl|\slash|python extraction options| to set the options that the
+ script will receive; consult the documentation of
+ \refscript{memoize-extract.pl} for their meaning.
+
+ The initial value of \refmmz{perl extraction options}, shown below, (i) sets
+ embedded mode, which prefixes each output line with the script name, (ii)
+ requests a log file named \meta{jobname}|.mmz.log| (|-l|; |\input|ting the
+ log after extraction informs Memoize, and the author, whether extraction was
+ successful), and (iii) sets the warning template suitable for the format
+ (|-w|; this way, any warning messages issued by the script can be reissued by
+ the compilation of the document).
+
+ These keys were initialized using \pkg{pgfkeys} handler |.initial|, so their
+ values may be modified by handlers |.prefix|, |.append|, etc. During the
+ execution of the system call, their values are fully expanded --- thus the
+ |\string|s in the initial options value below. The guards
+ (|%<latex>| etc.) make sure that
+ each format asks for a warning message it understands (the code shown below
+ is an excerpt from the |.dtx| file; ultimately, each format receives a single
+ of the three guarded lines).
+
+ \makeexcerpt{perl-extraction-options}
+ \tcbinputexample[.tex][.excerpt]{listing only, one file, no attachment,
+ title={The initial value of \refmmz{perl extraction
+ options}}, full width, left=-2mm, right=0mm, listing options app={
+ morecomment={[s]{\%<}>} }, }
+\end{doc}
+
+\begin{doc}{
+ script={name=memoize-extract.pl, par=[\meta{options}] \meta{name}\texttt{.mmz}},
+ script={name=memoize-extract.py, par=[\meta{options}] \meta{name}\texttt{.mmz}},
+ }
+ These scripts extract the new externs recorded in \meta{name}\dmmz from
+ \meta{name}|.pdf|. Memoize invokes them when loaded with package option
+ \refmmz{extract}|=|\refmmz{extract=perl} (the default) or
+ \refmmz{extract}|=|\refmmz{extract=python}.
+
+ The script inspects the given record file, \meta{name}\dmmz, for lines of
+ form \refcmd{mmzNewExtern}\marg{extern filename}\marg{extern page
+ number}\braces{\meta{expected width}\texttt{pt}}\braces{\meta{expected
+ height}\texttt{pt}}. For each such line, page number
+ \meta{extern page number} is extracted from \meta{name}|.pdf| into
+ \meta{extern filename}. Other lines are ignored (and so are commented
+ invocations of \refcmd{mmzNewExtern}).
+
+ The \meta{extern filename} may contain a (relative or absolute) path to the
+ new extern file. The relative paths are relative to the location of the
+ \dmmz file, even when the script is invoked from some other directory.
+
+ To guard against extracting a wrong page, the script checks whether the size
+ of each extracted page matches the \meta{expected width} and \meta{expected
+ height}.\footnote{\label{fn:tolerance}To avoid false positives, the match
+ need not be exact, a difference up to |0.01pt| is tolerated. Some PDF
+ tools, notably the |PDF::API2| library deployed by the Perl version of the
+ script, round the dimensions of a PDF page, recorded in |/MediaBox|, to two
+ digits.} If it does not, the script refuses to extract the page, yields a
+ warning and even removes the extern file if it exist.
+
+ The extraction script's paranoia extends further. It will refuse to extract
+ the page, yielding a warning, if a (c)c-memo associated to the extern does
+ not exist. And it will refuse (yielding a runtime error) to write to any
+ file whose absolute path does not occur under the current directory or the
+ directory set by \docref{TEXMFOUTPUT} (in \reffile{texmf.cnf} or as an
+ environment variable); \docref{TEXMFOUTPUT} is also not allowed to point to
+ the root directory, except on Windows, where it can only point to a drive
+ root.
+
+ \yadocset{
+ of=script:memoize-extract.pl,
+ override/.style={
+ index annotation={option of {%
+ \hypercolor{link}{gray}%
+ \hyperref[script:memoize-extract.pl]{\texttt{memoize-extract}}%
+ }},
+ },
+ }
+ \begin{doc}{
+ option={name=pdf, short name=P, par=\meta{pdf}}
+ }
+ Extract the externs from the given \meta{pdf} instead of the default
+ \meta{name}\texttt{.mmz}. Note that file \meta{pdf}, despite the different
+ name, should be produced by the same compilation that produced
+ \meta{name}\dmmz, otherwise wrong pages might be extracted.
+ \end{doc}
+ \begin{doc}{
+ option={name=prune, short name=p}
+ }
+ After extraction, remove the extracted extern pages from the document PDF.
+ \end{doc}
+ \begin{doc}{
+ option={name=keep, short name=k}
+ }
+ By default, the script comments out the \refcmd{mmzNewExtern} lines in the
+ \dmmz file, to prevent multiple extractions. Specifying this option
+ prevents this behaviour.
+ \end{doc}
+ \begin{doc}{
+ option={name=log, short name=l, parameters=\meta{filename}}
+ }
+ When given this option, the script creates a log file with the given name.
+ The log will receive any warnings yielded by the script, see also
+ \refscript{memoize-extract.pl--warning-template}. A well-formed log ends
+ with |\endinput|, indicating that the \dmmz file was completely processed.
+
+ In absence of this option, the warnings are printed to the standard error.
+ \end{doc}
+ \begin{doc}{
+ option={name=warning-template, short name=w, parameters=\meta{template}},
+ }
+ When this option is given, a warning message is not logged (or printed to
+ standard error) as-is; it is wrapped by the template given as the argument
+ of this option. More precisely, the script will log the given
+ \meta{template}, with all occurrences of \docaux{cmd}{warningtext}
+ substituted by the actual warning message.
+
+ The option can be used to propagate warnings to the upstream compilation,
+ simply by setting this option appropriately (see the initial value of
+ \refmmz{python extraction options}) and |\input|ting the log after
+ extraction.
+ \end{doc}
+ \begin{doc}{
+ option={name=force, short name=f}
+ }
+ Force extern extraction even if the size-check fails. The failure will
+ still be logged.
+ \end{doc}
+ \begin{doc}{
+ option={name=quiet, short name=q}
+ }
+ Normally, the script prints what it is doing to the standard output; in
+ particular, it prints out the page number and the filename of each extern
+ it is extracting. This option disables this behaviour.
+ \end{doc}
+ \begin{doc}{
+ option={name=embedded, short name=e}
+ }
+ When given this option, everything printed to the standard output is
+ prefixed by the script name. The idea is to use this option when calling
+ the script from the \hologo{TeX} compilation, as it makes it easy to
+ identify the output of the script.
+ \end{doc}
+ \begin{doc}{
+ option={name=mkdir, short name=m}
+ }
+ When given this option, the extraction script transforms into a paranoid
+ |mkdir| (|-p|). Argument \meta{name}|.mmz| is interpreted as a path to the
+ directory to create; all other options are ignored.
+
+ The ancestors of the directory are created as needed. The script will
+ refuse to create any directory whose absolute path does not occur under the
+ current directory or a directory listed in \docref{TEXMFOUTPUT} (set in
+ \reffile{texmf.cnf} or as an environment variable).
+
+ This option exists so that the author using the restricted shell mode does
+ not have to list |mkdir| among the restricted shell mode commands (and it
+ is also safer than a plain |mkdir|).
+
+ Memoize automatically uses this script to create the memo directory when
+ option \refmmz{extract} is given value \refmmz{extract=perl} or
+ \refmmz{extract=python}.
+ \end{doc}
+ \begin{doc}{
+ option={name=help, short name=h}
+ }
+ Show help.
+ \end{doc}
+ \begin{doc}{
+ option={name=version, short name=V}
+ }
+ Show Memoize version.
+ \end{doc}
+
+ Functionally, the Perl (|.pl|) and the Python (|.py|) version of the script
+ are almost equivalent. The minor differences, listed below, are mostly due
+ to the underlying PDF-processing library:
+ \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} in Perl, and
+ \hreftt{https://pypi.org/project/pdfrw2/}{pdfrw2} in Python.
+ \begin{itemize}
+ \item The Python script is about twice as fast as the Perl script. However,
+ both scripts are very fast compared to the \hologo{TeX}-based extraction.
+ On my computer, extracting 160 externs out of a 400-page book takes 1.4s
+ with Python, 3.7s with Perl, and 65s with \hologo{TeX}. But even when
+ using \hologo{TeX}-based extraction, externalization using Memoize is
+ extremely fast compared to the \TikZ's externalization library. Adding
+ the regular compilation time of one minute to the above numbers, we arrive
+ at the maximum externalization time of about two minues, whereas my
+ estimate for the production of all 160 externs using \TikZ's
+ externalization would be an \emph{hour} or more.
+ \item The Python script cannot extract externs out of PDFs created without
+ stream compression, i.e.\ with \refcmd{pdfvariable}
+ \docref{pdfvar:compresslevel} set to |0|.
+ \item Occasionally, the Perl script crashes during extraction externs; see
+ section~\ref{sec:troubleshooting} for details.
+ \end{itemize}
+\end{doc}
+
+\subsubsection{\texorpdfstring{\hologo{TeX}}{TeX}-based extraction}
+\label{sec:ref:extraction-tex}
+
+\begin{doc}{
+ key={name=tex extraction command, par=\meta{system command},
+ desc={no default, initially |pdftex|}},
+ key={name=tex extraction options, par=\meta{options},
+ desc={no default, initially: see below}},
+ key={name=tex extraction script, par=\meta{\hologo{TeX} code},
+ desc={no default, initially: see below}},
+ }
+ \yadocset{
+ before/.style={label prefix=cmd:te},
+ index annotation={defined at \hologo{TeX} extraction},
+ }
+
+ Together, these keys determine the system call used for invoking the
+ \hologo{TeX}-based extraction script, \refscript{memoize-extract-one.tex}.
+ (They were initialized using \pkg{pgfkeys} handler |.initial|, so their
+ values may be modified by handlers |.prefix|, |.append|, etc.)
+
+ Memoize uses the resulting system call string at the following occasions.
+ First, it executes it, once for each new extern in the \dmmz file, during the
+ internal extraction, i.e.\ when it is loaded with package option
+ \refmmz{extract}|=|\refmmz{extract=tex}. Second, it uses it to construct
+ record files of types \refmmz{record=sh}, \refmmz{record=bat} and
+ \refmmz{record=makefile} when recording of these types is requested.
+
+ Key \refmmz{tex extraction command} sets the \hologo{TeX} binary used for
+ \hologo{TeX}-based internal extraction. By default, the \hologo{pdfTeX}
+ engine |pdftex| is used; other sensible values for this key are |luatex| and
+ |xetex|, or the program name including the path. Note that shell escape mode
+ must be configured appropriately, and that
+ \refscript{memoize-extract-one.tex} must be compiled with the
+ \hologo{plainTeX} format.
+
+ The value of key \refmmz{tex extraction options} is passed as options to the
+ \hologo{plainTeX} binary. As shown in the initial value in the frame below,
+ it may use the temporary macro \docaux{cmd}{externbasepath}, which expands to
+ the path to the extern without the |.pdf| suffix. This macro is available
+ during internal \hologo{TeX}-based extraction and during the execution of
+ \refmmz[show keypath]{record/record type/new extern} key for and \meta{record
+ type}.
+
+ \makeexcerpt{tex-extraction-options}
+ \tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, no attachment, title={The initial value of
+ \refmmz{tex extraction options}},
+ }
+
+ Key \refmmz{tex extraction script} defines the command-line script executed
+ to extract the extern. The default value, shown in the frame below, invokes
+ \refscript{memoize-extract-one.tex} after setting its parameter macros.
+ Temporary macros \docAux{cmd={name=pagenumber}, comma, cmd={name=expectedwidth},
+ and, cmd={name={expectedheight}}} are defined at the same occasions as
+ \refcmd{te:externbasepath} above, i.e.\ during internal \hologo{TeX}-based
+ extraction and during the execution of a \refmmz{record/record type/new
+ extern} key. The initial value requests the extern to be of the same version as
+ the main document, if possible;\footnote{As far as I know, it is impossible
+ to access the version of the PDF being produced in \hologo{XeTeX}, i.e.\
+ there are no registers \docref{reg:pdfmajorversion} and
+ \docref{reg:pdfminorversion}. To request production of a specific version of
+ PDF, \hologo{XeTeX} must be invoked by with command-line option
+ \code{-output-driver 'xdvipdfmx -V $N$'}.} note that Memoize defines
+ \docref{reg:pdfmajorversion} and \docref{reg:pdfminorversion} in \hologo{LuaTeX}.
+
+ \makeexcerpt{tex-extraction-script}
+ \tcbinputexample[.tex][.excerpt]{%
+ listing only, one file, title=The initial value of \refmmz{tex extraction
+ script}, no attachment}
+
+ As the value of \refmmz{tex extraction script} is fully expanded when used,
+ the initial value shown above must prevent the expansion of much code.
+ Furthermore, the initial value varies with the \hologo{TeX} format, as
+ indicated by the |.dtx| guards in the definition of
+ \refcmd{meo:warningtemplate}.
+\end{doc}
+
+\begin{doc}{
+ script={
+ head prefix={%
+ (\texttt{pdf}\alt\texttt{lua}\alt\texttt{xe})\texttt{tex -jobname}
+ \meta{extern filename}
+ \texttt{"}\meta{parameters}
+ \cs{input}\texttt{\textbraceleft}
+ },
+ name=memoize-extract-one.tex,
+ head infix=\texttt{\textbraceright"},
+ },
+ }
+ Compiling \refscript{memoize-extract-one.tex} with \hologo{plainTeX}
+ produces an extern file containing a single (extern) page extracted from the
+ document PDF.
+
+ Memoize invokes this script, once for each new extern appearing in the \dmmz
+ file, when loaded with package option
+ \refmmz{extract}|=|\refmmz{extract=tex}.
+
+ The desired \meta{extern filename} is given as the value of option |-jobname|
+ of the \hologo{TeX} binary. To set the extraction \meta{parameters}, define
+ the following macros before |\input|ting the file:
+ \yadocset{
+ index annotation=option of \texttt{memoize-extract-one.tex},
+ before/.style={head prefix=\cs{def}, label prefix=cmd:meo},
+ }
+ \begin{doc}{cmd={name=fromdocument, parameters=\marg{document pdf filename}}}
+ Defining this macro sets the filename of the PDF which the externs will be
+ extracted from. The filename is relative to the working directory.
+ \end{doc}
+ \begin{doc}{cmd={name=pagenumber, parameters=\marg{number}}}
+ Defining this macro sets the number of the page to extract. The first page
+ has number 1.
+ \end{doc}
+ \begin{doc}{
+ cmd={name=expectedwidth, parameters=\marg{dimension}, desc=optional},
+ cmd={name=expectedheight, parameters=\marg{dimension}, desc=optional},
+ }
+ Defining these macros sets the expected width and height of the extracted
+ page.
+
+ To guard against extracting a wrong page, the dimensions of the extracted
+ page are compared against the expected width and height. If the size check
+ fails,\footnote{The match need not be exact, see
+ footnote~\ref{fn:tolerance}.} the resulting extern PDF is empty (which
+ counts as non-existent when Memoize checks for its presence when it
+ attempts to utilize it), and a warning message (formatted via
+ \refcmd{meo:warningtemplate}) is printed to the log file, if logging was
+ requested via \refcmd{meo:logfile}.
+
+ If any of these macros is undefined, the size check will be skipped.
+ \end{doc}
+ \begin{doc}{cmd={name=logfile, parameters=\marg{filename}, desc=optional}}
+ Defining this macro sets the name of the log file. If not defined, no log
+ file will be produced.
+
+ The log file is intended to be used when the script is invoked from an
+ outer \hologo{TeX} compilation. In particular, it is intended to be
+ |\input| by that compilation to see whether the extraction was successful.
+ Upon a failed size check, it will contain a warning (formatted by
+ \refcmd{meo:warningtemplate}, if that macro is defined). The log file ends
+ with |\endinput| to signal that extraction actually took place.
+ \end{doc}
+ \begin{doc}{cmd={name=warningtemplate, parameters=\marg{code}, desc=optional}}
+ Defining this macro determines how to log the warning message in the case
+ of a failed size check. The macro should expand to a \hologo{TeX}
+ format-specific warning message code containing the warning text given in
+ \docAux{cmd={name=warningtext, label prefix=cmd:meo, into
+ index=false}}.\footnote{Macro \refcmd{meo:warningtemplate} is passed
+ the warning text by a macro rather than a formal parameter to avoid
+ category code problems with the parameter character when setting key
+ \refmmz{tex extraction script}.}
+
+ While the script formats the warning message \emph{text} on its own (``I
+ refuse to extract page \dots''), the warning message is not written into
+ the log unadorned. The log file is intended to be \cs{input} by the outer
+ \hologo{TeX} compilation, and the idea is that inputting it should yield a
+ warning in that compilation (in the case of a failed size
+ check). Therefore, the content of the log file must contain an invocation
+ of the command used to produce warning messages in the \hologo{TeX} format
+ used by the outer compilation.
+
+ For example, when this script is invoked from within a \hologo{LaTeX}
+ compilation, it makes sense to define something like
+ |\def\warningtemplate{\PackageWarning{memoize}{\warningtext}}|.
+ \end{doc}
+ \begin{doc}{cmd={name=force,
+ parameters=\bracestt{\texttt{true}\Alt\texttt{false}}, desc=optional}}
+ If this macro is defined to |true|, extern extraction will be carried out
+ even if the size-check fails. The failure will still be logged.
+ \end{doc}
+ \begin{doc}{
+ cmd={name=mmzpdfmajorversion, parameters=\marg{number}, desc=optional},
+ cmd={name=mmzpdfminorversion, parameters=\marg{number}, desc=optional},
+ }
+ Defining (one or both of) these macros requests that the extern PDF be
+ produced with the given major\slash minor PDF version, i.e.\ the extraction
+ script will set registers \docref{reg:pdfmajorversion} and
+ \docref{reg:pdfminorversion}.
+ \end{doc}
+
+ After extracting the extern, the script will end the compilation, i.e.\
+ intentionally, only one page documents can be produced.
+\end{doc}
+
+\subsubsection{The clean-up scripts}
+\label{sec:cleanup-scripts}
+
+\begin{doc}{
+ script={name=memoize-clean.pl, par=[\meta{options}] [\meta{name}\texttt{.mmz} \dots]},
+ script={name=memoize-clean.py, par=[\meta{options}] [\meta{name}\texttt{.mmz} \dots]},
+ }
+ This script removes memo and extern files whose filenames start with
+ \meta{path prefix}es mentioned in the given \dmmz files or by the
+ \refscript{memoize-clean.pl--prefix} option. Unless option
+ \refscript{memoize-clean.pl--all} is given, the script only deletes the
+ \emph{stale} files, i.e.\ the files not mentioned in any of the given \dmmz
+ files.
+
+ A \meta{path prefix} of a memo or an extern is what was set by key
+ \refmmz{path}, or more commonly, one of the shortcut keys \refmmz{memo dir}
+ and \refmmz{no memo dir}; see section~\ref{sec:ref:dirs} for details on the
+ form of a memo/extern filename.
+
+ In detail, the script scans the given \dmmz files for occurrences of
+ \refcmd{mmzPrefix}, and adds their \meta{path prefix} arguments to the list
+ of prefixes given on the command line by option
+ \refscript{memoize-clean.pl--prefix}; a \meta{path prefix} occurring in some
+ \dmmz file is interpreted relatively to the location of the \dmmz file. The
+ script removes all files whose full pathname (relative to the current
+ directory) matches pattern \meta{path
+ prefix}\meta{md5sum}(|-|\meta{md5sum})(|.memo|\alt(|-|$N$)|.pdf|\alt|.log|),%
+ \footnote{The |.log| files are produced by the \hologo{TeX}-based extraction
+ script.} except those which occur as the \meta{filename} argument to one
+ of \refcmd{mmzUsedCMemo}, \refcmd{mmzUsedCCMemo}, \refcmd{mmzUsedExtern},
+ \refcmd{mmzNewCMemo}, \refcmd{mmzNewCCMemo} and \refcmd{mmzNewExtern} in one
+ of the \dmmz files.
+
+ The script is fairly paranoid. It refuses to delete anything if a \dmmz file
+ is malformed in any way (but not if it doesn't exist or is completely empty,
+ which facilitates its usage in clean-up scripts), or if it would remove a
+ file not residing under the current directory. Before removing the files, it
+ lists the files to be removed and asks for confirmation.
+
+ Functionally, the Perl (|.pl|) and the Python (|.py|) version are completely
+ equivalent.
+
+ \yadocset{
+ of=script:memoize-clean.pl,
+ override/.style={
+ index annotation={option of {%
+ \hypercolor{link}{gray}%
+ \hyperref[script:memoize-clean.pl]{\texttt{memoize-clean}}%
+ }},
+ },
+ }
+ \begin{doc}{
+ option={name=prefix, short name=p, par=\meta{path prefix}}
+ }
+ Add \meta{path prefix} to the list of prefixes; the given prefix is
+ relative to the current directory. This option may be given multiple
+ times.
+ \end{doc}
+ \begin{doc}{
+ option={name=all, short name=a}
+ }
+ When given this option, the script removes \emph{all} memos and externs
+ belonging to the document, not just the stale ones, i.e.\ it effectively
+ ignores the occurences of \refcmd{mmzUsedCMemo} and friends in the \dmmz
+ file.
+ \end{doc}
+ \begin{doc}{
+ option={name=yes, short name=y}
+ }
+ When given this option, the script does not ask for confirmation before
+ removing the files.
+ \end{doc}
+ \begin{doc}{
+ option={name=quiet, short name=q}
+ }
+ Normally, the script prints what it is doing to the standard output; in
+ particular, it prints out the filename of each file as it is deleting it.
+ This option disables this behaviour.
+ \end{doc}
+ \begin{doc}{
+ option={name=help, short name=h}
+ }
+ Show help.
+ \end{doc}
+ \begin{doc}{
+ option={name=version, short name=V}
+ }
+ Show Memoize version.
+ \end{doc}
+\end{doc}
+
+\subsubsection{Record files}
+\label{sec:ref:record-files}
+
+\begin{doc}{
+ key={name=record, par=\marg{record type},
+ desc={cumulative, initially \refmmz{record=mmz}, no default}},
+ key={name=no record},
+ }
+ Memoize records which externs were produced and used in the compilation,
+ producing a record file of every type found in the record-type list. These
+ keys add \meta{record type} to the record-type list, or clear this list. See
+ section~\ref{sec:record-files} for details.
+
+ Note that passing an undefined \meta{record type} to this key will not yield
+ an error.
+
+ Out of the box, the following \meta{record type}s are recognized:
+ \yadocset{of=key:/mmz/record}
+ \begin{doc}{value={name=mmz}}
+ This record type produces a \dmmz file recording new/used
+ externs/c-memos/cc-memos and changes in the \refmmz{path} prefix to these
+ files; see section~\ref{sec:.mmz} for details.
+
+ The produced file is named \docAux{file={name=mmz,
+ name prefix=\meta{jobname}.,
+ ref prefix=.,
+ index prefix=.,
+ }}. This name cannot be changed.
+
+ The \dmmz file is a \hologo{TeX} file, but uses only a simple subset of
+ the \hologo{TeX} syntax, to be easily parsable by the external scripts such
+ as \refscript{memoize-extract.pl}. Each line of the file consists of a
+ (possibly commented) invocation of one of the commands listed below; the
+ final line is |\endinput|. The \meta{path prefix} below consists of the
+ path to memos/externs and the immutable \refmmzpath{prefix} of their filename.
+ \begin{doc}{
+ cmd={name=mmzUsedCMemo, par=\marg{filename}},
+ cmd={name=mmzUsedCCMemo, par=\marg{filename}},
+ cmd={name=mmzUsedExtern, par=\marg{filename}},
+ }
+ Record that the (c)c-memo or extern residing in file \meta{filename} was
+ utilized.
+ \end{doc}
+ \begin{doc}{
+ cmd={name=mmzNewCMemo, par=\marg{filename}},
+ cmd={name=mmzNewCCMemo, par=\marg{filename}},
+ }
+ Record that a new (c)c-memo residing in file \meta{filename} was
+ produced.
+ \end{doc}
+ \begin{doc}{cmd={name=mmzNewExtern, par=\marg{filename}\marg{page number}%
+ \marg{expected width}\marg{expected height}}}
+ Record that a new extern was produced and dumped as page \meta{page
+ number} into the document, that it should be extracted into file
+ \meta{filename}, and that it should be \meta{expected width} wide and
+ \meta{expected height} high (modulo tolerance of |0.01pt|, see
+ footnote~\ref{fn:tolerance}), where the height is the total height
+ comprising both \hologo{TeX} height and depth.
+ \end{doc}
+ \begin{doc}{cmd={name=mmzPrefix, par=\marg{path prefix}}}
+ Record that the \refmmz{path} prefix of memo and extern files was
+ changed.
+ \end{doc}
+ \end{doc}
+ \begin{doc}{value={name=makefile}}
+ This record type produces a makefile which, when processed by the |make|
+ utility, triggers \hologo{TeX}-based extraction of the new externs.
+ \begin{doc}{
+ key={name=makefile, par=\marg{filename}, desc={no default,
+ initially \texttt{memoize-extract.\jobname.makefile}}}
+ }
+ Use this key to change the filename of the produced makefile.
+ \end{doc}
+ \end{doc}
+ \begin{doc}{value={name=sh}, value={name=bat}}
+ These record types produce a shell script which, when executed, triggers
+ \hologo{TeX}-based extraction of the new externs.
+
+ Use \refmmz{record=sh} on Unix-like systems, and \refmmz{record=bat} on
+ Windows.
+
+ \begin{doc}{
+ key={name=sh, par=\marg{filename}, desc={no default,
+ initially \texttt{memoize-extract.\jobname.sh}}},
+ key={name=bat, par=\marg{filename}, desc={no default,
+ initially \texttt{memoize-extract.\jobname.bat}}}
+ }
+ Use these keys to change the filename of the produced shell script.
+ \end{doc}
+ \end{doc}
+\end{doc}
+
+\begin{doc}{
+ desc=definable,
+ keypath=/mmz/record/\meta{record type},
+ keypath label=/mmz/record/record type,
+ name prefix={\meta{record type}/}, ref prefix=,
+ index annotation={key in \texttt{/mmz/\meta{record type}}},
+ key={name=begin},
+ key={name=prefix, par=\marg{path prefix}},
+ key={name=new extern, par=\marg{filename}},
+ key={name=new cmemo, par=\marg{filename}},
+ key={name=new ccmemo, par=\marg{filename}},
+ key={name=used extern, par=\marg{filename}},
+ key={name=used cmemo, par=\marg{filename}},
+ key={name=used ccmemo, par=\marg{filename}},
+ key={name=end},
+ }
+ A new record type can be implemented by defining these keys in keypath
+ \docAux{key path={name=mmz/record/\meta{record type}, label=mmz/record/record
+ type}} (using the standard \pkg{pgfkeys} handlers such as |.code| and
+ |.style|). The keys are invoked by Memoize where appropriate if recording
+ for the defined type is activated by \refmmz{record}|=|\meta{record type},
+ just as for the predefined types. Only those keys which are required for
+ implementing the desired functionality need to be defined.
+
+ The following macros are available during the execution of key
+ \refmmz{record/record type/new extern}:
+ \yadocset{before/.style={label prefix=cmd:ne},
+ index annotation=defined at \refmmz{record/record type/new extern}}
+ \begin{doc}{cmd={name=pagenumber}}
+ This macro holds the number of the extern page.
+ \end{doc}
+ \begin{doc}{
+ cmd={name=expectedwidth},
+ cmd={name=expectedheight},
+ }
+ These macros hold the width and the height of the extern page.
+ \end{doc}
+ \begin{doc}{cmd={name=externbasepath}}
+ This macro holds the filename of the extern, minus the |.pdf| suffix (but
+ including the path leading to the extern).
+ \end{doc}
+\end{doc}
+
+
+
+\subsection{Automemoization}
+\label{sec:ref:advicememoization}
+
+
+\subsubsection{Package Advice}
+\label{sec:ref:advice}
+
+Package Advice is a namesake of \Emacs's Advice. As such, it implements a
+generic framework for extending the functionality of selected commands and
+environments. Each \emph{advised} command and environment is assigned a piece
+of \emph{advice} --- a command which is executed instead of the advised command
+and environment, and which may, or may not, invoke the original command or
+environment during its execution. The package offers an elegant way of
+declaring advice, setting up the conditions upon which the advised command will
+actually be replaced by the advice, collecting the arguments of the advised
+command and invoking it, and (de)activating the advice.
+
+Before the advising framework can be used, it must be installed into a selected
+\pkg{pgfkeys} keypath (multiple installations into different keypaths are
+allowed, even if they handle the same commands). Memoize installs the
+framework into keypath \refkeypath{/mmz} and (primarily) uses it to
+automatically memoize the results of compilation of selected commands and
+environments.
+
+\begin{doc}{
+ keypath={/handlers},
+ key={name=.install advice,
+ sort index=install advice,
+ par=\marg{configuration keylist},
+ },
+ }
+ This key is a \pkg{pgfkeys} key handler (see \PGFmanual{87.3.5}) which
+ installs the advising framework into the keypath which it was invoked from
+ --- henceforth, the \meta{namespace}.
+
+ For example, \code{\cs{pgfkeys}\bracestt{/my/\refkey{/handlers/.install
+ advice}}} installs the framework into keypath |/my|.
+
+ Argument \meta{configuration keylist} may contain the following keys:
+ \yadocset{keypath=/advice/install}
+ \begin{doc}{key={
+ name=setup key,
+ parameters=\marg{name},
+ description={no default, initially \texttt{advice}}},
+ }
+ This key determines the names of the user-interface keys used to setup
+ advice for commands and environments in \meta{namespace}.
+
+ The keys whose names are determined by this key are the following:
+ \meta{name}, \code{\meta{name} csname}, \code{\meta{name} key},
+ \code{\meta{name}'}, \code{\meta{name} csname'} and \code{\meta{name}
+ key'}. Memoize sets \refkey{/advice/install/setup key}|=auto|, and
+ thereby defines \refmmz{auto}, \refmmz{auto csname}, \refmmz{auto key},
+ \refmmz{auto'}, \refmmz{auto csname'} and \refmmz{auto key'}.
+ \end{doc}
+ \begin{doc}{key={
+ name=activation,
+ par=\meta{initial activation type},
+ desc={no default, initially \texttt{immediate}}
+ },
+ }
+ This key sets the \meta{initial activation type} for \meta{namespace}.
+
+ At the end of the installation, the system will execute
+ \meta{namespace}|/|\refmmz{activation}|=|\meta{initial activation type};
+ consequently, \meta{initial activation type} must be one of
+ \refmmz{activation=immediate} and \refmmz{activation=deferred}. In
+ Memoize, the \meta{initial activation type} is
+ \refmmz{activation=deferred}.
+
+ Setting the \refmmz{activation} type during the installation only matters
+ in \hologo{LaTeX}, where the installation ends by advising \refcmd{begin}
+ to implement advising of environments.
+ \end{doc}
+
+ \begin{tcolorbox}[warning]
+ Writing the documentation for Advice, I was faced with a dilemma. Should
+ the documentation reflect the fact that the full names of keys defined by
+ the package depend on the installed instance of the framework, in
+ particular on \meta{namespace} and \meta{setup key}? For example, should
+ the reference headers contain things like \meta{namespace}|/activate| and
+ \meta{namespace}|/|\meta{setup key} |csname|? In my opinion, this would
+ make the reference hard to read, so I decided to have the reference headers
+ refer to the Advice keys of the Memoize installation, where
+ \meta{namespace}=|/mmz| and \meta{setup key}=|auto|, resulting in
+ friendlier headers such as \refkeypath{/mmz}|/|\refmmz{activate} and
+ \refkeypath{/mmz}|/|\refmmz{auto csname}. (Consequently, it also made
+ sense to document Advice within the Memoize documentation.)
+
+ The bottomline: if you're reading this section with a non-Memoize
+ installation in mind, you have to mentally replace any \refkeypath{/mmz}
+ and \refmmz{auto} in the reference headers with the \meta{namespace} and
+ the \meta{setup key} selected by that installation.
+ (Section~\ref{sec:ref:advice:memoization} is another matter. Keys
+ described there are only available in Memoize.)
+ \end{tcolorbox}
+
+ In more detail, key handler \refkey{/handlers/.install advice} performs the
+ following actions (as explained in the box above, we assume that the
+ advising framework was installed into keypath \refkeypath{/mmz} with the
+ setup key named |auto|):
+ \begin{itemize}
+ \item \edef\origtolerance{\the\tolerance}\tolerance=1000
+ It defines the following keys in keypath \refkeypath{/mmz}:
+ \refmmz{auto},
+ \refmmz{auto csname},
+ \refmmz{auto key},
+ \refmmz{auto'},
+ \refmmz{auto csname'},
+ \refmmz{auto key'},
+ \refmmz{activation},
+ \refmmz{activate deferred},
+ \refmmz{activate},
+ \refmmz{deactivate},
+ \refmmz{activate csname},
+ \refmmz{deactivate csname}.
+ \refmmz{activate key},
+ \refmmz{deactivate key}.
+ \refmmz{force activate},
+ \refmmz{try activate}.
+ \item
+ It defines the following keys in keypath \refkeypath{/mmz/auto}:
+ \refmmzauto{run conditions},
+ \refmmzauto{outer handler},
+ \refmmzauto{bailout handler},
+ \refmmzauto{collector},
+ \refmmzauto{args},
+ \refmmzauto{collector options},
+ \refmmzauto{clear collector options},
+ \refmmzauto{raw collector options},
+ \refmmzauto{clear raw collector options},
+ \refmmzauto{inner handler},
+ \refmmzauto{options},
+ \refmmzauto{clear options},
+ \refmmzauto{reset}.
+ \item \tolerance\origtolerance\relax
+ It defines the |.unknown| key handler for \refkeypath{/mmz/auto}.
+ This handler appends any unknown keys (and their values) to
+ \refmmzauto{options}.
+ \item It executes \refmmz[show keypath]{activation}|=|\meta{initial
+ activation type}.
+ \item In \hologo{LaTeX}, it submits \refcmd{begin} to advising, thereby
+ enabling environment support in this format. Consequently, advising of
+ environments can switched off by writing \refmmz{deactivate}|=\begin|.
+ \end{itemize}
+\end{doc}
+
+\paragraph*{The keys installed into keypath \metabf{namespace}} are used to
+declare and (de)activate advice. In the documentation in this subsection,
+we assume that \meta{namespace}=\refkeypath{/mmz} and that \meta{setup
+ key}=\refmmz{auto}. In particular, this also applies to the reference
+headers.
+
+\begin{doc}{
+ key={name=activation, par=\docAux{of=key:/mmz/activation, value={name=immediate},
+ text=\Alt, value={name=deferred}}, desc={style, no default}},
+ key={name=activate deferred, desc={style}},
+ }
+ Key \refmmz{activation} selects the activation regime. Under the
+ \refmmz{activation=immediate} regime, keys \refmmz{activate},
+ \refmmz{deactivate}, \refmmz{force activate} and \refmmz{try activate} behave
+ as described in their documentation below. Under the
+ \refmmz{activation=deferred} regime, however, those keys are not executed;
+ rather, their invocations are appended to style \refmmz{activate deferred}.
+ For example, writing \refmmz{activate}|=\foo| in the deferred activation
+ regime appends \refmmz{activate}|=\foo| to \refmmz{activate deferred}. It is
+ up to the user if and when to execute the keys collected in \refmmz{activate
+ deferred}; see the documentation of \refmmz{manual} to learn what Memoize
+ does with the contents of this style.
+\end{doc}
+
+
+\begin{doc}{easy,
+ par=\marg{list of commands and/or environments},
+ desc={style},
+ key={name=activate},
+ key={name=deactivate},
+ }
+ These keys activate or deactivate the advice for the given commands and
+ environments. When the advice is activated, it replaces the advised command;
+ when it is deactivated, the command is reverted to its original definition.
+
+ In Memoize, these keys are most commonly used to activate or deactivate
+ automemoization for the given commands or environments. For example, write
+ \refmmz{deactivate}|={\tikz,tikzpicture}| to deactivate automemoization of
+ \TikZ pictures (which is declared and active by default). The curly braces
+ may be omitted if the list contains a single command or environment, e.g.\
+ \refmmz{deactivate}|=\tikz| or \refmmz{deactivate}|=tikzpicture|.
+
+ (De)activation of a piece of advice is completely orthogonal to its declaration with
+ \refmmz{auto}. For example, there is no need to deactivate a command before
+ redeclaring its advice, and reactivate it afterwards. A command may be
+ activated even before declaring its advice --- however, the command itself
+ must be defined at the time of activation.
+
+ As the advice is normally automatically activated upon declaration with
+ \refmmz{auto}, explicit activation is rarely needed, but see \refmmz{auto'}.
+ The effect of these keys under the deffered activation regime is described in
+ \refmmz{activation}.
+
+ Note that I sometimes speak of (de)activating a command, and sometimes of
+ (de)activating its advice. I mean the same thing.
+\end{doc}
+
+\begin{doc}{
+ par=\marg{control sequence name},
+ desc={style},
+ key={name=activate csname},
+ key={name=deactivate csname},
+ }
+ These keys activate and deactivate a command given by its \meta{control
+ sequence name}; for example, \refmmz{activate csname}|=foo| is equivalent
+ to \refmmz{activate}|=\foo|. Note that unlike the regular \refmmz{activate}
+ and \refmmz{deactivate}, their |csname| variants only accept a single command
+ at a time (otherwise, including a comma in the command name would be
+ impossible).
+\end{doc}
+
+\begin{doc}{
+ par=\marg{list of full key names},
+ desc={style},
+ key={name=activate key},
+ key={name=deactivate key},
+ }
+ These keys activate and deactivate |pgfkeys| keys. Note that \emph{full} key
+ names must be given, i.e.\ the names must include the keypath.
+
+ Under the hood, these keys merely execute \refmmz{activate} and
+ \refmmz{deactivate} on the internal macros corresponding to the given keys.
+\end{doc}
+
+\begin{doc}{
+ key={name=try activate, conditional=false},
+ }
+ When this conditional is set to true, \refmmz{activate} will not yield an
+ error if the advice is already activated, and \refmmz{deactivate} will not
+ yield an error if the advice is not yet activated.
+
+ This key applies to the next, and only to the next, invocation of key
+ \refmmz{activate} or \refmmz{deactivate}, i.e.\ it is reset back to |false|
+ after invoking \refmmz{activate} or \refmmz{deactivate}.
+\end{doc}
+
+\begin{doc}{
+ key={name=force activate, conditional=false},
+ }
+ When this conditional is set to true, \refmmz{activate} will activate even a
+ previously activated command, provided that, additionally, the command has
+ been redefined since the prior activation.
+
+ In more detail, the original definition of the advised command is saved upon
+ activation (to provide the possibility of both deactivation and the usage of
+ the original command by the handler). Consequently, activation of an already
+ activated command would result in the saved original definition being
+ overwritten by the redefinition made during the first activation. However,
+ if the handled command was meanwhile redefined by a third party, reactivation
+ makes sense, under the assumption that the former original definition is
+ obsolete and should be replaced by the (third party) redefinition. As a
+ safeguard, however, \refmmz{activate} requires such reactivation to be
+ explicitly requested using conditional \refmmz{force activate}.\footnote{A
+ potential problem, not (yet) addressed, is that the third party might be
+ another incarnation of the advising framework. In this case, forced
+ reactivation will result in the loss of the original command and a circular
+ dependency between the two pieces of advice.}
+
+ This key applies to the next, and only to the next, invocation of key
+ \refmmz{activate}, i.e.\ it is reset back to |false| after invoking
+ \refmmz{activate}. This key does not apply to \refmmz{deactivate}.
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=auto, par=\marg{command or environment}{\marg{keylist}}, desc=style}}
+
+ This key sets up the advice for the given command or environment, or updates
+ the configuration of an existing piece of advice.
+
+ In Memoize, this key is most commonly used to submit a command or environment
+ to automemoization. For an environment (say, |bar|), it suffices to write
+ \refmmz{auto}|=|\bracestt{bar}\bracestt{\refmmzauto{memoize}}; for a command,
+ we usually need to include its argument specification:
+ \refmmz{auto}|=\foo|\bracestt{\refmmzauto{memoize},
+ \refmmzauto{args}=\bracestt{...}}. Another common usage is to prevent
+ memoization during the execution of a command or environment:
+ \refmmz{auto}|=|\bracestt{bar}\bracestt{\refmmzauto{nomemoize}}. For
+ details, see sections~\ref{sec:tut:automemoization},
+ \ref{sec:tut:working-on-a-picture} and~\ref{sec:tut:verbatim}.
+
+ The advice is configured by the given \meta{keylist}, which is executed with
+ the default keypath set to \docaux{key path}{mmz/auto}. Any unknown keys in
+ \meta{keylist} are passed on to key \refmmzauto{options}; for example, a
+ plain \refmmz{verbatim} or \refmmz{padding}|=2in| have the same effect as
+ \refmmzauto{options}|=|\refmmz{verbatim} or
+ \code{\refmmzauto{options}=\braces{\refmmz{padding}=2in}}.
+
+ This key automatically activates the declared advice, unless it is already
+ activated; under the deferred activation regime, the automatic activation is
+ deferred as well. Use variant \refmmz{auto'} when you don't want to
+ automatically activate the advice.
+
+ When this key is used on a command or environment with an existing piece of advice,
+ the advice is merely updated. This makes it easy to, for example,
+ temporarily switch to verbatim collection of an environment in Memoize:
+ \refmmz{auto}|=|\bracestt{tcolorbox}\braces{\refmmz{verbatim}}. Use key
+ \refmmzauto{reset} to setup the advice from scratch:
+ \refmmz{auto}|=|\bracestt{...}\bracestt{\refmmzauto{reset}, ...}.
+
+ A piece of advice consists of several interlocked components, declared by keys
+ residing in path \refkeypath{/mmz/auto}: \refmmzauto{run conditions},
+ \refmmzauto{bailout handler}, \refmmzauto{outer handler},
+ \refmmzauto{collector} and \refmmzauto{inner handler}. During the execution
+ of the advice, these components are available through the following macros:
+ \refcmd{AdviceRunConditions}, \refcmd{AdviceBailoutHandler},
+ \refcmd{AdviceOuterHandler}, \refcmd{AdviceCollector} and
+ \refcmd{AdviceInnerHandler}. These macros are also defined during setup, and
+ it is possible to change the configuration by modifying them directly; in
+ that case, it likely also makes sense to use the low-level variant of this
+ key, macro \refcmd{AdviceSetup}.
+
+ Control sequences used in the advice components do not need to be defined at
+ the time of invoking key \refmmz{auto}, or activating the advice; they must
+ only be defined at the time the advice is actually executed. It is thus
+ perfectly fine to declare \refmmzauto{inner handler}|=\myinnerhandler| before
+ defining |\myinnerhandler|, or to redefine |\myinnerhandler| between the
+ invocations of the advised command.
+
+ This key configures not only the components, but also the options of the
+ advice. These options are set by keys \refmmzauto{args},
+ \refmmzauto{collector options}, \refmmzauto{raw collector options} and
+ \refmmzauto{options}. Whether these options are used or not depends on the
+ advice components. (Same as the components, the options have their
+ corresponding low-level macros: \refcmd{AdviceArgs},
+ \refcmd{AdviceCollectorOptions}, \refcmd{AdviceRawCollectorOptions} and
+ \refcmd{AdviceOptions}.)
+
+ Parameter symbols (i.e.\ |#|) are not allowed in advice settings.
+
+ A command or environment may be submitted to several instances of the
+ advising framework, i.e.\ instances installed under different keypaths. The
+ effect of such chained advice depends on the order of activation. If advice
+ $A$ is activated before advice $B$, it will also be applied before $B$.
+
+ The advice setup takes place in a group. Use key \refmmzauto{after setup} to
+ execute code outside this group.
+
+ In general, the name of this key equals whatever was submitted to
+ \refkey{/advice/install/setup key} during the installation of the advising
+ framework via \refkey{/handlers/.install advice}.
+\end{doc}
+
+\begin{doc}{
+ key={name=auto csname, par=\marg{control sequence name}{\marg{keylist}}, desc=style}
+ }
+ This key is a variant of \refmmz{auto}, but with the command of the first
+ argument given as a control sequence name, i.e.\ \refmmz{auto
+ csname}|={foo}{...}| is equivalent to \refmmz{auto}|=\foo{...}|.
+\end{doc}
+
+\begin{doc}{
+ key={name=auto key, par=\marg{full key}{\marg{keylist}}, desc=style},
+ }
+ This key is a variant of \refmmz{auto}, but it works with \pkg{pgfkeys} keys.
+ The first argument should be a \meta{full key} like |/tcb/float|, i.e.\ it
+ must consist of both the keypath and the keyname.
+
+ This key sets up advice for the internal command corresponding to the given
+ \meta{full key}, and also properly initializes the collector, so that
+ \refmmzauto{inner handler} will ``just work.''
+\end{doc}
+
+\begin{doc}{
+ key={name=auto', par=\marg{command or environment}{\marg{keylist}}, desc=style},
+ key={name=auto csname', par=\marg{control sequence name}{\marg{keylist}}, desc=style},
+ key={name=auto key', par=\marg{full key}{\marg{keylist}}, desc=style},
+ }
+ These keys are variants of \refmmz{auto}, \refmmz{auto csname} and
+ \refmmz{auto key} which do not attempt to activate the command after setting
+ it up.
+\end{doc}
+
+\begin{doc}{
+ cmd={
+ name=AdviceSetup,
+ par=\marg{namespace}\marg{command or environment}{\marg{setup code}}
+ }}
+ This macro is the low-level variant of key \refmmz{auto}. The differences
+ between the two are the following:
+ \begin{itemize}
+ \item An invocation of the macro must provide the namespace (i.e.\ the
+ installation keypath) as the first argument.
+ \item There is no automatic activation at the end of the setup.
+ \item The final argument should not be a keylist (of keys belonging to
+ \refkeypath{/mmz/auto}) but \hologo{TeX} code adjusting the contents of the
+ settings macros \refcmd{AdviceRunConditions}, \refcmd{AdviceBailoutHandler},
+ \refcmd{AdviceOuterHandler}, etc. For the full list of available macros, see
+ the documentation of their corresponding keys below; the setting macros are
+ mentioned at the end of each entry.
+ \end{itemize}
+\end{doc}
+
+\begin{doc}{
+ cmd={name=AdviceTracingOn},
+ cmd={name=AdviceTracingOff},
+ }
+ Advice tracing is initially off. When it is on, Advice will show (on the
+ terminal and in the |.log| file) which advice components are executed, and
+ what arguments and options they have received.
+\end{doc}
+
+\paragraph*{The keys installed into keypath \metabf{namespace}\texttt{/}\metabf{setup key}}
+are used to configure advice. They may only occur within the second
+argument of the setup key. In the documentation in this subsection, we assume
+that \meta{namespace}=\refkeypath{/mmz} and that \meta{setup
+ key}=\refmmz{auto}. In particular, this also applies to the reference
+headers.
+
+\begingroup
+\yadocset{keypath=/mmz/auto}
+
+\begin{doc}{%
+ key={name=run conditions, par=\meta{\hologo{TeX} code},
+ desc=initially and default: \refcmd{AdviceRuntrue}},
+ }
+
+ This key declares the \meta{control sequence} as the run conditions component
+ of the advice.
+
+ The run conditions macro is executed at the very start of the advice. Its
+ function is to decide whether we should proceed to advise the command by
+ executing the outer handler, or execute the original command (after invoking
+ the bailout handler).
+
+ The run conditions macro should take no arguments. If it determines that the
+ run conditions are satisfied, it should set the \hologo{TeX} conditional
+ \docaux{cmd}{ifAdviceRun} to true by executing \docaux{cmd}{AdviceRuntrue}.
+ There is no need to execute \docaux{cmd}{AdviceRunfalse} when the run
+ conditions are not satisfied.
+
+ Initially, the run conditions are set to \refcmd{AdviceRuntrue}, translating to
+ ``always run.'' For two non-trivial examples, see \refmmzauto{run if
+ memoization is possible} and \refmmzauto{run if memoizing}. Executing this
+ key without a value restores it to the initial value.
+
+ During advising and advice setup, the run conditions of the advised command
+ are accessible through \docaux{cmd}{AdviceRunConditions}, a parameterless
+ macro expanding to the given \meta{\hologo{TeX} code}.
+\end{doc}
+
+\begin{doc}{%
+ key={name=bailout handler, par=\meta{\hologo{TeX} code},
+ desc=initially and default: \cs{relax}},
+ }
+
+ This key declares the \meta{\hologo{TeX} code} as the bailout handler
+ component of the advice.
+
+ The bailout handler is executed when the run conditions are not met, just prior
+ to executing the original definition of the advised command. The bailout
+ handler should take no arguments.
+
+ The initial bailout handler, |\relax|, does nothing. Memoize defines and
+ uses a bailout handler which clears the next-options. Executing this key
+ without a value restores it to the initial value.
+
+ During advising and advice setup, the bailout handler of the handled command is
+ accessible through \docaux{cmd}{AdviceBailoutHandler}, a parameterless macro
+ expanding to the given \meta{\hologo{TeX} code}.
+\end{doc}
+
+\begin{doc}{
+ key={name=outer handler,par=\meta{\hologo{TeX} code},
+ desc=initially and default: see below},
+ }
+
+ This key declares the \meta{\hologo{TeX} code} as the outer handler component
+ of the advice.
+
+ The outer handler can be safely imagined as the command which replaces the
+ handled command. This also holds for handled environments, but with a
+ caveat: for a \hologo{plainTeX} or \hologo{ConTeXt} environment |foo|, the
+ outer handler replaces |\foo| and |\startfoo|, respectively; in the case of a
+ \hologo{LaTeX} environment, it replaces |\begin{foo}|.%]
+
+ The outer handler is the first component which has the opportunity to inspect
+ the arguments given to the handled command. It is invoked just in front of
+ these arguments (which are, in case \hologo{TeX} hasn't seen them yet,
+ untokenized), and while it is expected that the advice will consume
+ the same arguments as the advised command itself would, how precisely that
+ happens may vary from situation to situation. In particular, the argument
+ structure of the outer handler is not prescribed.
+
+ In fact, the outer handler has complete control over the remainder of the
+ advising process. In situations where advising requires knowledge of the
+ advised command's arguments as a whole, the outer handler executes the
+ collector, which in turn invokes the inner handler, which does the real work;
+ see \refmmzauto{memoize} for the usage case which inspired this design.
+ Sometimes, however, it is the outer handler which does the real work (and
+ there is thus no inner handler). This is the case in situations when the
+ arguments of the handled command are irrelevant for the functioning of the
+ advice, or when the advice needs to inspect some individual argument of the
+ handled command; for examples of such situations, see \refmmzauto{abort} and
+ \refmmzauto{ref}.
+
+ To reiterate the argument situation of the outer handler, it sees the
+ arguments of the handled command as they were given. The arguments are
+ \emph{not} collected before invoking the outer handler --- in fact, avoiding
+ the argument collection is the raison d'être of the outer handler! (In the case
+ of an advised environment, the environment body can be seen as an argument of
+ \pkg{xparse} type \docref{xparse:+}\docref{xparse:b}.)
+
+ The outer handler (and any other component of the advice it invokes) has
+ access to the following auxiliary macros, defined by the framework:
+ \begin{itemize}
+ \item \tolerance 1000 the macros holding the configuration of the advised
+ command, as set up by \refmmz{auto}: \refcmd{AdviceRunConditions},
+ \refcmd{AdviceBailoutHandler} and \refcmd{AdviceOuterHandler} are probably
+ useless, as they refer to components already invoked, but the remaining
+ components (\refcmd{AdviceCollector} and \refcmd{AdviceInnerHandler}) and
+ their options (\refcmd{AdviceArgs}, \refcmd{AdviceCollectorOptions},
+ \refcmd{AdviceRawCollectorOptions} and \refcmd{AdviceOptions}) should be
+ commonly used.
+ \item the macros holding information about the namespace and the advised
+ command or environment: \refcmd{AdviceNamespace}, \refcmd{AdviceName},
+ \refcmd{AdviceReplaced} and \refcmd{AdviceOriginal}. (Command
+ \refcmd{AdviceGetOriginal} might also be useful, although using
+ \refcmd{AdviceOriginal} will likely be more practical.)
+ \end{itemize}
+
+ This key is initially set to an internal control sequence which merely
+ invokes the collector by executing \refcmd{AdviceCollector}; in other words,
+ the initial outer handler leaves all the work to the collector and the inner
+ handler. There is no need to specifically set up the outer handler when
+ using the inner handler. Executing this key without a value restores it to
+ the initial value.
+
+ During advising and advice setup, the outer handler of the advised command is
+ accessible through \docaux{cmd}{AdviceOuterHandler}, a parameterless macro
+ expanding to the given \meta{\hologo{TeX} code}.
+\end{doc}
+
+\begin{doc}{
+ key={name=collector,par=\meta{\hologo{TeX} code},
+ desc=initially and default: see below},
+ }
+
+ This key declares the \meta{\hologo{TeX} code} as the collector component of
+ the advice.
+
+ The collector, if used, is invoked by the outer handler. It is invoked
+ immediately in front of the advised command's arguments (which are, in case
+ \hologo{TeX} hasn't seen them yet, untokenized), and its function is to
+ collect these arguments and pass them on, as a single argument, to the inner
+ handler.
+
+ While this manual occasionally states that the initial argument collector is
+ \refcmd{CollectArguments} of package CollArgs, this is, if we're precise,
+ incorrect on two counts. For one, the initial collector is not a CollArgs
+ command, but a macro which acts as the ``bridge'' between Advice
+ and CollArgs. Second, the initial collector does not really invoke
+ \refcmd{CollectArguments}, but its cousin, \refcmd{CollectArgumentsRaw},
+ which allows Advice (and Memoize) to fine tune its behaviour
+ using the fast low-level (``programmer interface'') commands rather than the
+ slower \pkg{pgfkeys} interface; clearly, the latter point also provides
+ raison d'être for \refmmzauto{raw collector options}. Summing up, this key
+ is initially set to an internal control sequence which compiles the settings
+ provided by \refmmzauto{args}, \refmmzauto{collector options} and
+ \refmmzauto{raw collector options} into an invocation of
+ \refcmd{CollectArgumentsRaw} of package CollArgs.\footnote{The initial
+ collector also sets the CollArgs' option \refcollargs{caller} to the
+ name of the advised command or environment.} Executing this key without a
+ value restores it to the initial value.
+
+ The above-mentioned collector settings were clearly tailored to suit
+ \refcmd{CollectArgumentsRaw}. In general, a collector might or might not use
+ them, and if it does, it may interpret them in any way. For example, Advice
+ ships with a \refcmd{tikz} collector, \docaux{cmd}{mmzCollectTikZArguments}, which
+ ignores them completely, as it knows everything about the idiosyncrasies of
+ that command anyway. Incidentally, \refcmd{mmzCollectTikZArguments} becomes
+ available upon loading \reffile{advice-tikz.code.tex} (which Memoize does
+ automatically in the presence of \TikZ).
+
+ The collector has access to the same auxiliary macros as the outer handler.
+ In particular, it will \emph{have} to use \refcmd{AdviceInnerHandler} (followed
+ by the braced collected arguments) to invoke the inner handler.
+
+ During advising and advice setup, the collector of the advised command is
+ accessible through \docaux{cmd}{AdviceCollector}, a parameterless macro
+ expanding to the given \meta{\hologo{TeX} code}.
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=args,par=\meta{argument specification}, desc=initially and default: unset},
+ }
+
+ This key describes the \meta{argument specification} of the advised command.
+
+ Assuming that the initial value of \refmmzauto{collector} has not been
+ modified, the given \meta{argument specification} is eventually interpreted
+ by command \refcmd{CollectArguments} of package CollArgs, which expects an
+ argument specification in the format specified by package \pkg{xparse}; the
+ format is summarized in the frame below for convenience, for details, see the
+ \pkg{xparse} manual. If the specification is not given, the initial collector
+ assumes that the advised command was defined using \refcmd{NewDocumentCommand}
+ (or similar) of package \pkg{xparse}, and will attempt to retrieve the argument
+ specification automatically via \refcmd{GetDocumentCommandArgSpec}.
+
+ \begin{tcolorbox}[float, before float=\hfill,
+ title={The {\pkg[white]{xparse}} argument specification
+ (as understood by \refcmd[link color=white]{CollectArguments})}]
+ \begin{tabularx}{\linewidth}{>{\tt}lX}
+ \multicolumn{2}{l}{\rm\textbf{Mandatory argument types}}\\
+ m&standard (a single token or multiple tokens in braces)\\
+ r\meta{token$_1$}\meta{token$_2$}&delimited by
+ \meta{token$_1$} and \meta{token$_2$} \\
+ v&verbatim, in the style of \cs{verb}\\
+ b&the body of an environment\\
+ [1ex]\multicolumn{2}{l}{\rm\textbf{Optional argument types}}\\
+ o&in square brackets\\
+ d\meta{token$_1$}\meta{token$_2$}&delimited by
+ \meta{token$_1$} and \meta{token$_2$}\\
+ s&an optional star\\
+ t\meta{token}&an optional \meta{token}\\
+ e\marg{tokens}&a set of embellishments\\
+ [1ex]\multicolumn{2}{l}{\rm\textbf{Weird argument types}}\\
+ l&a mandatory argument until the first begin-group token\\
+ u\marg{tokens}&\hologo{TeX}'s delimited argument\\
+ g&an optional argument inside braces\\
+ [1ex]\multicolumn{2}{l}{\rm\textbf{Modifiers}}\\
+ +&allow the next argument to be long\\
+ !&disallow spaces before arguments of type \docref{xparse:d} and \docref{xparse:t}\\
+ >\marg{processor}&process the next argument\\
+ [1ex]\multicolumn{2}{l}{\rm\textbf{CollArgs extensions}}\\
+ \docref{xparse:b}\marg{name}&set the environment name for this environment\\
+ \docref{xparse:amp}\marg{options}&apply CollArgs options to the next argument\\
+ \docref{xparse:amp}\docref{xparse:amp}\marg{raw options}&apply raw CollArgs options to the next argument\\
+ \end{tabularx}
+
+ \smallskip
+
+ \refcmd{CollectArguments} can grab an argument of any type in the
+ \refcollargs{verbatim} mode.
+
+ As \refcmd{CollectArguments} does not use the arguments but only collects
+ them, it does not care about the default values of optional arguments.
+ Therefore, argument types with defaults (\docref{xparse:O},
+ \docref{xparse:D} and \docref{xparse:R}) may be substituted by their
+ \texttt{-NoValue-} counterparts (\docref{xparse:o}, \docref{xparse:d} and
+ \docref{xparse:r}) and are therefore not included in the above table.
+ \end{tcolorbox}
+
+ In general, however, an argument collector may this interpret this setting it
+ in any way it sees fit --- or not at all. For example, in Memoize the value
+ of \refmmzauto{args} is ignored for command \refcmd{tikz}, which requires a special
+ collector (\refcmd{mmzCollectTikZArguments}).
+
+ When setting up advice for a \emph{command}, this key is initially
+ ``unset,'' i.e.\ it holds a special value indicating that the argument
+ specification is not provided. Note that this special value is not an empty
+ string --- \refmmzauto{args}|={}|, or simply \refmmzauto{args}|=|, indicates
+ a command which takes no arguments. During the execution of the advice, one
+ may use the \hologo{LaTeX}-style conditional
+ \docaux{cmd}{AdviceIfArgs}\marg{true branch}\marg{false branch} to test
+ whether the argument specification was provided. Executing this key without
+ a value restores it to the initial, unset value.
+
+ When setting up the advice of an \emph{environment}, this key is
+ initialized to \docref{xparse:+}\docref{xparse:b} (a long environment body),
+ making it unnecessary to specify this value manually. Note that this holds
+ even for environments with arguments other that the environment body
+ ``argument'': those arguments will be caught as the start of the body even if
+ not explicitly specified.
+
+ During advising and advice setup, the argument specification of the advised
+ command is accessible through \docaux{cmd}{AdviceArgs}, a parameterless macro
+ expanding to the given \meta{argument specification}.
+\end{doc}
+
+
+\begin{doc}{
+ key={name=collector options, par=\marg{keylist},
+ desc={cumulative, initially empty, value required}},
+ key={name=raw collector options, par=\marg{code},
+ desc={cumulative, initially empty, value required}},
+ }
+ These keys append the given value to the list of user-friendly and raw
+ collector options, respectively. A comma is prefixed to the user-friendly
+ \meta{keylist} before appending it.
+
+ Both kinds of collector options are intended to be used by the collector,
+ which may interpret them in any way it sees fit --- or not at all. The
+ initial collector, which invokes \refcmd{CollectArgumentsRaw} of package
+ CollArgs, passes both lists to this command, which interprets
+ \refmmzauto{collector options} as a user-friendly \pkg{pgfkeys} keylist
+ (which therefore requires a bit of processing) and \refmmzauto{raw collector
+ options} as plain \hologo{TeX} code (expecting it to contain only the
+ allowed, ``programmer's interface'' macros).\footnote{Clearly,
+ \refmmzauto{raw collector options} are why Advice deploys
+ \refcmd{CollectArgumentsRaw} rather than \refcmd{CollectArguments}. But
+ how does it then pass the user-friendly \refmmzauto{collector options} to
+ that command? It embeds them in \refcmd{collargsSet}.} The raw variant is
+ used internally by both Advice and Memoize, and may be used by a package
+ deploying the advising framework which wants to save a few processing cycles.
+ In CollArgs, the two kinds of options are functionally equivalent; both are
+ documented in section~\ref{sec:ref:collargs}.
+
+ Initially, the list of collector options is empty, and for commands, so is
+ the list of raw collector options. For environments, however, the latter
+ list is initialized to set (the raw equivalent of) \refcollargs{environment}
+ to the environment name, and \refcollargs{end tag} to true. The rationale
+ for the latter is that the environment body containing the end tag (e.g.\
+ |\end{foo}|) is nicely compatible with \refcmd{AdviceReplaced} (which equals
+the begin tag, e.g.\ |\begin{foo}|) and \refcmd{AdviceOriginal} (which executes
+ the original definition of e.g.\ |\begin{foo}|). For example, thanks to
+ \refcollargs{end tag}, writing \refcmd{AdviceOriginal}|#1| in the inner
+ handler executes the original environment. Importantly, the original
+ environment can be executed without explicitly referring to the
+ environment's name, and with code that works not only for environments of
+ any \hologo{TeX} format, but is actually the same as the code which invokes
+ an original \emph{command}. Consequently, the same inner handler works for
+ both commands and environments, and in all \hologo{TeX} formats.
+
+ Furthermore, the initial collector also sets option \refcollargs{caller}
+ to the name of the advised command or environment (however,
+ \refcollargs{caller} never appears in any of the collector options
+ lists; it is simply prefixed to them while constructing the invocation of
+ \refcmd{CollectArgumentsRaw}). And in Memoize, using keys
+ \refmmz{verbatim}, \refmmz{verb} or \refmmz{no verbatim} triggers the
+ addition of the cognominal \refcollargs{verbatim}, \refcollargs{verb}
+ or \refcollargs{no verbatim} among the collector options.
+
+ Precious few CollArgs' options thus remain to be set by the author. For
+ memoization, the most likely candidates are \refcollargs{ignore nesting}
+ and \refcollargs{ignore other tags}, which could help deal with unusual
+ environments. Overriding the initial \refcollargs{end tag} by
+ \refcollargs{begin tag}, \refcollargs{end tag} and/or \refcollargs{tags}
+ might also be useful on occasion.
+
+ During advising and advice setup, the \pkg{pgfkeys} and the raw collector
+ options of the advised command are accessible through
+ \docaux{cmd}{AdviceCollectorOptions} and
+ \docaux{cmd}{AdviceRawCollectorOptions}, both a parameterless macro expanding
+ to the given \meta{keylist} and \meta{code}, respectively.
+\end{doc}
+
+\begin{doc}{
+ key={name=clear collector options},
+ key={name=clear raw collector options},
+ }
+ These keys empty the list of user-friendly and raw collector options,
+ respectively.
+\end{doc}
+
+\begin{doc}{
+ key={name=inner handler, par=\meta{\hologo{TeX} code}, long description=0.5,
+ desc=initially and default: see below},
+ }
+
+ This key declares the \meta{\hologo{TeX} code} as the inner handler component
+ of the advice.
+
+ The inner handler is intended to be used in situations which require
+ knowledge of the advised command's arguments as a whole. In such situations,
+ the outer handler will normally invoke the collector, which will in turn
+ execute the inner handler and provide it with a single (braced) argument,
+ containing the collected arguments of the advised command. See
+ \refmmzauto{memoize} for the usage case which inspired this design.
+
+ The simplest example of an inner handler is a (single-parameter) macro which
+ does nothing. Surprisingly enough, such an inner handler could be useful.
+ Defining |\def\Gobble#1{}| and setting
+ \code{\refmmz{auto}=\cs{foo}\bracestt{\refmmzauto{inner handler}=\cs{Gobble},
+ \refmmzauto{args}=\bracestt{...}}} with the argument structure
+ appropriate for |\foo| could be used to eradicate all invocations of |\foo|
+ from the document.
+
+ The inner handler has access to all the macros available to the outer
+ handler, but given that most of them have already fulfilled their function,
+ only the following will likely be useful in the inner handler:
+ \refcmd{AdviceNamespace}, \refcmd{AdviceName}, \refcmd{AdviceReplaced},
+ \refcmd{AdviceOriginal}, and \refcmd{AdviceOptions}.
+
+ Because there is clearly no reasonable default for the inner handler, this key
+ is initially set to an internal control sequence producing an ``undefined
+ inner handler'' error. Note that it is not necessary to define a dummy inner
+ handler when handling is entirely performed by the outer handler, i.e.\ in
+ cases when the inner handler is not invoked. Executing this key without a
+ value restores it to the initial value.
+
+ During advising and advice setup, the inner handler of the advised command is
+ accessible through \docaux{cmd}{AdviceInnerHandler}, a parameterless macro
+ expanding to the given \meta{\hologo{TeX} code}.
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=options,par=\marg{keylist},
+ desc={cumulative, initially empty, value required}},
+ key={name=clear options},
+ }
+
+ The first key appends the given \meta{keylist} to the list of advice options
+ (after prefixing it by a comma), and the second one empties this list. For a
+ \meta{key} undefined in keypath \refkeypath{/mmz/auto},
+ \meta{key}|=|\meta{value} has the same effect as
+ \refmmzauto{options}|=|\bracestt{\meta{key}=\meta{value}}.
+
+ In Memoize, the options set by this key are known as
+ \emph{auto-options} --- options which are applied (using \refcmd{mmzset}) at
+ every invocation of the advised command or environment. For example, the
+ \env{tcolorbox} environment of package \pkg{tcolorbox} is used extensively
+ for typesetting this manual, and I have submitted this environment to
+ automemoization. However, the \env{tcolorbox}es in this manual often include
+ code listings. To memoize such environments successfully, their bodies must
+ be grabbed verbatim. I have therefore submitted the \env{tcolorbox}
+ environment to automemoization like this:
+ \refmmz{auto}|={tcolorbox}|\bracestt{\refmmzauto{memoize},
+ \refmmzauto{options}=\refmmz{verbatim}}; the simpler
+ \refmmz{auto}|={tcolorbox}|\bracestt{\refmmzauto{memoize}, \refmmz{verbatim}}
+ would work as well.
+
+ In general, whether to use the options set by this key, and how, remains at
+ the sole discretion of the advice. Note that they might be used by either
+ the outer or the inner handler, or perhaps even the collector.
+
+ During advising and advice setup, the options of the advised command are
+ accessible through \docaux{cmd}{AdviceOptions}, a parameterless macro expanding
+ to the given \meta{keylist}.
+\end{doc}
+
+\begin{doc}{key={name=reset, desc=style}}
+ Executing this key restores all \refmmz{auto} keys to their initial values.
+
+ Invoking \refmmz{auto} on the same command or environment again
+ \emph{updates} the advice configuration. Use this key to start from scratch.
+\end{doc}
+
+\begin{doc}{key={name=after setup, desc={initially empty, cumulative}}}
+ The code given to this key will be executed after exiting the group opened by
+ \refmmz{auto}. The same effect may be achieved by appending to macro
+ \docaux{cmd}{AdviceAfterSetup}.
+
+ For example, \refmmzauto{integrated driver} uses this key to declare a new
+ conditional.
+\end{doc}
+
+\paragraph{Commands available during the execution of advice}
+
+With the exception of \refcmd{AdviceGetOriginal}, the commands listed below
+only become available in the outer handler, and if that handler does nothing
+funky, they should be available in the collector and the inner handler, as
+well. However, once the advice yields control to foreign code, these macros
+are not guaranteed to hold the expected values anymore, because the foreign
+code might trigger another piece of advice. Consequently, these macros
+should be expanded, once, before integrating them into arbitrary (non-advice)
+code; in particular, this applies to \refcmd{AdviceOriginal}.
+
+\begin{doc}{cmd={name=AdviceNamespace}}
+ This macro holds the \meta{namespace}, i.e.\ the keypath which this instance
+ of the advising framework was installed into.
+\end{doc}
+
+\begin{doc}{cmd={name=AdviceName}}
+ This macro holds the name of the advised command or environment, i.e.\ the
+ name which was used as the first argument to \refmmz{auto}. For a command,
+ this will be a control sequence, e.g.\ |\foo|; for environments (in any
+ \hologo{TeX} format), their name, e.g.\ |foo|.
+\end{doc}
+
+\begin{doc}{cmd={name=AdviceReplaced}}
+ This macro holds the code which was replaced by the outer handler. For
+ commands, this will be the command itself, e.g.\ |\foo|, so
+ \refcmd{AdviceReplaced} will equal \refcmd{AdviceName}. For an environment
+ |foo|, \refcmd{AdviceReplaced} is set to |\begin{foo}| in \hologo{LaTeX},
+ |\foo| in \hologo{plainTeX} and |\startfoo| in \hologo{ConTeXt}.
+\end{doc}
+
+\begin{doc}{cmd={name=AdviceOriginal}}
+ This macro executes the original code of the advised command.
+
+ This macro is defined as \refcmd{AdviceGetOriginal}\marg{namespace}\marg{name},
+ and therefore acts as a shortcut for an explicit invocation of
+ \refcmd{AdviceGetOriginal}. When executing the original command directly from
+ the advice, one may safely write \refcmd{AdviceOriginal}. However, whenever
+ \refcmd{AdviceOriginal} is embedded in code which might contain other advised
+ commands, it should be pre-expanded, exactly once.
+\end{doc}
+
+\begin{doc}{cmd={name=AdviceGetOriginal, par=\marg{namespace}\marg{control sequence}}}
+ This command invokes the original definition of the \meta{control sequence}
+ advised by the \meta{namespace} instantiation of Advice. It may be safely
+ used outside the advice, even if the advised command is not activated.
+
+ For example, upon executing key |/ns/|\refmmz{auto}|=\foo{...}|,
+ |\AdviceGetOriginal{/ns}{\foo}| will recall the original definition of |\foo|
+ if |\foo| is activated, and simply execute |\foo| otherwise.
+
+ The second argument of this command should \emph{not} be an environment name.
+ To execute the original environment |foo| in \hologo{TeX} or
+ \hologo{ConTeXt}, use \refcmd{AdviceGetOriginal} with the appropriate macro:
+ |\AdviceGetOriginal{/ns}{\foo}| or |\AdviceGetOriginal{/ns}{\startfoo}|. In
+ \hologo{LaTeX}, one should use |\AdviceGetOriginal{/ns}{\begin}{foo}|, which
+ executes the original \refcmd{begin} and provides it with the environment name.
+
+ Within the advice, you will probably never have to use this command directly,
+ but will rather rely on the (plain or pre-expanded) \refcmd{AdviceOriginal}.
+ However, outside the advice, this command provides the only means to
+ access the original definition of an advised command. (Unlike the
+ commands described above, this command is available throughout the
+ document.)
+
+ \begin{tcolorbox}[warning]
+ A typo in the invocation of this command may result in an infinite loop.
+ Assume that the advice for |\foo|, declared in namespace \refkeypath{/mmz},
+ executes \refcmd{AdviceGetOriginal}|{/zzm}{\foo}|, which incorrectly refers
+ to the non-existing namespace |/zzm|, and that command |\foo| is activated.
+ Executing |\foo| will eventually execute
+ \refcmd{AdviceGetOriginal}|{/zzm}{\foo}|, which won't find the original
+ definition of |\foo| in the non-existing namespace |/zzm| and will thus
+ execute macro |\foo| (again), which, being advised, will lead to another
+ \refcmd{AdviceGetOriginal}|{/zzm}{\foo}|, etc. My advice is to define an
+ abbreviation like |\def\mmzAdviceGetOriginal{\AdviceGetOriginal{/mmz}}|.
+ And note that the name\-space is a full keypath, which begins with a slash
+ (|/|), but has no slash at the end.
+ \end{tcolorbox}
+\end{doc}
+
+\paragraph{Support for specific packages}
+At the moment, Advice only implements specific support for \TikZ, by defining a
+\refmmzauto{collector} for command \refcmd{tikz}.
+
+\begin{doc}{
+ cmd={name=AdviceCollectTikZArguments},
+ }
+ This command collects the arguments in the format expected by \refcmd{tikz}, and
+ executes macro \refcmd{AdviceInnerHandler} with the collected arguments given
+ as a single braced argument. The collector supports both the group and the
+ semicolor invocation of |\tikz|, i.e.\ both |\tikz{...}| and |\tikz...;|.
+
+ This command is only available upon |\input|ting file
+ \docaux{file}{advice-tikz.code.tex}.
+\end{doc}
+
+\endgroup % keypath = /mmz/auto
+
+\subsubsection{Memoization-related additions to the advising framework}
+\label{sec:ref:advice:memoization}
+
+In section~\ref{sec:ref:advice}, we have seen that Memoize installs the
+advising framework into keypath \refkeypath{/mmz}, with setup key name
+\refmmz{auto}. This populates keypaths \refkeypath{/mmz} and
+\refkeypath{/mmz/auto} with various generic advice keys. However, Memoize
+installs further advice\slash automemoization-related keys into these keypaths.
+It is these keys which are described in this section.\footnote{One such key,
+ \refmmzauto{integrated driver}, is actually documented in
+ section~\ref{sec:ref:memoization}.}
+
+Therefore, in contrast to section~\ref{sec:ref:advice}, \refkeypath{/mmz} and
+\refmmz{auto} have no secret generic meaning here, i.e.\ they should \emph{not}
+be generalized to \meta{namespace} and \meta{setup key} of
+\refkey{/handlers/.install advice}.
+
+\paragraph{Keys residing in \refkeypath{/mmz}}
+
+\begingroup
+\setlength\textfloatsep{20pt plus 2pt minus 4pt}% back to the default
+
+\begin{doc}{easy,
+ key={name=manual, description={preamble-only,{ }}, conditional=false},
+ }
+ When this conditional is set to true, no commands are \refmmz{activate}d at
+ the beginning of the document. The list of commands and environments advised
+ and activated out of the box can be found in Table~\ref{tab:advised-commands}.
+
+ The auto-framework allows the activation to be deferred (see
+ \refmmz{activation} and \refkey{/handlers/.install advice}) but leaves it
+ open to the specific instance of the framework to use the deferred activation
+ commands as it sees fit. Normally, Memoize switches to immediate activation
+ at the end of the preamble (hook \refmmz{begindocument/before}) and issues
+ \refmmz{activate deferred} at the beginning of the document, more precisely
+ in hook \refmmz{begindocument/end} (afterwards, \refmmz{activate deferred} is
+ emptied). However, when \refmmz{manual} is in effect, the deferred
+ activation is suppressed (though it may be still carried out by the user by
+ executing \refmmz{activate deferred}).
+
+ In \hologo{LaTeX}, \refmmz{manual} affects the (internal) activation of
+ \refcmd{begin} as well, which effectively deactivates handling of all environments.
+\end{doc}
+
+\begin{table}
+ \centering
+ \begin{tabularx}{\linewidth}{llX}
+ \toprule
+ command/environment&handler&notes\\
+ \midrule
+ \refcmd{begin}&custom&Only in \hologo{LaTeX}; declared by Advice.\\
+ \refcmd{errmessage}&\refmmzauto{abort}&Not available in \hologo{LuaTeX},
+ where better error-detection is implemented.\\
+ \refenv{forest}&\refmmzauto{memoize}\\
+ \refcmd{Forest}&\refmmzauto{memoize}\\
+ \refcmd{index}&\refmmzauto{replicate}&The argument is expanded prior to replication.\\
+ \refcmd{label}&custom&Globally appends \refcmd{mmzLabel}\marg{label key}\marg{current label}
+ to register \refcmd{mmzCCMemo}; \refmmzauto{run if memoizing}.\\
+ \refcmd{pageref}&\refmmzauto{ref}\\
+ \refcmd[into index=false]{pdfsavepos}&\refmmzauto{abort}&Not available in \hologo{LuaTeX}.\\
+ \refcmd{pgfsys@getposition}&\refmmzauto{abort}&Available only in \TikZ is
+ loaded, it aborts memoization of a picture which gets accidentally marked as
+ ``remembered''.\\
+ \refcmd{ref}&\refmmzauto{ref}\\
+ \refcmd[short]{savepos}&\refmmzauto{abort}&Available only in \hologo{LuaTeX}.\\
+ \refcmd{tikz}&\refmmzauto{memoize}\\
+ \refenv{tikzpicture}&\refmmzauto{memoize}\\
+ \bottomrule
+ \end{tabularx}
+ \caption{Commands advised by Memoize}
+ \label{tab:advised-commands}
+\end{table}
+
+\begin{doc}{easy,
+ key={name=ignore spaces, conditional=false},
+ }
+ Ignore any spaces following \emph{auto}memoized code. This key has no effect
+ for manual memoization, i.e.\ command \refcmd{mmz} and environment
+ \refenv{memoize}.
+
+ It is common practice to conclude the definition of a command by \hologo{TeX}
+ primitive \refcmd{ignorespaces}, which consumes any following spaces, to
+ prevent unintended blank space after the command's invocation. Automemoizing
+ such a command disrupts this behaviour.\footnote{It is clear that
+ \refcmd{ignorespaces} is disrupted during utilization; in this case, the
+ original command, including the concluding \cs{ignorespaces}, is never even
+ executed. However, the disruption also occurs during memoization, and even
+ during regular compilation. In both cases, the memoized code is embedded
+ in some internal Memoize code. Therefore, the original \cs{ignorespaces}
+ does not occur directly in front of the rest of the document.} The
+ workaround is to use this key, normally as an option in the \refmmz{auto}
+ declaration; it will work both for automemoized macros and environments.
+\end{doc}
+
+\paragraph{Keys residing in \refkeypath{/mmz/auto}}
+
+\begingroup
+\yadocset{keypath=/mmz/auto}
+
+\begin{doc}{easy,key={name=memoize, desc=style}}
+ This key sets up advice which triggers memoization of the command or
+ environment whenever it is encountered; we often refer to such a command as
+ ``automemoized,'' or say that it was ``submitted to automemoization.''
+
+ An automemoized command will consume the next-options, whether memoization
+ actually occurs or not.
+
+ Under the hood, this key declares both an \refmmzauto{outer handler} and an
+ \refmmzauto{inner handler}. The outer handler opens the memoization group
+ (so that options can be applied locally), applies the auto-options (given by
+ \refmmzauto{options} within \refmmz{auto}) and the next-options (given by
+ \refcmd{mmznext}) by executing \refmmzauto{apply options}, and appends the
+ verbatim keys to \refmmzauto{collector options} if necessary. The inner
+ handler invokes \refcmd{Memoize} (which closes the group opened by the outer
+ handler): the first argument is \refcmd{AdviceReplaced}, expanded once and
+ followed by the arguments of the handled command; the second argument is
+ \refcmd{AdviceOriginal}, also expanded once and followed by the arguments of
+ the handled command. The inner handler also makes sure that \refmmz{ignore
+ spaces} is respected.
+\end{doc}
+
+\begin{doc}{easy,key={name=nomemoize,desc=style}}
+ This key installs advice which disables memoization for the space of the
+ command or environment; we sometimes refer to such commands as
+ ``autodisabled.''
+
+ This key is merely an abbreviation for \refmmzauto{noop}|,|
+ \refmmzauto{options}|=|\refmmz{disable}. See the documentation of
+ \refmmzauto{noop} for further details.
+\end{doc}
+
+\begin{doc}{key={name=noop,desc=style}}
+ This key sets up advice which does nothing.
+
+ Ok, not nothing at all. The installed handler applies the auto-options and
+ the next-options by executing \refmmzauto{apply options}, and makes sure that
+ \refmmz{verbatim} and \refmmz{ignore spaces} are respected.
+
+ For commands and non-\hologo{LaTeX} environments, this key declares the same
+ outer handler as \refmmzauto{memoize}, while the inner handler merely
+ executes the original command (respecting the potential verbatim mode),
+ closes the group opened by the outer handler, and makes sure that
+ \refmmz{ignore spaces} is respected.
+
+ For \hologo{LaTeX} environments, which open the group necessary for the local
+ application of options themselves, this key declares an outer handler which
+ adds the relevant code into the next hook |env/|\meta{environment
+ name}|/begin|. There is no need to open a group, collect the environment
+ body, or make special provisions for the verbatim mode.
+\end{doc}
+
+
+\begin{doc}{key={name=apply options,desc=style}}
+ This style, used by \refmmzauto{memoize}, \refmmzauto{nomemoize} and
+ \refmmzauto{noop} described above, installs two handlers:
+ \begin{itemize}
+ \item an outer handler which opens a group, applies auto-options and
+ next-options by executing \refcmd{mmzAutoInit}, and executes the collector;
+ and
+ \item a bailout handler which clears the next-options.
+ \end{itemize}
+\end{doc}
+
+
+\begin{doc}{cmd={name=mmzAutoInit}}
+ This macro applies the auto-options and the next-options.
+
+ Additionally, if \refmmz{verbatim}, \refmmz{verb} or \refmmz{no verbatim} was
+ previously executed, this style appends the corresponding CollArgs key
+ (\refcollargs{verbatim}, \refcollargs{verb} or \refcollargs{no
+ verbatim}) to \refcmd{AdviceRawCollectorOptions}. In case several of the
+ verbatim keys were executed, the final one takes effect.
+\end{doc}
+
+
+\begin{doc}{easy, key={name=abort,desc=style}}
+ This key sets up advice which aborts any ongoing memoization.
+
+ Under the hood, the advice merely executes \refcmd{mmzAbort} followed by
+ \refcmd{AdviceOriginal}. The advised command does \emph{not} consume the
+ next-options. Out of the box, we submit two control sequences to this
+ handler:
+ \begin{itemize}
+ \item \refcmd{errmessage}: this allows us to detect and abort upon at least some
+ errors.
+ \item \refcmd[into index=false]{pdfsavepos} (in \hologo{LuaTeX},
+ \refcmd[short]{savepos}): one common effect is that memoization of any
+ \TikZ picture with \refkey{/tikz/remember picture} set is aborted.
+ \end{itemize}
+\end{doc}
+
+
+\begin{doc}{key={name=unmemoizable,desc=style}}
+ This key sets up advice which aborts the ongoing memoization and marks the
+ automemoized code as unmemoizable, so that it will be henceforth compiled
+ regularly.
+
+ Under the hood, the advice merely executes \refcmd{mmzUnmemoizable} followed
+ by \refcmd{AdviceOriginal}. The advised command does \emph{not} consume the
+ next-options.
+
+ Out of the box, we submit no control sequences to this advice, but it might
+ make sense to submit \refcmd[into index=false]{pdfsavepos}\slash
+ \refcmd[short]{savepos}. Keys \refmmzauto{abort}|=|\refcmd[short]{savepos}
+ and \refmmzauto{unmemoizable}|=|\refcmd[short]{savepos} will most often have
+ the same effect, as far as the author is concerned; the former was chosen as
+ the default because it does not produce a c-memo; see
+ \refcmd{mmzUnmemoizable} for a situation where \refmmzauto{unmemoizable} is
+ preferred.
+\end{doc}
+
+
+\begin{doc}{easy,
+ key={name=ref,desc=style},
+ key={name=force ref,desc=style},
+ }
+
+ These keys set up advice which adds the reference key to the context
+ expression. They are intended to be used with cross-referencing commands
+ such as \refcmd{ref} and \refcmd{pageref}.
+
+ Indeed, \refcmd{ref} and \refcmd{pageref} are submitted to this advice by
+ Memoize, with the effect that standard cross-referencing inside memoized code
+ ``just works.'' Note that the stabilization of the document after changing
+ the reference takes three compilation cycles, i.e.\ one cycle more than
+ without memoization.
+
+ The advice set up by \refmmzauto{ref} aborts memoization if the reference
+ key is undefined, the rationale being that the produced memo and extern would
+ most often be useless, and could even obscure an undefined reference. The
+ \refmmzauto{force ref} handler produces the memo and the extern even when the
+ reference is undefined.
+
+ The reference produced by the advised command should be fully expandable
+ (because it will be expanded as a part of the context expression).
+
+ Typically, a \refcmd{ref} command takes a single argument, the reference key.
+ However, some packages may define a reference command which takes optional
+ arguments, as well; in particular, the \pkg{hyperref}'s incarnation of \refcmd{ref}
+ takes an optional star. This advice does not care: it will accept any number
+ of any kind of optional arguments, as long as the reference key is the first
+ braced argument following the advised command; for example, |\ref*{key}|,
+ |\ref[opt]{key}|, |\ref*[opt]{key}| etc.\ will all be handled correctly,
+ while |\ref{mand}{key}| will not work. Effectively, it is as if we had set
+ \refmmzauto{args}|=lm| --- and with the same downside, namely that an
+ unlikely unbraced single-token reference key, like |\ref k|, will not work.
+
+ Under the hood, these two pieces of advice pass the reference key to macros
+ \refcmd{mmzNoRef} and \refcmd{mmzForceNoRef}, and it is these commands ---
+ which may also be used in user-defined advice or the document itself ---
+ which actually add the reference key to the context expression.
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=refrange,desc=style},
+ key={name=force refrange,desc=style},
+ }
+ These keys have the same function as \refmmzauto{ref} and \refmmzauto{force
+ ref}, but they operate on reference-range commands, such as \pkg{cleveref}'s
+ \refcmd{crefrange}, which take two arguments (the starting and the ending reference
+ key).
+\end{doc}
+
+\begin{doc}{easy,
+ key={name=multiref,desc=style},
+ key={name=force multiref,desc=style},
+ }
+ These keys have the same function as \refmmzauto{ref} and \refmmzauto{force
+ ref}, but they operate on ``multireference'' commands, such as
+ \pkg{cleveref}'s \refcmd{cref}, which allow the author to list several
+ comma-separated reference keys in a single argument.
+\end{doc}
+
+\begin{doc}{
+ key={name=replicate, desc=style}
+ }
+ This key sets up advice which replicates the invocation of the command in
+ the cc-memo during memoization.
+
+ When using this key, it is necessary to set \refmmzauto{args} as well. For
+ \refcmd{index}, Memoize executes
+ \refmmz{auto}|=\index|\bracestt{\refmmzauto{args}=m, \refmmzauto{replicate}}.
+
+ This key takes an auto-option, \docAux{keypath=/mmz/auto/replicate,
+ key={name=expanded}}.\footnote{This option is unrelated to Memoize's options,
+ settable by \refcmd{mmzset}.} If given, the collected arguments will be
+ expanded before replicating them in the cc-memo; in \hologo{LaTeX}, this
+ expansion is |\protect|ed.
+
+ In \hologo{LaTeX}, Memoize submits \refcmd{index} to this handler (with
+ expansion). Therefore, any |\index{key}| in the memoized code gets copied
+ into the cc-memo. Effectively, indexing from within the memoized code ``just
+ works.''
+
+ Note that \refcmd{label}, despite essentially requiring replication, cannot
+ use this advice, because it needs to replicate not only the label key but
+ \refcmd{@currentlabel} as well.
+\end{doc}
+
+\begin{doc}{key={name=run if memoization is possible, desc=style}}
+ Under the run conditions installed by this key, a command is only advised if
+ Memoize is enabled but we're not already ``within Memoize,'' i.e.\ memoizing
+ or normally compiling some code submitted to memoization. In code:
+ \refcmd{ifmemoize}\refcmd{ifinmemoize}|\else|\refcmd{AdviceRuntrue}|\fi\fi|.
+
+ Internally, this key is used by \refmmzauto{memoize} and \refmmzauto{noop}.
+\end{doc}
+
+\begin{doc}{key={name=run if memoizing, desc=style}}
+ Under the run conditions installed by this key, a command is only advised
+ during memoization. In code:
+ \refcmd{ifmemoize}\refcmd{ifmemoizing}\refcmd{AdviceRuntrue}|\fi\fi|.
+
+ Internally, this key is used by \refmmzauto{abort}, \refmmzauto{replicate},
+ and \refmmzauto{ref} and friends.
+\end{doc}
+
+\endgroup % keypath = /mmz/auto
+\endgroup
+
+
+
+\subsubsection{Package CollArgs}
+\label{sec:ref:collargs}
+
+\begingroup
+\yadocset{keypath=/collargs}
+
+\begin{doc}{cmd={
+ name=CollectArguments,
+ par=\oarg{options}\marg{argument specification}\marg{next-code}%
+ \textcolor{gray}{\meta{tokens}}}}
+
+ This command determines the extent to which the \meta{tokens} following the
+ the three formal arguments of the command conform to the given \meta{argument
+ specification}, effectively splitting \meta{tokens} into \meta{argument
+ tokens} and the \meta{rest} of the tokens, and then executes
+ \meta{next-code} with the \meta{argument tokens} provided as a single, braced
+ argument:
+ \begin{center}
+ \meta{next-code}\marg{argument tokens}\textcolor{gray}{\meta{rest}}
+ \end{center}
+ If the initial part of \meta{tokens} does not conform to \meta{argument
+ specification}, \refcmd{CollectArguments} throws an error. (In this case,
+ \meta{next-code} is not executed, and the \meta{tokens} collected until the
+ error are thrown away.)
+
+ The optional \meta{options} are processed using the \pkg{pgfkeys} utility of
+ PGF/\TikZ (see \PGFmanual{87}), with the default path set to
+ \docaux{key path}{collargs}. The given options apply to all the arguments in
+ \meta{argument specification}. The recognized keys are listed in the rest of
+ the section.
+
+ The \meta{argument specification} should be given in the \pkg{xparse} format
+ (we summarize this format in the documentation for \refmmzauto{args} in
+ section~\ref{sec:ref:advice}), with several extensions:\footnote{Collargs
+ internally uses a dot (|.|) to delimit the argument specification from the
+ following argument tokens. Therefore, the dot really counts as an extra
+ argument type, in the sense that Collargs will stop working if the dot
+ becomes an argument type or a modifier in some future release of
+ \pkg{xparse}.}
+ \begin{itemize}
+ \item We introduce modifier \docAux{xparse modifier={name=\&,label=amp,index
+ annotation/.prefix={additional\ }, index annotation/.append={\
+ (options)} }} taking a mandatory argument specifying the options to
+ apply to the following argument in the specification. Options given here
+ override the \meta{options} given as the optional argument.
+ \item The environment body type \docAux{xparse type={name=b,index
+ annotation/.append={\ (environment body)}}} may be followed by an optional
+ \emph{braced} argument providing the name of the environment to collect.
+ The name given here overrides the name given by the
+ \refcollargs{environment} option.
+ \item The number of collected ``arguments'' is unlimited.
+ \end{itemize}
+
+ Also note that the effect of \docref{xparse:O}\marg{default} is the same as
+ the effect of \docref{xparse:o}, and similarly for other pairs of types with
+ and without defaults (\docref{xparse:R} and \docref{xparse:r},
+ \docref{xparse:D} and \docref{xparse:d}, and \docref{xparse:E} and
+ \docref{xparse:e}). CollArgs is dedicated to collecting the argument tokens
+ precisely as they are given: if an optional argument is missing, its default
+ value is \emph{not} inserted among the collected arguments --- consequently,
+ \refcmd{CollectArguments} is utterly uninterested in the default value.
+
+ Collection of environments automatically adapts to the format, i.e.\ given
+ environment body name |foo|, \refcmd{CollectArguments} knows to search for
+ \refcmd{begin}\bracestt{foo} |...| \refcmd{end}\bracestt{foo} in
+ \hologo{LaTeX}, \cs{foo} |...| \cs{endfoo} in \hologo{plainTeX}, and
+ \cs{startfoo} |...| \cs{stopfoo} in \hologo{ConTeXt}. For further
+ information on environment collection, see keys \refcollargs{ignore
+ nesting} and \refcollargs{tags}.
+\end{doc}
+
+\begin{doc}{cmd={
+ name=CollectArgumentsRaw,
+ par=\marg{option-setting code}\marg{argument specification}\marg{next-code}%
+ \textcolor{gray}{\meta{tokens}}}}
+
+ This command is the programmer's interface to CollArgs, intended to be used
+ instead of \refcmd{CollectArguments} when compilation speed is an issue. The
+ two commands only differ in how they deal with options.
+
+ One difference is that for \refcmd{CollectArgumentsRaw}, the options form a
+ mandatory rather than an optional argument. More importantly, however, they
+ do not take the form of a keylist, but should be composed out of low-level
+ option-setting commands. Each key documented in this section has a
+ corresponding low-level macro; these macros are listed in footnotes alongside
+ the keys. The name of the macro starts with |\collargs| and continues with
+ the name of the key, without spaces, each word capitalized; if the key is
+ boolean, this convention applies to the base of the \hologo{TeX}
+ conditional. For example,
+ \begin{tcblisting}{listing only, listing options app={escapechar=|}}
+\CollectArguments[caller=\foo, tags, verbatim]|\marg{argument specification}\marg{next-code}|
+ \end{tcblisting}
+ is equivalent to
+ \begin{tcblisting}{listing only, listing options app={escapechar=|}}
+\CollectArgumentsRaw{%
+ \collargsCaller{\foo}%
+ \collargsBeginTagtrue\collargsEndTagtrue
+ \collargsVerbatim
+}|\marg{argument specification}\marg{next-code}|
+ \end{tcblisting}
+
+ Withing the option-setting code, the programmer may also deploy macro
+ \docaux{cmd}{collargsSet}, which processes the \meta{options} in the keylist
+ format. One idea could be to execute this macro at the end of the low-level
+ options; this would set the ``defaults'' using the fast programmer's
+ interface, but still allow for user customization.
+\end{doc}
+
+
+\begin{doc}[
+ pi={\docaux{cmd}{collargsCaller}},
+ ]{
+ key={name=caller, par=\meta{control sequence (name)},
+ desc={no default, initially \cs{CollectArguments}}},
+ }
+ Set the control sequence to refer to in error messages.
+
+ If \meta{tokens} do not match the \meta{argument specification},
+ \refcmd{CollectArguments} throws an error. By default, the error message
+ contains a reference to \refcmd{CollectArguments} itself, for example %
+ |! Argument of \CollectArguments has an extra }.| However, this might not be
+very informative to the author. When \refcollargs{caller}|=\cs| is in effect,
+the error messages will refer to the given |\cs| instead.
+
+If the value of this key is not a control sequence, it is assumed to be an
+environment name, but as the caller must be a macro, this name will be
+converted into a control sequence. Setting \refcollargs{caller}|=foo| will
+result in error messages referencing |\foo| in \hologo{plainTeX}, |\startfoo|
+in \hologo{ConTeXt} and |\begin{foo}| (a single control sequence!) in
+ \hologo{LaTeX}.
+\end{doc}
+
+\begin{doc}[
+ pi=\docaux{cmd}{collargsEnvironment},
+ ]{key={name=environment, par=\meta{environment name},
+ desc={applicable to type \docref{xparse:b}, no default, initially empty}}
+ }
+
+ Set the name of the environment collected by argument type
+ \docref{xparse:b}.
+\end{doc}
+
+\begin{doc}[
+ pi={\docaux{cmd}{ifcollargsBeginTag}, \docaux{cmd}{ifcollargsEndTag};
+ \refcollargs{tags} has no corresponding low-level command}
+ ]{
+ key={name=begin tag, desc={applicable to type \docref{xparse:b},{ }}, conditional=false},
+ key={name=end tag, desc={applicable to type \docref{xparse:b},{ }}, conditional=false},
+ key={name=tags, par=\meta{boolean}, % not a conditional
+ desc={applicable to type \docref{xparse:b}, style, default |true|}},
+ }
+
+ When \refcollargs{begin tag}\slash \refcollargs{end tag} is in effect, the
+ begin\slash end tag will be will be prepended/appended to the collected
+ environment body. Style \refcollargs{tags} is a shortcut for setting
+ \refcollargs{begin tag} and \refcollargs{end tag} simultaneously.
+
+ In \hologo{LaTeX}, using \refcollargs{tags} will thus dress up the
+ collected body in a pair or \refcmd{begin}\marg{environment name} and
+ \refcmd{end}\marg{environment name}. CollArgs will automatically use the tags
+ appropriate to the format.
+
+ In the verbatim modes, the added tags are verbatim as well, with the detail
+ that in \hologo{LaTeX}, there is a slight difference between the full
+ \refcollargs{verbatim} and the partial \refcollargs{verb} mode. In the
+ full verbatim mode, the braces surrounding the environment name are verbatim
+ (the characters used as braces are actually determined by key
+ \refcollargs{braces}). In the partial verbatim, as well as the
+ non-verbatim mode, the environment name is surrounded by a pair of actual
+ braces of category 1 and 2, regardless of which characters are of these
+ categories in the calling code.
+\end{doc}
+
+\begin{doc}[
+ pi=\docaux{cmd}{ifcollargsIgnoreNesting},
+ ]{
+ key={name=ignore nesting, desc={applicable to type \docref{xparse:b},{ }},
+ conditional=false},
+ }
+ When this key is \emph{not} in effect, CollArgs respects the hierarchical
+ structure created by tag pairs such as \refcmd{begin}\bracestt{foo} and
+ \refcmd{end}\bracestt{foo}. Given the situation below on the
+ left, argument type |b{foo}| will collect everything up until the
+ \emph{second} |\end{foo}|. Now this is what we usually want, because
+\hologo{LaTeX} keeps track of environment embedding as well. However, all
+\emph{verbatim} environments I know of, starting with the standard
+\hologo{LaTeX} \refenv{verbatim}, will ignore the nesting and simply scoop up
+everything up to the first \cs{end}|{verbatim}|. In CollArgs, we can replicate
+their behaviour by setting \refcollargs{ignore nesting}, as shown below on the
+right. (Of course we also need to set \refcollargs{verbatim} if we want to
+grab the environment body in the verbatim mode.)
+
+ \begin{tcbraster}[raster columns=2]
+ \begin{tcblisting}{listing only, mark region={1}{5},
+ example title=\texttt{ignore nesting=false}}
+ ...
+ \begin{foo}
+ ...
+ \end{foo}
+ ...
+\end{foo}
+ \end{tcblisting}
+ \ExampleName{_collargs-verbatim}
+ \makeexample{\examplename.tex.c1}
+ \tcbinputexample{listing only, no attachment, mark region={1}{3},
+ example title=\texttt{ignore nesting=true}}
+ \end{tcbraster}
+
+ This key applies not only to argument type \docref{xparse:b} (in either
+ normal or verbatim mode), but also to the verbatim argument type
+ \docref{xparse:v} and to argument types \docref{xparse:m} and
+ \docref{xparse:g} in the \refcollargs{verbatim} (but not normal, or
+ \refcollargs{verb}) mode. With these keys, the relevant structure markers
+ are braces, |{| and |}|.
+\end{doc}
+
+\begin{doc}[
+ pi=\docaux{cmd}{ifcollargsIgnoreOtherTags},
+ ]{
+ key={name=ignore other tags, desc={applicable to type \docref{xparse:b},{ }},
+ conditional=false},
+ }
+ In \hologo{LaTeX}, the environment tags, \refcmd{begin}\marg{name} and
+ \refcmd{end}\marg{name}, contain braces, which retain their usual category codes
+ in the non-verbatim and in the partial verbatim mode. Consequently, CollArgs
+ cannot easily search for the full tags to delimit the
+ environment.
+
+ When this key is \emph{not} in effect, CollArgs takes the easy path, and
+ determines the end of the environment only by inspection of \cs{begin}s and
+ \cs{end}s, without reference to what \meta{name} they begin or end. Only
+ when this key \emph{is} in effect does CollArgs inspect these \meta{name}s,
+ effectively ignoring any \cs{begin}s and \cs{end}s not followed by the name of
+ environment being collected. The effect of absence vs.\ presence of this key
+ is shown below, where the shaded area marks the code collected into
+ environment |foo|.
+
+ \begin{tcbraster}
+ \ExampleName{_collargs-ignore-other-tags}
+ \makeexample{\examplename.tex.c1 N=2}
+ \tcbinputexample{listing only, no attachment, mark region={3}{3},
+ example title=\texttt{ignore other tags=false}}
+ \tcbinputexample[.tex][.c2]{listing only, no attachment, mark region={3}{5},
+ example title=\texttt{ignore other tags=true}}
+ \end{tcbraster}
+
+ This key does not have any effect the full verbatim mode, which always
+ behaves as if this key was set to true, because braces are of category
+ ``other'' as well. Similarly, it is as if this key was always true in
+ \hologo{plainTeX} and \hologo{ConTeXt}, simply because environment tags in
+ these formats don't contain braces.
+\end{doc}
+
+\begin{doc}[
+ pi={\raggedright
+ \docaux{cmd}{collargsAppendPreprocessor},
+ \docaux{cmd}{collargsPrependPreprocessor},
+ \docaux{cmd}{collargsAppendPostprocessor},
+ \docaux{cmd}{collargsPrependPostprocessor}},
+ ]{
+ key={name=append preprocessor, par=\meta{code}, desc={no default}},
+ key={name=prepend preprocessor, par=\meta{code}, desc={no default}},
+ key={name=append postprocessor, par=\meta{code}, desc={no default}},
+ key={name=prepend postprocessor, par=\meta{code}, desc={no default}},
+ }
+ These keys declare processors which will transform the collected argument
+ before appending it to the argument list.
+
+ A collected argument undergoes the following transformations:
+ \begin{itemize}
+ \item First, the argument is processed by any \emph{pre}processors, in the
+ order indicated by |append| and |prepend|.
+ \item Next, the processed argument is dressed up in the delimiters according
+ to its type. For example, an optional argument of type \docref{xparse:o}
+ will be surrounded by square brackets.
+ \item Finally, the delimited argument is processed by any
+ \emph{post}processors, again in the order indicated by |append| and
+ |prepend|.
+ \end{itemize}
+
+ \meta{code} will typically consist of a single control sequence pointing to a
+ one-argument macro, which will receive the collected argument (possibly
+ modified by the processors already applied). In general, however, the value
+ of this key may be any code; Collargs will execute \meta{code}\marg{collected
+ argument}.
+
+ The processed argument should be returned by storing it into token register
+ \docaux{cmd}{collargsArg}.
+
+ The following example illustrates how one could go about reimplementing Bruno
+ Le Floch ingenious package \pkg{cprotect}.\footnote{This example is merely a
+ proof of concept. For the bells and whistles which would make it useful in
+ real life, see the documentation of \pkg{cprotect}.} We define processor
+ |\writetofile| which dumps the argument into a file, replacing it with the
+ |\input| statement. (Of course, to allow for verbatim content in the
+ footnote, we also have to mark the argument as \refcollargs{verbatim}.
+ And we use \refcollargs{no delimiters} to get rid of the braces around the
+ footnote text.)
+
+ \ExampleName{collargs-processor}
+ \makeexample{\examplename.tex.c1}
+ \tcbinputexample{listing and text, listing file=\examplepath.tex.c1}
+\end{doc}
+
+\begin{doc}[
+ pi={\docaux{cmd}{collargsClearPreprocessors},
+ \docaux{cmd}{collargsClearPostprocessors}},
+ ]{
+ key={name=clear preprocessors},
+ key={name=clear postprocessors},
+ }
+ Clear the list of pre- or post-processors.
+\end{doc}
+
+\begin{doc}[
+ pi={\docaux{cmd}{collargsAppendExpandablePreprocessor},
+ \docaux{cmd}{collargsPrependExpandablePreprocessor},
+ \docaux{cmd}{collargsAppendExpandablePostprocessor},
+ \docaux{cmd}{collargsPrependExpandablePostprocessor}
+ },
+ ]{
+ key={name=append expandable preprocessor, par=\meta{code}, desc={no default}},
+ key={name=prepend expandable preprocessor, par=\meta{code}, desc={no default}},
+ key={name=append expandable postprocessor, par=\meta{code}, desc={no default}},
+ key={name=prepend expandable postprocessor, par=\meta{code}, desc={no default}},
+ }
+ These keys may be used to add fully expandable processors. A processor added
+ with one of these keys will end up among the processors declared by
+ \refcollargs{append preprocessor} et al.
+
+ A processor declared by one of these keys will define the processed argument
+ as the full expansion (|\edef|) of \meta{code}\marg{collected argument}.
+ \meta{code} will typically consist of a single control sequence pointing to a
+ fully expandable one-argument macro.
+
+ For example, |\trim@spaces@noexp| from package \pkg{trimspaces} could be used
+ as an expandable processor of environment body to remove the spaces around
+ the grabbed environment body.
+\end{doc}
+
+\begin{doc}[
+ pi={\docaux{cmd}{collargsAppendPrewrap},
+ \docaux{cmd}{collargsPrependPrewrap},
+ \docaux{cmd}{collargsAppendPostwrap},
+ \docaux{cmd}{collargsPrependPostwrap}},
+ ]{
+ key={name=append prewrap, par=\meta{macro definition}, desc={no default}},
+ key={name=prepend prewrap, par=\meta{macro definition}, desc={no default}},
+ key={name=append postwrap, par=\meta{macro definition}, desc={no default}},
+ key={name=prepend postwrap, par=\meta{macro definition}, desc={no default}},
+ }
+ These keys add processors which transform the collected argument in a single
+ expansion.
+
+ The declared processor will use \meta{macro definition} to define a temporary
+ one-argument \meta{macro}, and then set the \meta{processed argument} to be
+ the single expansion of \meta{macro}\marg{collected argument}.
+
+ For example, to add quotes around the collected argument, write
+ \refcollargs{append prewrap}|={``#1''}| (doubling the hash when executing
+ \refcmd{CollectArguments} from a macro, of course). Or, perhaps more
+ usefully, \refcollargs{append prewrap}|={\scantokens{#1}}| can be used to
+ retokenize a verbatim argument (during the execution of the
+ \meta{next-code}).
+\end{doc}
+
+
+\begin{doc}[
+ pi=\docaux{cmd}{ifcollargsNoDelimiters}
+ ]{
+ key={name=no delimiters, conditional=false},
+ }
+ When this key is in effect, the collected argument will not be dressed up
+ into delimiters that it was dressed up in \meta{argument tokens}. For
+ example, an optional argument, encountered as [\meta{argument}] inside
+ \meta{argument tokens}, will be spit out simply as \meta{argument}.
+
+ Any user-specified pre- or post-processing will still be applied.
+ \ExampleName{collargs-nodelimiters}
+ \makeexample{\examplename.tex.c1}
+ \tcbinputexample{comment=\input{\examplepath.tex.c1}}
+\end{doc}
+
+
+\begin{doc}[
+ pi={\docaux{cmd}{collargsVerbatim},
+ \docaux{cmd}{collargsVerb},
+ \docaux{cmd}{collargsNoVerbatim}.
+ To ensure the same effect as with the keys,
+ place these macros at the end of the option code},
+ ]{
+ key={name=verbatim, desc=style},
+ key={name=verb, desc=style},
+ key={name=no verbatim, desc=style},
+ }
+ Select the full verbatim, the partial verbatim, or the non-verbatim mode of
+ argument collection.
+
+ In the full \refcollargs{verbatim} mode, the arguments are collected under
+ a category code regime in which all characters are of category 12, ``other''.
+ The same goes for the partial \refcollargs{verb} mode, except that in this
+ case, the grouping characters --- usually the braces |{| and |}| --- retain
+ their usual category codes 1 and 2. Key \refcollargs{no verbatim} selects
+ the normal, non-verbatim mode.
+
+ The partial \refcollargs{verb} mode can be useful for verbatim collection
+ of an optional argument. To pass |]| as an optional argument to command
+|\foo|, we normally enclose it in braces: ˇ\foo[{~]~}]ˇ. However, if we try to
+collect |[{]}]| with \refcmd{CollectArguments}|[|\refmmz{verbatim}|]{o}|, we
+will get |{| (and most likely an error, as well), because in the
+ \refmmz{verbatim} mode, braces do not have their grouping function. Using
+ the \refmmz{verb} mode solves the problem: occuring within braces, the first
+ |]| is ``invisible'' to \refcmd{CollectArguments}|[|\refmmz{verb}|]|, so the
+optional argument is correctly recognized as ending at the second |]|.
+
+The partial \refcollargs{verb} mode is also useful for collecting the bodies
+of \emph{\hologo{LaTeX}} environments. The full \refcollargs{verbatim} mode
+will only correctly collect these bodies when the relevant \refcmd{begin}
+and\slash or \refcmd{end} control sequences are followed by the grouped
+environment name without any intervening spaces. The partial
+\refcollargs{verb} mode has no such restriction.
+
+In the verbatim modes, modifier \docref{xparse:+} has no effect. The arguments
+are always collected as if they were long.
+
+To correctly collect arguments in the verbatim modes, CollArgs has to mimic the
+many details of \hologo{TeX}'s tokenization and argument delineation. These
+details depend on the category code regime, and CollArgs automatically adapts
+to the ``outside'' category code regime, i.e.\ the regime in effect at the time
+of invoking \refcmd{CollectArguments}. In particular, CollArgs remembers which
+characters were of category codes 0, 1, 2, 5, 10 and 11, and adapts the
+argument collection accordingly. For example, it will correctly pick up a
+control sequence as a single-token \docref{xparse:m}-type (\hologo{TeX}'s undelimited)
+argument even when it begins with a non-standard character of category code 0.
+The single caveat is that only a single pair of characters can function as the
+grouping characters in the full verbatim mode; to compensate for the
+deficiency, this character pair is customizable via key
+\refcollargs{braces}.
+\end{doc}
+
+\begin{doc}[
+ pi={\docaux{cmd}{collargsFixFromVerbatim},
+ \docaux{cmd}{collargsFixFromVerb},
+ \docaux{cmd}{collargsFixFromNoVerbatim}},
+ ]{
+ key={name=fix from verbatim, desc=style},
+ key={name=fix from verb, desc=style},
+ key={name=fix from no verbatim, desc=style},
+ }
+ Key \refcollargs{fix from no verbatim} should be used when the first
+ argument should be collected in a verbatim mode, but the outside code has
+ already tokenized the first character of the subsequent input stream (most
+ probably by a |\futurelet|) in the non-verbatim category code regime. Using
+ this key will trigger a CollArgs' ``mode transition'' (described below) which
+ will fix the situation. (This key is used in the implementation of
+ \refcmd{mmz}.)
+
+ The other two keys should be used in the unlikely reverse situation, where
+ the outside code has tokenized the following character in a verb(atim) mode,
+ while CollArgs is requested to collect the first argument in the non-verbatim
+ mode.
+\end{doc}
+
+\begin{doc}[
+ pi=\docaux{cmd}{collargsBraces}
+ ]{
+ key={name=braces, par={\meta{begin-group char}\meta{end-group char}},
+ desc={no default, for details see below}},
+ }% here
+ This key sets the verbatim begin-group and end-group characters. The setting
+ affects collection of argument types \docref{xparse:m}, \docref{xparse:g},
+ \docref{xparse:v}, \docref{xparse:l}, \docref{xparse:e} and (in
+ \hologo{LaTeX}) \docref{xparse:b} in the \emph{full} verbatim
+ mode.\footnote{The choice of the verbatim grouping characters also affects
+ the effect of \refcollargs{begin tag} and\slash or \refcollargs{end tag};
+ see the documentation of these keys for details.}
+
+ For example, in the non-verbatim and the partial verbatim mode, an
+ \docref{xparse:m}-type argument may be delimited by any characters of
+ category code 1 (``begin-group'') and 2 (``end-group''). In the full
+ verbatim mode, there are of course no characters of these categories, so
+ CollArgs internally assigns the grouping function to some pair of characters.
+ When entering the full verbatim mode, CollArgs automatically sets the
+ verbatim grouping characters to characters which were of categories 1 and 2
+ in the ``outside'' category code regime, i.e.\ the regime in effect at the
+ time of invoking \refcmd{CollectArguments}. However, in contrast to
+ \hologo{TeX}'s internal argument parser, only one pair of characters may
+ serve as the begin-group and the end-group character in CollArgs' full
+ verbatim mode. In case multiple characters were of category 1 or 2 on the
+ outside, CollArgs therefore has to make a choice, and it chooses the
+ candidate with the lowest character code. This choice may be overridden by
+ the user by invoking key \refcollargs{braces}; the user may even choose
+ characters which did not belong to categories 1 and 2 in the outside regime.
+
+ When \meta{begin-group char} and \meta{end-group char} are of categories 1
+ and 2 in the outside category regime, they must be enclosed in a triple
+ group. For example, if both |()| and |{}| have the grouping function on the
+ outside, and the user wants to select |{}| as the verbatim grouping
+ characters (CollArgs would go for |()|, as this pair has lower character
+ codes), the correct way to invoke this key is |braces={{{{}}}}| or
+ |braces=((({})))|. \footnote{This complication is due to the details of
+ \pkg{pgfkeys}' keylist processing, and does not apply to
+ \refcmd{collargsBraces}.}
+\end{doc}
+
+\begin{doc}[
+ pi=\docaux{cmd}{collargsVerbatimRanges}
+ ]{
+ key={name=verbatim ranges,
+ par={\bracestt{\meta{from}\texttt{-}\meta{to}(\texttt{,} \meta{from}\texttt{-}\meta{to})*}},
+ desc={no default, initially \texttt{0-255}}},
+ }
+ If run under the \hologo{pdfTeX} or \hologo{XeTeX} engine, this key
+ determines which characters will be assigned category code 12 in the verbatim
+ mode. In \hologo{pdfTeX}, the range should remain at the initial |0-255|,
+ but in \hologo{XeTeX}, some rare situations might require extending this
+ range (don't attempt to set the full range of |0-1114111|, as this would be
+ very slow and you would most likely run out of save stack).
+
+ In \hologo{LuaTeX}, we switch the category code regime using category code
+ tables, so this key has another meaning: it determines the range in which
+ CollArgs will scan for characters of category codes 1, 2 and 14, whose
+ identity it needs to know, for internal reasons.
+\end{doc}
+
+
+
+\paragraph{Mode transition limitations}
+
+\refcmd{CollectArguments} has some minor limitations regarding the transition
+from a verbatim into non-verbatim mode, or vice versa. The gist of the issue
+is best illustrated with the optional argument type \docref{xparse:o} collected
+in the verbatim mode. CollArgs determines whether an argument of this type is
+present by peeking ahead (using \hologo{TeX}'s |\futurelet| primitive) into the
+input stream. If the argument is present (i.e.\ if the input stream continues
+with an open bracket, |[|%]
+), all is well. But when the optional argument is absent, the peek-ahead will
+tokenize the following character, which presents a problem when no more
+arguments are present in the input stream, like in the example below, where the
+verbatim \docref{xparse:o} is the (only and) final type in the argument
+specification. In this case, the peek-ahead ``incorrectly'' assigns category
+code 12 (``other'') to the first |$|. %$
+This character was intended to be tokenized as the math shift character of
+category 3, to start the math mode after \refcmd{CollectArguments} is finished,
+but having been assigned category code 12, it cannot perform this function,
+resulting in error |! Missing $ inserted| %$
+once \hologo{TeX} encounters the superscript character |^|.
+
+\ExampleName{collargs-transition-ok}
+\makeexample{\examplename.tex.c1}
+\tcbinputexample{sidebyside, lefthand ratio=0.6,
+ comment=\input{\examplepath.tex.c1}}
+
+Well --- this is what \emph{would} happen if CollArgs didn't address the
+transition issue described above. In fact, the above example compiles just
+fine, because CollArgs \emph{does} address this issue, but unfortunately,
+certain transition problems simply cannot be resolved --- read on to learn what
+can go wrong.
+
+For example, you can typeset the name of the document author via
+\hologo{LaTeX}'s internal command |\@author|, but to use this command in the
+document, you have to precede it by |\makeatletter|. As shown by the first
+line of the example below, this works rather nicely: |\makeatletter| sets the
+category code of |@| to 11 (``letter''), so |@| may help form the control word
+|\@author| --- importantly, |\makeatletter| sets the category code of |@|
+\emph{before} control sequence |\@author| is constructed, even if it precedes
+it immediately.
+
+\ExampleName{collargs-transition-cs}
+\makeexample{\examplename.tex.c1}
+\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''}
+\tcbinputexample{comment=\input{\examplepath.tex.c1}}
+
+In the second line of the example, our clever invocation of |\@author| is
+immediately preceded by a call to \refcmd{CollectArguments}, which tries to
+collect a verbatim argument of type \docref{xparse:o}. It doesn't find it, which results in
+the wrong, verbatim tokenization of the escape character of |\makeletter|.
+CollArgs realizes the problem and tries to fix it. But while it is searching
+for the end of control sequence |\makeletter| (which it successfully
+constructs), it triggers the tokenization of what follows --- which, as |@| is
+at that point of category 12 (``other''), yields the control symbol |\@| (later
+followed by word ``author'', typeset in the example).
+
+In short, the solution has created another, delayed instance of the problem ---
+an instance which cannot be addressed any further. But we're nevertheless
+better off, as this particular issue will bite only in the case when the
+``corrupted'' control sequence immediately following the invocation
+\refcmd{CollectArguments} changes category codes in a way that affects the
+tokenization of what immediately follows it.
+
+This was an example of what can go wrong in the transition from the
+\meta{argument tokens} to the \meta{rest} of the tokens following an invocation
+of \refcmd{CollectArguments}. As the ``outside world'' is non-verbatim, this
+transition can only be problematic if the argument which corrupted the first of
+the \meta{rest} tokens was verbatim, so if the transition was from the verbatim
+to the non-verbatim mode. Such a transition can also occur within the
+\meta{argument tokens}, but the good news here is that CollArgs successfully
+solves any problems that occur there, so you should only worry about the
+end-of-arguments situation.
+
+The other direction of the transition, from the non-verbatim to the verbatim
+mode, however, can affect both the internal and the external transitions. Let
+us illustrate the problem with the internal transition. Say you want to
+collect an optional argument (\docref{xparse:o}) in the non-verbatim mode, and
+then a mandatory argument (\docref{xparse:m}) in (either full or partial)
+verbatim mode. In the first invocation of \refcmd{CollectArguments} below, the
+optional argument is present, and we get what we expect: the percent sign is
+collected, verbatim, into the mandatory argument. In the second invocation,
+however, the percent character retains its usual commenting function ---
+despite the fact that we have requested verbatim mode for the mandatory
+argument --- which results in the group in the second line being picked up as
+the mandatory argument. Again, this happens because CollArgs has to peek ahead
+in the input stream when determining whether the optional argument is present.
+Having requested non-verbatim mode for the optional argument, the peeking is
+performed in the non-verbatim mode, and as the optional argument is not
+present, it finds the comment character, which fulfills its regular function of
+disappearing along with the rest of the line. Once CollArgs sets to find the
+(verbatim) mandatory argument, the rest of the line is already gone, so it
+searches for, and finds, this argument in the next line.
+
+\ExampleName{collargs-transition-comment}
+\makeexample{\examplename.tex.c1}
+\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''}
+\tcbinputexample{listing and text}
+
+Nothing can be done here --- commenting deletes information, irrevocably ---
+and in a similar fashion, nothing can be done to catch a verbatim end-of-line
+character when preceded by an absent optional argument in the non-verbatim mode
+(because it was already tokenized into a space token).
+
+Finally, the transition issues are not limited to transits from argument type
+\docref{xparse:o}. The full list of argument types which give rise to
+transition problems (when transiting \emph{from} arguments of these types) is
+as follows: \docref{xparse:o}, \docref{xparse:d}, \docref{xparse:s},
+\docref{xparse:t}, \docref{xparse:g}, \docref{xparse:e}.
+
+
+\endgroup % /collargs
+
+
+\section{Varia}
+
+\subsectionclearpagefalse
+
+\subsection{Known issues}
+\label{sec:known-issues}
+
+\paragraph*{Bitmap graphics export} is coming up in the next release of the
+package.
+
+
+\paragraph{Disappearing errors}
+If a non-fatal internal \hologo{TeX} error occurs during memoization, the memos
+and externs may be nevertheless produced and utilized in subsequent
+compilations. In such a case, the erroneous code won't be compiled again, and
+therefore won't yield any errors, giving the mistaken impression that the code
+is error-free.
+
+This problem does not apply to errors which trigger \refcmd{errmessage},
+because that control sequence is advised by \refmmzauto{abort}.
+Note that internal \hologo{TeX} errors like |Undefined control sequence| are
+\emph{not} reported through \refcmd{errmessage}, and will therefore cause the
+issue.
+
+This problem does not affect \hologo{LuaTeX}, because this engine allows
+Memoize to detect errors and abort memoization if it encounters any.
+
+
+\paragraph{A minimal issue with \hologo{XeLaTeX}}
+If the very first page of a document of class |minimal|, compiled by
+\hologo{XeLaTeX}, happens to be an extern page, we have a problem: all the
+regular pages of the document will be of the same size as that extern page.
+\hologo{pdfLaTeX} and \hologo{LuaLaTeX} do not exhibit this behaviour, nor do
+\hologo{LaTeX} classes other than |minimal|, even when compiled with
+\hologo{XeLaTeX}.
+
+
+\paragraph{CollArgs}
+
+Due to an unfortunate design decision, CollArgs does not accept a dot |.| as
+the \meta{token} argument of types, \docref{xparse:r}, \docref{xparse:R},
+\docref{xparse:d}, \docref{xparse:D}, and \docref{xparse:t}. Furthermore,
+\refcollargs{append prewrap} and friends (and their macro counterparts) do not
+accept a parameter symbol consistently. These issues will be fixed in the next
+release.
+
+
+\subsection{Troubleshooting}
+\label{sec:troubleshooting}
+
+\paragraph{Extern extraction does not work}
+\label{sec:fadings-problem}
+\label{sec:loading-order}
+
+If the internal extern extraction does not work, you should have gotten one of
+the following warnings:
+\begin{enumerate}
+\item \code{Package memoize Warning: Extraction of externs from document
+ "\meta{jobname}.pdf" using method "perl" was unsuccessful. Have you set the
+ shell escape mode as suggested in chapter 1 of the manual?}
+
+ This warning is thrown when the extraction log \meta{jobname}|.mmz.log|,
+ which should be produced by the extraction script, is incomplete, i.e.\ it
+ does not finish by |\endinput|.\footnote{The extraction log will never be
+ absent, because Memoize clears it before executing the extraction script
+ --- and clearing it creates it if it doesn't exist.} The most likely
+ reason is that the script was not executed at all, so the question asked in
+ the warning message is pertinent. However, if all is well with the
+ shell-mode, you have a mystery at your hands. To gather information, I
+ suggest inspecting:
+ \begin{itemize}
+ \item \meta{jobname}|.log| --- search for \code{runsystem(memoize-extract.pl
+ ...)}, it will tell you whether the script was executed;
+ \item the terminal output --- if the script was executed, it should've
+ announced itself by \code{Extracting externs from \meta{jobname}.pdf}; are
+ there any further messages between this header and the warning message?
+ \item \meta{the path to the extern}|.log|, if you are using the
+ \hologo{TeX}-based extraction (\code{\refmmz{extract}=\refmmz{extract=tex}}).
+ \end{itemize}
+ \hologo{TeX}-based extraction will yield this error even in the case of a
+ missing or corrupted PDF, i.e.\ in
+ case~\ref{item:warning:extract:cannot-read} below.
+
+\item\label{item:warning:extract:cannot-read}
+ \code{Package memoize (perl-based extraction) Warning: Cannot read file
+ "\meta{jobname}.pdf". Perhaps you have to load Memoize earlier in the
+ preamble?}
+
+ Embedded extern extraction requires an intact document PDF from the previous
+ compilation, so Memoize must be loaded before the document PDF is opened for
+ writing the results of the ongoing compilation. In particular, the PDF is
+ opened by \PGF library |fadings|, included by \TikZ's libraries |fadings|
+ and |shadows|, so Memoize must be loaded before any of these libraries.
+
+ With \pkg{beamer}, the problem is particularly acute because the PDF is
+ opened while loading the class. In this case, simply moving
+ |\usepackage{memoize}| up the preamble, as suggested, won't help: you have to
+ write |\RequirePackage{memoize}| \emph{before} |\documentclass{beamer}|!
+
+\item\label{item:warning:extract:unexpected-size} \code{Package memoize
+ (perl-based extraction) Warning: I refuse to extract page $n$ from
+ "\meta{jobname}.pdf", because its size ($\meta{width}\times\meta{height}$)
+ is not what I expected\\ ($\meta{expected width}\times\meta{expected
+ height}$)}
+
+ If the compilation which produced the offending extern pages yielded any
+ errors, you should probably disregard this warning, fix the errors, and
+ compile again. Otherwise, you have somehow winded up with mismatched
+ \meta{jobname}|.pdf| and \meta{jobname}\dmmz (the latter file contains
+ instructions on which pages to extract, complete with the expected
+ dimensions). Are you sure that they were produced by the same compilation,
+ and have remained untouched since? Are you perhaps trying to perform the
+ extraction the second time, after the first extraction
+ \refscript{memoize-extract.pl--prune}d the PDF?
+
+ If the warning stubbornly persists, but you are sure that the page the script
+ is refusing to extract is correct, you can force the extraction by adding
+ option \refscript{memoize-extract.pl--force} to the script invocation, which
+ can be set by \refmmz{perl extraction options}. However, as such a situation
+ probably indicates a bug in Memoize, please let me know about it.
+\item\code{\myfontexpansionon Invalid dictionary key at
+ /.../perl5/site\_perl/PDF/API2/Basic/PDF/File.pm line $N$\myfontexpansionoff}
+
+ This can sometimes happen when extracting with the Perl-based script. The
+ issue might be related to PDF version --- by default, \hologo{TeX} produces
+ PDFs of version 1.5, while the PDF library
+ \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} officially only
+ supports versions up to 1.4 --- but I'm afraid I haven't identified the exact
+ circumstances yet. Possibly, the externalizing a picture containing an
+ embedded PDF file might be the culprit. The workaround is to use Python- or
+ \hologo{TeX}-based extraction, i.e.\ load Memoize with package option
+ \refmmz{extract}|=|\refmmz{extract=python} or
+ \refmmz{extract}|=|\refmmz{extract=tex}.
+\end{enumerate}
+
+The failure to extract externs intentionally doesn't result in an error,
+because what if you deleted the document PDF on purpose? At any rate, the
+compilation will succeed, it's just that as Memoize cannot extract the externs,
+they will be produced, and dumped into your document, at each and every
+compilation.
+
+\paragraph{An extern won't be included}
+
+Did you receive a warning or error message?
+\begin{enumerate}
+\item \code{Package memoize Warning: Unexpected size of extern "\meta{extern
+ path}.pdf"; expected\\ $\meta{expected width}\times\meta{expected
+ height}$, got $\meta{width}\times\meta{height}$}
+
+ This warning is related to warning~\ref{item:warning:extract:unexpected-size}
+ above, only that it occurs once the extern is extracted. The same
+ investigative methods apply.
+\item \code{!pdfTeX error: pdflatex (file \meta{extern path}.pdf): reading
+ image file failed}
+
+ This is a fatal error. The extern file got corrupted, somehow ---
+ inexistent, or even empty, extern files merely trigger recompilation.
+\end{enumerate}
+
+If there was no warning or error --- are you certain that Memoize is
+\refmmz{enable}d, and that it is not in the \refmmz{recompile} mode? Remember
+that these settings can also apply only to a part of the document; search for
+any stray \refcmd{mmzset} or \refcmd{mmznext} commands.
+
+
+\paragraph*{Warnings about duplicate labels, indices, etc.} may be safely
+disregarded.
+
+Externalization causes any (non-immediate) |\write| commands in the extern to
+be executed twice, once upon the shipout of the regular page, and once upon the
+shipout of the extern page. This results in warnings about doubly defined
+labels, hyperreferences, indices, etc. For example, you might get
+\texttt{LaTeX Warning: Label `<name>' multiply defined} or \texttt{warning (pdf
+ backend): ignoring duplicate destination with the name '<name>'}. You can
+safely disregard these warnings; they will disappear once the extern is
+utilized.
+
+
+\paragraph{Memoization was aborted}
+
+This warning means that either:
+\begin{itemize}
+\item you are trying to (auto)memoize a \refenv{tikzpicture} with
+ \refkey{/tikz/remember picture} set, or more generally, some code which
+ contains \refcmd{savepos} --- this can't be done, see
+ section~\ref{sec:tut:good-to-know}; or
+\item an error occurred during memoization --- in this case, Memoize cowardly
+ refuses to proceed with memoization, see section~\ref{sec:known-issues} for
+ details.
+\end{itemize}
+
+
+\subsection{License}
+
+Copyright \textcopyright\ 2020- Sašo Živanović.
+
+This work may be distributed and/or modified under the conditions of the
+\hologo{LaTeX} Project Public License, either version 1.3c of this license or
+(at your option) any later version. The latest version of this license is
+in \url{https://www.latex-project.org/lppl.txt} and version 1.3 or later is
+part of all distributions of \hologo{LaTeX} version 2008 or later.
+
+This work comprises of the sources, generated files, accompanying scripts,
+auxiliary files and scripts, documentation, documentation sources, examples and
+example sources of packages |memoize|, |nomemoize|, |memoizable|, |auto| and
+|collargs|. The files belonging to this work and covered by LPPL are listed in
+\meta{texmf}|/doc/generic/memoize/FILES|.
+
+This work has the LPPL maintenance status `maintained.' The Current Maintainer
+of this work is Sašo Živanović. The work is available on CTAN
+at \url{https://ctan.org/pkg/memoize} and on GitHub
+at \url{https://github.com/sasozivanovic/memoize}.
+
+
+\subsection{Changelog}
+
+\newcommand\githubrelease[2]{%
+ \href{https://github.com/sasozivanovic/memoize/releases/tag/#2}{#1 #2}%
+}
+\begin{description}
+\item[\githubrelease{2020/07/17}{v0.1}]
+ The proof-of-concept, available only at GitHub.
+\item[\githubrelease{2023/10/10}{v1.0.0}]
+ A complete, fully documented reimplementation.
+\end{description}
+
+\subsection{Acknowledgments}
+
+First and foremost, my gratitude goes to Stefan Müller of Language Science
+Press for his encouragement and patience --- without him, this package might've
+remained an idea forever!
+
+But there were others as well. Shunsaku Hirata of the \hologo{XeTeX} team
+promptly resolved an issue with forward references in |xdvipdfmx|, and thereby
+made Memoize work with \hologo{XeTeX}. Joseph Wright kindly didn't object to
+me misappropriating \pkg{etoolbox} for other formats. Petra Rübe-Pugliese
+(CTAN) and Karl Berry (\hologo{TeX}Live) offered good advice on packaging the
+package; I would never get to call Advice Advice without their advice. Karl
+also performed a security review of the extraction scripts, providing some very
+useful comments along the way, and agreed to include the scripts among the
+shell escape commands allowed in \hologo{TeX}Live.
+
+Thank you all!
+
+
+\printindex
+
+\end{document}
+
+
+% Local Variables:
+% TeX-engine: luatex
+% TeX-master: t
+% End:
diff --git a/macros/generic/memoize/doc/yadoc.sty b/macros/generic/memoize/doc/yadoc.sty
new file mode 100644
index 0000000000..c069b11f55
--- /dev/null
+++ b/macros/generic/memoize/doc/yadoc.sty
@@ -0,0 +1,491 @@
+%% yadoc.sty
+%%
+%% This file is a part of Memoize, a TeX package for externalization of
+%% graphics and memoization of compilation results in general, available at
+%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+%%
+%% Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/memoize/)FILES.
+
+\RequirePackage{tcolorbox}
+%\tcbuselibrary{listings,documentation,xparse,raster,hooks,breakable}
+\tcbuselibrary{raster,skins}
+
+\RequirePackage{etoolbox}
+
+\newif\ifyadoc@into@index
+\newif\ifyadoc@index@gather
+\newif\ifyadoc@index@colorize@names
+\newif\ifyadoc@ref@page
+\newif\ifyadoc@show@keypath
+
+\newcommand\yadocset[1]{\pgfqkeys{/yadoc}{#1}\ignorespaces}
+
+\yadocset{
+ cmd item/.style={
+ name prefix=\textbackslash,
+ label prefix=cmd,
+ },
+ key item/.style={
+ name prefix={\ifdefempty{\yadoc@keypath}{}{%
+ \ifyadoc@show@keypath
+ \textcolor
+ {\yadoc@name@color!\yadoc@keypath@color@opacity}%
+ {\yadoc@keypath/}%
+ \fi
+ }%
+ },
+ ref prefix={\protect\ifyadoc@show@keypath\yadoc@keypath/\protect\fi},
+ index prefix=,
+ parameters prefix={\texttt{=}},
+ label prefix:=key:\yadoc@keypath@label/,
+ index annotation={key\ifdefempty{\yadoc@keypath}{}{ in \texttt{\yadoc@keypath}}},
+ },
+ env item/.style={
+ head prefix={\texttt{\cs{begin}\{}},
+ head infix={\}},
+ head suffix={%
+ \par\strut{\ttfamily\nobreakspace\nobreakspace}\meta{environment body}%
+ \par\strut\texttt{\cs{end}\{\yadoc@do@name\}}},
+ index annotation=environment,
+ label prefix=env,
+ },
+ register item/.style={
+ name prefix=\textbackslash,
+ label prefix=reg,
+ index annotation=register,
+ },
+ file item/.style={
+ index annotation=file,
+ label prefix=file,
+ },
+ value item/.style={
+ index annotation={value of
+ {\docref[show keypath,into index=false,link color=gray]{\yadoc@of}}},
+ label prefix:={\yadoc@of=},
+ },
+ scope/.code={%
+ \begingroup
+ \pgfkeysalso{#1}%
+ \endgroup
+ },
+ generic item/.style={
+ label prefix:=,
+ },
+ %
+ raster options/.style={},
+ before body/.store in=\yadoc@before@body,
+ after body/.store in=\yadoc@after@body,
+ left/.dimstore in=\yadoc@left,
+ right/.dimstore in=\yadoc@right,
+ left indent/.dimstore in=\kvtcb@doc@indentleft,
+ right indent/.dimstore in=\kvtcb@doc@indentright,
+ name/.store in=\yadoc@name,
+ name/.append style={label={#1}, index={#1}, sort index={#1}},
+ parameters/.store in=\yadoc@parameters,
+ description/.store in=\yadoc@description,
+ label/.store in=\yadoc@label,
+ label prefix:/.store in=\yadoc@label@prefix,
+ label prefix/.style={label prefix:={#1:}},
+ name font/.store in=\yadoc@name@font,
+ name color/.store in=\yadoc@name@color,
+ name prefix/.store in=\yadoc@name@prefix,
+ name suffix/.store in=\yadoc@name@suffix,
+ name prefix/.append style={index prefix={#1}, ref prefix={#1}},
+ name suffix/.append style={index suffix={#1}, ref suffix={#1}},
+ parameters font/.store in=\yadoc@parameters@font,
+ parameters prefix/.store in=\yadoc@parameters@prefix,
+ parameters suffix/.store in=\yadoc@parameters@suffix,
+ keypath/.store in=\yadoc@keypath,
+ keypath label/.store in=\yadoc@keypath@label,
+ keypath/.append style={keypath label={#1}},
+ keypath color opacity/.store in=\yadoc@keypath@color@opacity,
+ show keypath/.is if=yadoc@show@keypath,
+ index/.store in=\yadoc@index,
+ index prefix/.store in=\yadoc@index@prefix,
+ index suffix/.store in=\yadoc@index@suffix,
+ index annotation/.initial=,
+ index font/.store in=\yadoc@index@font,
+ index annotation font/.store in=\yadoc@index@annotation@font,
+ sort index/.store in=\yadoc@sort@index,
+ index colorize names/.is if=yadoc@index@colorize@names,
+ index page number format/.store in=\yadoc@index@page@number@format,
+ index gather/.is if=yadoc@index@gather,
+ index command/.store in=\yadoc@index@command,
+ index actual/.store in=\yadoc@index@actual,
+ index quote/.store in=\yadoc@index@quote,
+ index level/.store in=\yadoc@index@level,
+ index encapsulator/.store in=\yadoc@index@encapsulator,
+ see/.initial=,
+ ref font/.store in=\yadoc@ref@font,
+ ref prefix/.store in=\yadoc@ref@prefix,
+ ref suffix/.store in=\yadoc@ref@suffix,
+ head prefix/.store in=\yadoc@head@prefix,
+ head infix/.store in=\yadoc@head@infix,
+ head suffix/.store in=\yadoc@head@suffix,
+ phrases/.code={\pgfqkeys{/yadoc/phrases}{#1}},
+ phrases/.unknown/.code={\csdef{yadoc@phrases@\pgfkeyscurrentname}{#1}},
+ ref page/.is if=yadoc@ref@page,
+ of/.store in=\yadoc@of,
+ link color/.code={\hypercolor{link}{#1}},
+ long description/.style={% for do/def
+ head/.append style={
+ sidebyside gap=1em,
+ lefthand ratio=#1,
+ },
+ },
+ long description/.default=0.6,
+ %
+ .unknown/.code={%
+ \pgfkeysifdefined{/yadoc/\pgfkeyscurrentname\space item/.@cmd}{%
+ \begingroup
+ \expandafter\pgfkeysalso\expandafter{%
+ \pgfkeyscurrentname\space item,
+ before,#1,after,
+ do
+ }%
+ \endgroup
+ }{%
+ \PackageError{yadoc}{Unknown item "\pgfkeyscurrentname"}%
+ {Perhaps you have misspelled an option name?}%
+ }%
+ },
+ before/.code={},
+ after/.code={},
+ do/.is choice,
+ ref options/.style={
+ show keypath=false,
+ },
+ def options/.style={
+ show keypath,
+ },
+ aux options/.style={
+ show keypath=false,
+ },
+ foreign options/.style={
+ show keypath=false,
+ cmd item/.append style={index annotation=command},
+ },
+ index options/.code=,
+ into index/.is if=yadoc@into@index,
+ print/.is if=yadoc@printref,
+}
+
+\NewDocumentEnvironment{doc}{O{}m}{%
+ \begin{list}{}{%
+ \setlength{\leftmargin}{\yadoc@left}%
+ \setlength{\itemindent}{0pt}%
+ \setlength{\itemsep}{0pt}%
+ \setlength{\parsep}{0pt}%
+ \setlength{\rightmargin}{\yadoc@right}%
+ }%
+ \item
+ \begin{tcboxedraster}[
+ raster columns=1,
+ raster row skip=0pt,
+ raster before skip=0pt,
+ raster after skip=0pt,
+ raster force size=false,
+ /yadoc/raster options
+ ]{blankest,
+ before skip=1\baselineskip plus 6\baselineskip minus .5\baselineskip,
+ after skip=0pt plus 2pt minus .5\baselineskip,%
+ #1%
+ }%
+ \yadocset{do/.default=def,def options,#2}%
+ \end{tcboxedraster}
+ \nopagebreak
+ \yadoc@before@body\relax
+ \nopagebreak
+ \ignorespaces
+}{%
+ \ifvmode\else\unskip\fi
+ \yadoc@after@body\relax
+ \end{list}%
+}
+
+\newcommand\docaux[2]{%
+ \begingroup
+ \yadocset{do/.default=aux,aux options,#1={name={#2}}}%
+ \endgroup
+}
+
+\newcommand\docAux[1]{%
+ \begingroup
+ \yadocset{do/.default=aux,aux options,#1}%
+ \endgroup
+}
+
+\newcommand\docForeign[1]{%
+ \begingroup
+ \yadoc@hyperreffalse
+ \yadocset{do/.default=foreign,foreign options,#1}%
+ \endgroup
+}
+
+\newcommand\docindex[1]{%
+ \begingroup
+ \yadoc@hyperreffalse
+ \yadocset{do/.default=index,index options,#1}%
+ \endgroup
+}
+
+\yadocset{
+ do/def/.code={%
+ \begin{tcolorbox}[%
+ blank,
+ colback=white, colframe=white,
+ code={%
+ \tcbdimto\tcb@temp@grow@left{\yadoc@left}%
+ \tcbdimto\tcb@temp@grow@right{\yadoc@right}%
+ },
+ grow to left by=\tcb@temp@grow@left,
+ grow to right by=\tcb@temp@grow@right,
+ sidebyside, sidebyside align=top, sidebyside gap=-\tcb@w@upper@real,
+ force nobeforeafter,
+ phantom=\phantomsection,
+ /yadoc/head,
+ ]%
+ \yadoc@head@prefix
+ \yadoc@do@name
+ \yadoc@do@index
+ \yadoc@do@label
+ \yadoc@head@infix
+ \yadoc@do@parameters
+ \yadoc@head@suffix
+ \yadoc@do@description
+ \end{tcolorbox}
+ \nopagebreak
+ },
+ do/aux/.code={%
+ \yadoc@do@name
+ \yadoc@do@index
+ \yadoc@do@label
+ },
+ do/foreign/.code={%
+ \yadoc@do@label
+ },
+ do/index/.code={%
+ \yadoc@do@label
+ \yadoc@do@index
+ },
+}
+
+\def\yadoc@do@name{%
+ \begingroup
+ \yadoc@name@colorize{%
+ \yadoc@name@font
+ \strut\yadoc@name@prefix\yadoc@name\yadoc@name@suffix\strut
+ }%
+ \endgroup
+}
+
+\def\yadoc@do@index{%
+ \ifyadoc@into@index
+ \yadoc@index@command{%
+ \yadoc@sort@index
+ \yadoc@index@actual
+ \yadoc@format@index
+ }%
+ \ifyadoc@index@gather
+ \yadoc@index@command{%
+ \yadoc@phrases@Commands
+ \yadoc@index@level
+ \yadoc@sort@index
+ \yadoc@index@actual
+ \yadoc@format@index
+ }%
+ \fi
+ \fi
+}
+
+\def\yadoc@name@colorize{%
+ \ifdefempty\yadoc@name@color{}{%
+ \textcolor{\yadoc@name@color}%
+ }%
+}
+
+\def\yadoc@format@index{%
+ {%
+ \ifyadoc@index@colorize@names\yadoc@name@colorize\fi
+ \yadoc@index@font
+ \yadoc@index@prefix\yadoc@index\yadoc@index@suffix
+ }%
+ {%
+ \ifkeyempty{/yadoc/index annotation}{}{%
+ \space\yadoc@index@annotation@font\pgfkeysvalueof{/yadoc/index annotation}%
+ }%
+ }%
+ \ifdefempty\yadoc@index@page@number@format{}{%
+ \yadoc@index@encapsulator
+ \yadoc@index@page@number@format
+ }%
+ \ifkeyempty{/yadoc/see}{}{%
+ \yadoc@index@encapsulator
+ see{\pgfkeysvalueof{/yadoc/see}}%
+ }%
+}
+
+\def\yadoc@do@label{%
+ \ifdefempty{\yadoc@label}{}{%
+ \begingroup
+ \yadocset{ref options}%
+ \protected@edef\@currentlabel{%
+ \protect\ifyadoc@setupref
+ \ifyadoc@hyperref
+ \protect\yadoc@hyperreftrue
+ \else
+ \protect\yadoc@hyperreffalse
+ \fi
+ \protect\fi
+ \protect\ifyadoc@printref
+ \yadoc@ref@font
+ \yadoc@ref@prefix\yadoc@name\yadoc@ref@suffix
+ \protect\fi
+ \protect\ifyadoc@into@index
+ \yadoc@do@index
+ \protect\fi
+ }%
+ \label{\yadoc@label@prefix\yadoc@label}%
+ \endgroup
+ }%
+}
+
+\def\yadoc@do@parameters{%
+ \ifdefempty\yadoc@parameters{}{%
+ \begingroup
+ \yadoc@parameters@font
+ \yadoc@parameters@prefix\yadoc@parameters\yadoc@parameters@suffix
+ \endgroup
+ }%
+}
+
+\def\yadoc@do@description{%
+ \ifdefempty{\yadoc@description}{}{%
+ \tcblower
+ \raggedleft
+ \strut
+ (\yadoc@description)%
+ \strut
+ }%
+}
+
+% ref
+
+\newif\ifyadoc@setupref
+\newif\ifyadoc@printref
+\newif\ifyadoc@hyperref
+\yadoc@printreftrue
+\yadoc@hyperreftrue
+\DeclareRobustCommand\docref[2][]{%
+ \quitvmode % otherwise, extra vertical space if this begins an \item !?!
+ \begingroup
+ \yadocset{ref options,#1}%
+ \ifcsname r@#2\endcsname
+ \expanded{%
+ \noexpand\yadoc@setupreftrue
+ \ifyadoc@printref\noexpand\yadoc@printreffalse\fi
+ \ifyadoc@into@index\noexpand\yadoc@into@indexfalse\fi
+ \ifmemoize\noexpand\memoizefalse\fi
+ \ref*{#2}%
+ \noexpand\yadoc@setupreffalse
+ \ifyadoc@printref\noexpand\yadoc@printreftrue\fi
+ \ifyadoc@into@index\noexpand\yadoc@into@indextrue\fi
+ \ifmemoize\noexpand\memoizetrue\fi
+ }%
+ \fi
+ \ifyadoc@printref\else\yadoc@hyperreffalse\fi
+ \ifyadoc@hyperref
+ \ifnum\getpagerefnumber{#2}=\thepage\relax
+ \yadoc@into@indexfalse
+ \fi
+ \hyperref[#2]{%
+ \ref*{#2}%
+ \ifyadoc@printref
+ \ifyadoc@ref@page\yadoc@ref@pagenumber{#2}\fi
+ \fi
+ }%
+ \else
+ \ref*{#2}%
+ \ifyadoc@printref
+ \ifyadoc@ref@page\yadoc@ref@pagenumber{#2}\fi
+ \fi
+ \fi
+ \endgroup
+}
+\def\yadoc@ref@pagenumber#1{%
+ \ifnum\getpagerefnumber{#1}=\thepage\relax
+ \else%
+ \textsuperscript{%
+ {\fontfamily{pzd}\fontencoding{U}\fontseries{m}\fontshape{n}%
+ \selectfont\char213}%
+ \,\yadoc@phrases@pageshort\,\pageref*{#1}}%
+ \fi
+}
+
+
+\yadocset{
+ before body=,
+ after body=,
+ left=2em,
+ right=0pt,
+ left indent=-2em,
+ right indent=0pt,
+ name=,
+ name font=\ttfamily\bfseries,
+ index font=\ttfamily,
+ ref font=\ttfamily,
+ index annotation font=,
+ name color=black,
+ name prefix=,
+ name suffix=,
+ label=,
+ label prefix=,
+ parameters=,
+ parameters font=,
+ parameters prefix=,
+ parameters suffix=,
+ keypath=,
+ keypath color opacity=30,
+ description=,
+ into index=true,
+ index colorize names=false,
+ index page number format=,
+ index command=\index,
+ index gather=false,
+ index actual={@},
+ index quote={"},
+ index level={!},
+ index encapsulator={|},
+ head prefix=,
+ head infix=,
+ head suffix=,
+ ref page=false,
+ phrases={
+ index=Index,
+ pageshort=P.,
+ Commands=Commands,
+ },
+ text/.code={#1},
+ comma/.code={,\ },
+ and/.code={\ and\ },
+}
+
+\def\ifkeyempty#1{\ifcsempty{pgfk@#1}}
+
+\AddToHook{begindocument}{%
+ \robustify\index
+ \robustify\hypersetup
+}
diff --git a/macros/generic/memoize/memoize-clean.pl b/macros/generic/memoize/memoize-clean.pl
new file mode 100755
index 0000000000..4e1334c695
--- /dev/null
+++ b/macros/generic/memoize/memoize-clean.pl
@@ -0,0 +1,163 @@
+#!/usr/bin/env perl
+
+# This file is a part of Memoize, a TeX package for externalization of
+# graphics and memoization of compilation results in general, available at
+# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+#
+# Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+#
+# This work may be distributed and/or modified under the conditions of the
+# LaTeX Project Public License, either version 1.3c of this license or (at
+# your option) any later version. The latest version of this license is in
+# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+# all distributions of LaTeX version 2008 or later.
+#
+# This work has the LPPL maintenance status `maintained'.
+# The Current Maintainer of this work is Saso Zivanovic.
+#
+# The files belonging to this work and covered by LPPL are listed in
+# <texmf>/doc/generic/memoize/FILES.
+
+use strict;
+use Getopt::Long;
+# I intend to rewrite this script using Path::Class.
+use Cwd 'realpath';
+use File::Spec;
+use File::Basename;
+
+my $VERSION = '2023/10/10 v1.0.0';
+
+my $usage = "usage: memoize-clean.py [-h] [--yes] [--all] [--quiet] [--prefix PREFIX] [mmz ...]\n";
+my $Help = <<END;
+Remove (stale) memo and extern files.
+
+positional arguments:
+ mmz .mmz record files
+
+options:
+ -h, --help show this help message and exit
+ --version, -V show version and exit
+ --yes, -y Do not ask for confirmation.
+ --all, -a Remove *all* memos and externs.
+ --quiet, -q
+ --prefix PREFIX, -p PREFIX
+ A path prefix to clean; this option can be specified multiple times.
+
+For details, see the man page or the Memoize documentation.
+END
+
+my ($yes, $all, @prefixes, $quiet, $help, $print_version);
+GetOptions(
+ "yes|y" => \$yes,
+ "all|a" => \$all,
+ "prefix|p=s" => \@prefixes,
+ "quiet|q|?" => \$quiet,
+ "help|h|?" => \$help,
+ "version|V" => \$print_version,
+ ) or die $usage;
+$help and die "$usage\n$Help";
+if ($print_version) { print("memoize-clean.pl of Memoize $VERSION\n"); exit 0 }
+
+my (%keep, %prefixes);
+
+my $curdir = Cwd::getcwd();
+
+for my $prefix (@prefixes) {
+ $prefixes{Cwd::realpath(File::Spec->catfile(($curdir), $prefix))} = '';
+}
+
+my @mmzs = @ARGV;
+
+for my $mmz (@mmzs) {
+ my ($mmz_filename, $mmz_dir) = File::Basename::fileparse($mmz);
+ @ARGV = ($mmz);
+ my $endinput = 0;
+ my $empty = -1;
+ my $prefix = "";
+ while (<>) {
+ if (/^ *$/) {
+ } elsif ($endinput) {
+ die "Bailing out, \\endinput is not the last line of file $mmz.\n";
+ } elsif (/^ *\\mmzPrefix *{(.*?)}/) {
+ $prefix = $1;
+ $prefixes{Cwd::realpath(File::Spec->catfile(($curdir,$mmz_dir), $prefix))} = '';
+ $empty = 1 if $empty == -1;
+ } elsif (/^%? *\\mmz(?:New|Used)(?:CC?Memo|Extern) *{(.*?)}/) {
+ my $fn = $1;
+ if ($prefix eq '') {
+ die "Bailing out, no prefix announced before file $fn.\n";
+ }
+ $keep{Cwd::realpath(File::Spec->catfile(($mmz_dir), $fn))} = 1;
+ $empty = 0;
+ if (rindex($fn, $prefix, 0) != 0) {
+ die "Bailing out, prefix of file $fn does not match " .
+ "the last announced prefix ($prefix).\n";
+ }
+ } elsif (/^ *\\endinput *$/) {
+ $endinput = 1;
+ } else {
+ die "Bailing out, file $mmz contains an unrecognized line: $_\n";
+ }
+ }
+ die "Bailing out, file $mmz is empty.\n" if $empty && !$all;
+ die "Bailing out, file $mmz does not end with \\endinput; this could mean that " .
+ "the compilation did not finish properly. You can only clean with --all.\n"
+ if $endinput == 0 && !$all;
+}
+
+my @tbdeleted;
+sub populate_tbdeleted {
+ my ($basename_prefix, $dir, $suffix_dummy) = @_;
+ opendir(MD, $dir) or die "Cannot open directory '$dir'";
+ while( (my $fn = readdir(MD)) ) {
+ my $path = File::Spec->catfile(($dir),$fn);
+ if ($fn =~ /\Q$basename_prefix\E[0-9A-F]{32}(?:-[0-9A-F]{32})?(?:-[0-9]+)?(\.memo|(?:-[0-9]+)?\.pdf|\.log)/ and ($all || !exists($keep{$path}))) {
+ push @tbdeleted, $path;
+ }
+ }
+ closedir(MD);
+}
+for my $prefix (keys %prefixes) {
+ my ($basename_prefix, $dir, $suffix);
+ if (-d $prefix) {
+ populate_tbdeleted('', $prefix, '');
+ }
+ populate_tbdeleted(File::Basename::fileparse($prefix));
+}
+@tbdeleted = sort(@tbdeleted);
+
+my @allowed_dirs = ($curdir);
+my @deletion_not_allowed;
+for my $f (@tbdeleted) {
+ my $f_allowed = 0;
+ for my $dir (@allowed_dirs) {
+ if ($f =~ /^\Q$dir\E/) {
+ $f_allowed = 1;
+ last;
+ }
+ }
+ push(@deletion_not_allowed, $f) if ! $f_allowed;
+}
+die "Bailing out, I was asked to delete these files outside the current directory:\n" .
+ join("\n", @deletion_not_allowed) if (@deletion_not_allowed);
+
+if (scalar(@tbdeleted) != 0) {
+ my $a;
+ unless ($yes) {
+ print("I will delete the following files:\n" .
+ join("\n",@tbdeleted) . "\n" .
+ "Proceed (y/n)? ");
+ $a = lc(<>);
+ chomp $a;
+ }
+ if ($yes || $a eq 'y' || $a eq 'yes') {
+ foreach my $fn (@tbdeleted) {
+ print "Deleting ", $fn, "\n" unless $quiet;
+ unlink $fn;
+ }
+ } else {
+ die "Bailing out.\n";
+ }
+} elsif (!$quiet) {
+ print "Nothing to do, the directory seems clean.\n";
+}
diff --git a/macros/generic/memoize/memoize-clean.py b/macros/generic/memoize/memoize-clean.py
new file mode 100755
index 0000000000..dd543327cb
--- /dev/null
+++ b/macros/generic/memoize/memoize-clean.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+
+# This file is a part of Memoize, a TeX package for externalization of
+# graphics and memoization of compilation results in general, available at
+# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+#
+# Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+#
+# This work may be distributed and/or modified under the conditions of the
+# LaTeX Project Public License, either version 1.3c of this license or (at
+# your option) any later version. The latest version of this license is in
+# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+# all distributions of LaTeX version 2008 or later.
+#
+# This work has the LPPL maintenance status `maintained'.
+# The Current Maintainer of this work is Saso Zivanovic.
+#
+# The files belonging to this work and covered by LPPL are listed in
+# <texmf>/doc/generic/memoize/FILES.
+
+__version__ = '2023/10/10 v1.0.0'
+
+import argparse, re, sys, pathlib, os
+
+parser = argparse.ArgumentParser(
+ description="Remove (stale) memo and extern files.",
+ epilog = "For details, see the man page or the Memoize documentation."
+)
+parser.add_argument('--yes', '-y', action = 'store_true',
+ help = 'Do not ask for confirmation.')
+parser.add_argument('--all', '-a', action = 'store_true',
+ help = 'Remove *all* memos and externs.')
+parser.add_argument('--quiet', '-q', action = 'store_true')
+parser.add_argument('--prefix', '-p', action = 'append', default = [],
+ help = 'A path prefix to clean; this option can be specified multiple times.')
+parser.add_argument('mmz', nargs= '*', help='.mmz record files')
+parser.add_argument('--version', '-V', action = 'version',
+ version = f"%(prog)s of Memoize " + __version__)
+args = parser.parse_args()
+
+re_prefix = re.compile(r'\\mmzPrefix *{(.*?)}')
+re_memo = re.compile(r'%? *\\mmz(?:New|Used)(?:CC?Memo|Extern) *{(.*?)}')
+re_endinput = re.compile(r' *\\endinput *$')
+
+prefixes = set(pathlib.Path(prefix).resolve() for prefix in args.prefix)
+keep = set()
+
+# We loop through the given .mmz files, adding prefixes to whatever manually
+# specified by the user, and collecting the files to keep.
+for mmz_fn in args.mmz:
+ mmz = pathlib.Path(mmz_fn)
+ mmz_parent = mmz.parent.resolve()
+ try:
+ with open(mmz) as mmz_fh:
+ prefix = ''
+ endinput = False
+ empty = None
+ for line in mmz_fh:
+ line = line.strip()
+
+ if not line:
+ pass
+
+ elif endinput:
+ raise RuntimeError(
+ r'Bailing out, \endinput is not the last line of file $mmz_fn.')
+
+ elif m := re_prefix.match(line):
+ prefix = m[1]
+ prefixes.add( (mmz_parent/prefix).resolve() )
+ if empty is None:
+ empty = True
+
+ elif m := re_memo.match(line):
+ if not prefix:
+ raise RuntimeError(
+ f'Bailing out, no prefix announced before file "{m[1]}".')
+ if not m[1].startswith(prefix):
+ raise RuntimeError(
+ f'Bailing out, prefix of file "{m[1]}" does not match '
+ f'the last announced prefix ({prefix}).')
+ keep.add((mmz_parent / m[1]))
+ empty = False
+
+ elif re_endinput.match(line):
+ endinput = True
+ continue
+
+ else:
+ raise RuntimeError(fr"Bailing out, "
+ fr"file {mmz_fn} contains an unrecognized line: {line}")
+
+ if empty and not args.all:
+ raise RuntimeError(fr'Bailing out, file {mmz_fn} is empty.')
+
+ if not endinput and empty is not None and not args.all:
+ raise RuntimeError(
+ fr'Bailing out, file {mmz_fn} does not end with \endinput; '
+ fr'this could mean that the compilation did not finish properly. '
+ fr'You can only clean with --all.'
+ )
+
+ # It is not an error if the file doesn't exist.
+ # Otherwise, cleaning from scripts would be cumbersome.
+ except FileNotFoundError:
+ pass
+
+tbdeleted = []
+def populate_tbdeleted(folder, basename_prefix):
+ re_aux = re.compile(
+ re.escape(basename_prefix) +
+ '[0-9A-F]{32}(?:-[0-9A-F]{32})?(?:-[0-9]+)?(?:\.memo|(?:-[0-9]+)?\.pdf|\.log)$')
+ try:
+ for f in folder.iterdir():
+ if re_aux.match(f.name) and (args.all or f not in keep):
+ tbdeleted.append(f)
+ except FileNotFoundError:
+ pass
+
+for prefix in prefixes:
+ # "prefix" is interpreted both as a directory (if it exists) and a basename prefix.
+ if prefix.is_dir():
+ populate_tbdeleted(prefix, '')
+ populate_tbdeleted(prefix.parent, prefix.name)
+
+allowed_dirs = [pathlib.Path().absolute()] # todo: output directory
+deletion_not_allowed = [f for f in tbdeleted if not f.is_relative_to(*allowed_dirs)]
+if deletion_not_allowed:
+ raise RuntimeError("Bailing out, "
+ "I was asked to delete these files outside the current directory:\n" +
+ "\n".join(str(f) for f in deletion_not_allowed))
+
+_cwd_absolute = pathlib.Path().absolute()
+def relativize(path):
+ try:
+ return path.relative_to(_cwd_absolute)
+ except ValueError:
+ return path
+
+if tbdeleted:
+ tbdeleted.sort()
+ if not args.yes:
+ print('I will delete the following files:')
+ for f in tbdeleted:
+ print(relativize(f))
+ print("Proceed (y/n)? ")
+ a = input()
+ if args.yes or a == 'y' or a == 'yes':
+ for f in tbdeleted:
+ if not args.quiet:
+ print("Deleting", relativize(f))
+ try:
+ f.unlink()
+ except FileNotFoundError:
+ print(f"Cannot delete {f}")
+ else:
+ print("Bailing out.")
+elif not args.quiet:
+ print('Nothing to do, the directory seems clean.')
diff --git a/macros/generic/memoize/memoize-extract.pl b/macros/generic/memoize/memoize-extract.pl
new file mode 100755
index 0000000000..8fba3d356f
--- /dev/null
+++ b/macros/generic/memoize/memoize-extract.pl
@@ -0,0 +1,205 @@
+#!/usr/bin/env perl
+
+# This file is a part of Memoize, a TeX package for externalization of
+# graphics and memoization of compilation results in general, available at
+# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+#
+# Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+#
+# This work may be distributed and/or modified under the conditions of the
+# LaTeX Project Public License, either version 1.3c of this license or (at
+# your option) any later version. The latest version of this license is in
+# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+# all distributions of LaTeX version 2008 or later.
+#
+# This work has the LPPL maintenance status `maintained'.
+# The Current Maintainer of this work is Saso Zivanovic.
+#
+# The files belonging to this work and covered by LPPL are listed in
+# <texmf>/doc/generic/memoize/FILES.
+
+use strict;
+use Getopt::Long;
+use Path::Class;
+use File::Spec;
+use File::Basename;
+use PDF::API2;
+
+my $VERSION = '2023/10/10 v1.0.0';
+
+my $usage = "usage: memoize-extract.pl [-h] [--pdf PDF] [--prune] [--keep] [--force] [--log LOG] [--warning-template WARNING_TEMPLATE] [--quiet] [--mkdir] mmz\n";
+my $Help = <<END;
+Extract extern pages out of the document PDF.
+
+positional arguments:
+ mmz the record file produced by Memoize: doc.mmz when compiling doc.tex
+
+options:
+ --help, -h show this help message and exit
+ --version, -V show version and exit
+ --pdf PDF, -P PDF extract from file PDF
+ --prune, -p remove the extern pages after extraction
+ --keep, -k do not mark externs as extracted
+ --force, -f extract even if the size-check fails
+ --log LOG, -l LOG the log file
+ --warning-template WARNING_TEMPLATE, -w WARNING_TEMPLATE
+ \warningtext in the template will be replaced by the warning message
+ --quiet, -q don't describe what's happening
+ --embedded, -e prefix all messages to the standard output with the script name
+ --mkdir, -m create a directory (and exit)
+
+For details, see the man page or the Memoize documentation.
+END
+
+my ($pdf_arg, $prune, $keep, $log, $quiet, $embedded, $force, $mkdir, $help, $print_version);
+my $warning_template = '\warningtext';
+Getopt::Long::Configure ("bundling");
+GetOptions(
+ "pdf|P=s" => \$pdf_arg,
+ "keep|k" => \$keep,
+ "prune|p" => \$prune,
+ "log|l=s" => \$log,
+ "quiet|q" => \$quiet,
+ "embedded|e" => \$embedded,
+ "force|f" => \$force,
+ "warning-template|w=s" => \$warning_template,
+ "mkdir|m" => \$mkdir,
+ "help|h|?" => \$help,
+ "version|V" => \$print_version,
+ ) or die $usage;
+if ($help) {print("$usage\n$Help"); exit 0}
+if ($print_version) { print("memoize-extract.pl of Memoize $VERSION\n"); exit 0 }
+die $usage unless @ARGV == 1;
+
+my $message_prefix = $embedded ? basename($0) . ': ' : '';
+print("\n") if ($embedded);
+
+my @output_paths = (dir()->absolute->resolve);
+my $texmfoutput = `kpsewhich --var-value=TEXMFOUTPUT`;
+$texmfoutput =~ s/^\s+|\s+$//g;
+if ($texmfoutput) {
+ my $texmfoutput_dir = dir($texmfoutput)->absolute->resolve;
+ push(@output_paths, $texmfoutput_dir) unless $texmfoutput_dir->dir_list == 1 && ! $texmfoutput_dir->volume;
+}
+
+sub paranoia {
+ my $file = $_[0];
+ die "${message_prefix}Cannot create a hidden file or dir: $file"
+ if $file->basename =~ /^\./;
+ my $parent = $file->parent->absolute->resolve;
+ die "${message_prefix}Cannot write outside the current working or output directory tree: $file"
+ unless grep($_->contains($parent), @output_paths);
+}
+
+my $mmz_arg = $ARGV[0];
+my $mmz_file = file($mmz_arg);
+my $mmz_dir = $mmz_file->parent;
+
+if ($mkdir) {
+ my $dir = dir($mmz_arg)->cleanup;
+ my $current = dir(File::Spec->catpath($dir->volume,
+ $dir->is_absolute ? File::Spec->rootdir : File::Spec->curdir,
+ ''))->absolute;
+ for my $c ($dir->components) {
+ $current = $current->subdir($c);
+ if (-d $current) {
+ $current = $current->resolve;
+ } else {
+ paranoia($current);
+ mkdir($current);
+ print("${message_prefix}Created directory $current\n") unless $quiet;
+ }
+ }
+ exit;
+} else {
+ die "${message_prefix}The 'mmz' argument should be a file with suffix '.mmz', not '$mmz_file'\n" unless $mmz_file->basename =~ /\.mmz$/;
+}
+
+# Enable in-place editing (of the .mmz file).
+paranoia($mmz_file) unless $keep;
+$^I = "" unless $keep;
+
+my $pdf_file = $pdf_arg ? file($pdf_arg) : $mmz_dir->file($mmz_file->basename =~ s/\.mmz$/\.pdf/r)->cleanup;
+paranoia($pdf_file) if $prune;
+
+if ($log) {
+ paranoia(file($log));
+ open LOG, ">$log";
+} else {
+ *LOG = *STDERR;
+}
+
+my ($pdf, %extern_pages);
+print "${message_prefix}Extracting externs from $pdf_file:\n" unless $quiet;
+
+my $tolerance = 0.01;
+my $done_message = "${message_prefix}Done (there was nothing to extract).\n";
+
+while (<>) {
+ if (/^\\mmzNewExtern *{(?P<extern_path>(?P<prefix>.*?)(?P<code_md5sum>[0-9A-F]{32})-(?P<context_md5sum>[0-9A-F]{32})(?:-[0-9]+)?.pdf)}{(?P<page_n>[0-9]+)}{(?P<expected_width>[0-9.]*)pt}{(?P<expected_height>[0-9.]*)pt}/) {
+ my $extern_file = file($+{extern_path});
+ if (! $extern_file->is_absolute) {
+ $extern_file = $mmz_dir->file($+{extern_path});
+ }
+ paranoia($extern_file);
+ my $page = $+{page_n};
+ my $expected_width_pt = $+{expected_width};
+ my $expected_height_pt = $+{expected_height};
+ my $c_memo_file = $mmz_dir->file($+{prefix} . $+{code_md5sum} . '.memo');
+ my $cc_memo_file = $mmz_dir->file($+{prefix} . $+{code_md5sum} . '-' . $+{context_md5sum} . '.memo');
+ if (!(-e $c_memo_file && -e $cc_memo_file)) {
+ print LOG ($warning_template =~ s/\\warningtext/Not extracting page $page into extern $extern_file, because the associated (c)c-memo does not exist/gr), "\n\\endinput\n";
+ last;
+ }
+ eval { $pdf = PDF::API2->open($pdf_file->stringify) unless $pdf; };
+ if ($@) {
+ print LOG ($warning_template =~ s/\\warningtext/Cannot read file "$pdf_file". Perhaps you have to load Memoize earlier in the preamble?/gr), "\n\\endinput\n";
+ close LOG;
+ die "${message_prefix}File '$pdf_file' cannot be read, bailing out.\n";
+ }
+ my $extern = PDF::API2->new();
+ $extern->version($pdf->version);
+ $extern->import_page($pdf, $page);
+ my $extern_page = $extern->open_page(1);
+ my ($x0, $y0, $x1, $y1) = $extern_page->get_mediabox();
+ my $width_pt = ($x1 - $x0) / 72 * 72.27;
+ my $height_pt = ($y1 - $y0) / 72 * 72.27;
+ my $warning = '';
+ if (abs($width_pt - $expected_width_pt) > $tolerance
+ || abs($height_pt - $expected_height_pt) > $tolerance)
+ {
+ $warning = "I refuse to extract page $page from $pdf_file, because its size (${width_pt}pt x ${height_pt}pt) is not what I expected (${expected_width_pt}pt x ${expected_height_pt}pt)";
+ print LOG ($warning_template =~ s/\\warningtext/$warning/gr), "\n";
+ }
+ if ($warning && !$force) {
+ unlink $extern_file;
+ } else {
+ $extern->saveas($extern_file->stringify);
+ $done_message = "${message_prefix}Done.\n";
+ print STDOUT "${message_prefix} Page $page --> $extern_file\n" unless $quiet;
+ $extern_pages{$page} = 1 if $prune;
+ print("%") unless $keep;
+ }
+ }
+ print unless $keep;
+}
+
+print $done_message unless $quiet;
+
+if ($pdf and $prune) {
+ paranoia($pdf_file);
+ my $pruned_pdf = PDF::API2->new();
+ for (my $n = 1; $n <= $pdf->page_count(); $n++) {
+ if (! $extern_pages{$n}) {
+ $pruned_pdf->import_page($pdf, $n);
+ }
+ }
+ $pruned_pdf->save($pdf_file->stringify);
+ print("${message_prefix}The following extern pages were pruned out of the PDF: ",
+ join(",", sort(keys(%extern_pages))) . "\n") unless $quiet;
+}
+
+if ($log) {
+ print LOG "\\endinput\n";
+ close LOG;
+}
diff --git a/macros/generic/memoize/memoize-extract.py b/macros/generic/memoize/memoize-extract.py
new file mode 100755
index 0000000000..54d8870e7b
--- /dev/null
+++ b/macros/generic/memoize/memoize-extract.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+
+# This file is a part of Memoize, a TeX package for externalization of
+# graphics and memoization of compilation results in general, available at
+# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+#
+# Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+#
+# This work may be distributed and/or modified under the conditions of the
+# LaTeX Project Public License, either version 1.3c of this license or (at
+# your option) any later version. The latest version of this license is in
+# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+# all distributions of LaTeX version 2008 or later.
+#
+# This work has the LPPL maintenance status `maintained'.
+# The Current Maintainer of this work is Saso Zivanovic.
+#
+# The files belonging to this work and covered by LPPL are listed in
+# <texmf>/doc/generic/memoize/FILES.
+
+__version__ = '2023/10/10 v1.0.0'
+
+import argparse, re, sys, os, pdfrw, subprocess, itertools
+from pathlib import Path
+
+parser = argparse.ArgumentParser(
+ description = "Extract extern pages out of the document PDF.",
+ epilog = "For details, see the man page or the Memoize documentation.",
+ prog = 'memoize-extract.py',
+)
+parser.add_argument('--pdf', '-P', help = 'extract from file PDF')
+parser.add_argument('--prune', '-p', action = 'store_true',
+ help = 'remove the extern pages after extraction')
+parser.add_argument('--keep', '-k', action = 'store_true',
+ help = 'do not mark externs as extracted')
+parser.add_argument('--force', '-f', action = 'store_true',
+ help = 'extract even if the size-check fails')
+parser.add_argument('--log', '-l', default = os.devnull, help = 'the log file')
+parser.add_argument('--warning-template', '-w', default = '\warningtext',
+ help = '\warningtext in the template will be replaced by the warning message')
+parser.add_argument('--quiet', '-q', action = 'store_true',
+ help = "describe what's happening")
+parser.add_argument('--embedded', '-e', action = 'store_true',
+ help = "prefix all messages to the standard output with the script name")
+parser.add_argument('--mkdir', '-m', action = 'store_true',
+ help = 'create a directory (and exit)')
+parser.add_argument('mmz',
+ help = 'the record file produced by Memoize: doc.mmz when compiling doc.tex')
+parser.add_argument('--version', '-V', action = 'version',
+ version = f"%(prog)s of Memoize " + __version__)
+
+args = parser.parse_args()
+
+message_prefix = parser.prog + ': ' if args.embedded else ''
+if args.embedded:
+ print()
+
+# Even a bit more paranoid than required:
+# (a) disallowing TEXMFOUTPUT=/ (while allowing C:\ on Windows)
+# (b) waiting for access to '-output-directory'.
+output_paths = [Path.cwd()]
+if texmfoutput := subprocess.run(
+ ['kpsewhich', '--var-value=TEXMFOUTPUT'],
+ capture_output = True).stdout.decode().strip():
+ texmfoutput_dir = Path(texmfoutput).resolve()
+ if len(texmfoutput_dir.parts) != 1 or texmfoutput_dir.drive:
+ output_paths.append(texmfoutput_dir)
+
+def paranoia(f):
+ p = Path(f).resolve()
+ if p.stem.startswith('.'):
+ raise RuntimeError(f"{message_prefix}Cannot create a hidden file or dir: {f}")
+ if not any(p.is_relative_to(op) for op in output_paths):
+ raise RuntimeError(f"{message_prefix}Cannot write outside the current working or output directory tree: {f}")
+
+mmz_file = Path(args.mmz)
+
+if args.mkdir: # Here, argument "mmz" is interpreted as the directory to create.
+ # We cannot simply say
+ # paranoia(mmz_file)
+ # mmz_file.mkdir(parents = True, exist_ok = True)
+ # because have be paranoid about the intermediate directories as well:
+ # memoize-extract.py -m a/../../BAD/../<cwd-name>/b
+ # Note that paranoia might kick in only after a part of the given path was
+ # already created. This is in accord to how "mkdir" behaves wrt existing
+ # files.
+ for folder in itertools.chain(reversed(mmz_file.parents), (mmz_file,)):
+ if not folder.is_dir():
+ paranoia(folder)
+ folder.mkdir(exist_ok = True)
+ if not args.quiet:
+ print(f"{message_prefix}Created directory {folder}")
+ sys.exit()
+elif mmz_file.suffix != '.mmz':
+ raise RuntimeError(f"{message_prefix}The 'mmz' argument should be a file with suffix '.mmz', not '{mmz_file}'")
+
+mmz_dir = mmz_file.parent
+pdf_file = Path(args.pdf) if args.pdf else mmz_file.with_suffix('.pdf')
+paranoia(pdf_file)
+pdf = None
+extern_pages = []
+new_mmz = []
+args.log is os.devnull or paranoia(Path(args.log))
+re_newextern = re.compile(r'\\mmzNewExtern *{(?P<extern_fn>(?P<prefix>.*?)(?P<code_md5sum>[0-9A-F]{32})-(?P<context_md5sum>[0-9A-F]{32})(?:-[0-9]+)?.pdf)}{(?P<page_n>[0-9]+)}{(?P<expected_width>[0-9.]*)pt}{(?P<expected_height>[0-9.]*)pt}')
+tolerance = 0.01
+done_message = f"{message_prefix}Done (there was nothing to extract)."
+
+# Complication: I want to use 'with', but don't have to open stderr.
+with open(args.log, 'w') as log:
+ log = sys.stderr if args.log is os.devnull else log
+ try:
+ mmz = mmz_file.open()
+ except FileNotFoundError:
+ print(f'''{message_prefix}File "{mmz_file}" does not exist, assuming there's nothing to do.''',
+ file = sys.stderr)
+ else:
+ if not args.quiet:
+ print(f"{message_prefix}Extracting externs from {pdf_file}")
+ for line in mmz:
+ if m := re_newextern.match(line):
+ extern_file = mmz_dir / m['extern_fn']
+ paranoia(extern_file)
+ page_n = int(m['page_n'])-1
+ c_memo = mmz_dir / (m['prefix'] + m['code_md5sum'] + '.memo')
+ cc_memo = mmz_dir / (m['prefix'] + m['code_md5sum'] + '-' + m['context_md5sum'] + '.memo')
+ if not (c_memo.exists() and cc_memo.exists()):
+ print(args.warning_template.replace('\warningtext', f'Not extracting page {page_n} into extern {extern_file}, because the associated (c)c-memo does not exist'), file = log)
+ continue
+ if not pdf:
+ try:
+ pdf = pdfrw.PdfReader(pdf_file)
+ except pdfrw.errors.PdfParseError:
+ print(f'{message_prefix}File "{pdf_file}" cannot be read, bailing out.', file = sys.stderr)
+ print(args.warning_template.replace('\warningtext', f'Cannot read file "{pdf_file}". Perhaps you have to load Memoize earlier in the preamble?'), file = log)
+ args.keep = True
+ break
+ extern = pdfrw.PdfWriter(extern_file)
+ page = pdf.pages[page_n]
+ expected_width_pt, expected_height_pt = float(m['expected_width']), float(m['expected_height'])
+ mb = page['/MediaBox']
+ width_bp, height_bp = float(mb[2]) - float(mb[0]), float(mb[3]) - float(mb[1])
+ width_pt = width_bp / 72 * 72.27
+ height_pt = height_bp / 72 * 72.27
+ warning = None
+ if abs(width_pt - expected_width_pt) > tolerance \
+ or abs(height_pt - expected_height_pt) > tolerance:
+ warning = (
+ f'I refuse to extract page {page_n+1} from "{pdf_file}", '
+ f'because its size ({width_pt}pt x {height_pt}pt) is not '
+ f'what I expected ({expected_width_pt}pt x {expected_height_pt}pt)')
+ print(args.warning_template.replace('\warningtext', warning), file = log)
+ if warning and not args.force:
+ extern_file.unlink(missing_ok = True)
+ else:
+ extern.addpage(page)
+ if not args.quiet:
+ print(f"{message_prefix} Page {page_n+1} --> {extern_file}", file = sys.__stdout__)
+ extern.write()
+ done_message = f"{message_prefix}Done."
+ if args.prune:
+ extern_pages.append(page_n)
+ if not args.keep:
+ line = '%' + line
+ if not args.keep:
+ new_mmz.append(line)
+ mmz.close()
+ if not args.quiet:
+ print(done_message)
+ if not args.keep:
+ paranoia(mmz_file)
+ with open(mmz_file, 'w') as mmz:
+ for line in new_mmz:
+ print(line, file = mmz, end = '')
+ if args.prune and extern_pages:
+ pruned_pdf = pdfrw.PdfWriter(pdf_file)
+ pruned_pdf.addpages(
+ page for n, page in enumerate(pdf.pages) if n not in extern_pages)
+ pruned_pdf.write()
+ if not args.quiet:
+ print(f"{message_prefix}The following extern pages were pruned out of the PDF:",
+ ",".join(str(page+1) for page in extern_pages))
+ if args.log is not os.devnull:
+ print(r'\endinput', file = log)
diff --git a/macros/generic/memoize/memoize.edtx b/macros/generic/memoize/memoize.edtx
new file mode 100644
index 0000000000..10794c7a3b
--- /dev/null
+++ b/macros/generic/memoize/memoize.edtx
@@ -0,0 +1,3597 @@
+% \iffalse
+%
+% memoize.edtx (this is not a .dtx file; to produce a .dtx, process it with edtx2dtx)
+%
+%% This file is a part of Memoize, a TeX package for externalization of
+%% graphics and memoization of compilation results in general, available at
+%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+%%
+%% Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/memoize/)FILES.
+%
+% \fi
+%
+% \begin{macrocode}
+%
+% \relax
+%
+% This file contains the documented source code of
+% package \href{https://ctan.org/pkg/memoize}{Memoize} and, somewhat
+% unconventionally, its two independently distributed auxiliary
+% packages \href{https://ctan.org/pkg/advice}{Advice}
+% and \href{https://ctan.org/pkg/collargs}{CollArgs}.
+%
+% The source code of the \hologo{TeX} parts of the package resides in
+% |memoize.edtx|, |advice.edtx| and |collargs.edtx|. These files are written
+% in \href{https://ctan.org/pkg/easydtx}{EasyDTX}, a format of my own invention
+% which is almost like the DTX format but eliminates the need for all those
+% pesky |macrocode| environments: Any line introduced by a single comment
+% counts as documentation, and to top it off, documentation lines may be
+% indented. An |.edtx| file is converted to a |.dtx| by a little Perl script
+% called |edtx2dtx|; there is also a rudimentary Emacs mode, implemented in
+% |easydoctex-mode.el|, which takes care of fontification, indentation, and
+% forward and inverse search.
+%
+% The |.edtx| files contain the code for all three formats supported by the
+% three packages --- \hologo{LaTeX} (guard |latex|), \hologo{plainTeX} (guard
+% |plain|) and \hologo{ConTeXt} (guard |context|) --- but upon reading the
+% code, it will quickly become clear that Memoize was first developed for
+% \hologo{LaTeX}. In \S\ref{sec:code:identification}, we manually define
+% whatever \hologo{LaTeX} tools are ``missing'' in \hologo{plainTeX} and
+% \hologo{ConTeXt}. Even worse, \hologo{ConTeXt} code is often just the same
+% as \hologo{plainTeX} code, even in cases where I'm sure \hologo{ConTeXt}
+% offers the relevant tools. This nicely proves that I have no clue about
+% \hologo{ConTeXt}. If you are willing to \hologo{ConTeXt}-ualize my code ---
+% please do so, your help is welcome!
+%
+% The runtimes of Memoize (and also Advice) comprise of more than just the main
+% runtime for each format. Memoize ships with two additional stub packages,
+% |nomemoize| and |memoizable|, and a \hologo{TeX}-based extraction script
+% |memoize-extract-one|; Advice optionally offers a \TikZ; support defined in
+% |advice-tikz.code.tex|. For the relation between guards and runtimes,
+% consult the core of the |.ins| files below.
+%
+% \tcbset{ins listing/.style={listing only, fonttitle=\ttfamily\footnotesize,
+% leftupper=-1.5mm, lefttitle=2mm, right=0mm, top=2mm, bottom=2.65mm,
+% listing options app={basicstyle=\ttfamily\scriptsize}}}
+%
+% \begin{tcbraster}[raster columns=100]
+% \tcbinputlisting{raster multicolumn=55, ins listing, top=1mm, bottom=1mm, title=memoize.ins,listing file=../memoize.ins, linerange={27-38}, leftupper=1mm}
+% \begin{tcboxedraster}[raster columns=1]{blankest, raster multicolumn=45}
+% \tcbinputlisting{ins listing, title=advice.ins, listing file=../advice.ins, linerange=28-31}
+% \tcbinputlisting{ins listing, title=collar\raisebox{0pt}[\height][0pt]{g}s.ins, listing file=../collargs.ins, linerange=29-31}
+% \end{tcboxedraster}
+% \end{tcbraster}
+%
+% Memoize also contains two scripts, |memoize-extract| and |memoize-clean|.
+% Both come in two functionally equivalent implementations: Perl (|.pl|) and a
+% Python (|.py|). The code is listed in \S\ref{sec:code:scripts}, I believe it
+% is self-explanatory enough to lack more than a occasional comment.
+%
+%
+% \thispagestyle{empty}
+% \clearpage
+% \tableofcontents
+% \clearpage
+%
+% \newgeometry{left=4cm,right=1cm,top=1cm,bottom=1cm,
+% marginparwidth=3cm,marginparsep=0pt,nohead,includefoot}
+% \settowidth\marginparsep{\ }
+%
+% \section{First things first}
+% \label{sec:code:identification}
+%
+% \paragraph{Identification} of |memoize|, |memoizable| and |nomemoize|.
+%<*mmz>
+%<latex>\ProvidesPackage{memoize}[2023/10/10 v1.0.0 Fast and flexible externalization]
+%<context>%D \module[
+%<context>%D file=t-memoize.tex,
+%<context>%D version=1.0.0,
+%<context>%D title=Memoize,
+%<context>%D subtitle=Fast and flexible externalization,
+%<context>%D author=Saso Zivanovic,
+%<context>%D date=2023-10-10,
+%<context>%D copyright=Saso Zivanovic,
+%<context>%D license=LPPL,
+%<context>%D ]
+%<context>\writestatus{loading}{ConTeXt User Module / memoize}
+%<context>\unprotect
+%<context>\startmodule[memoize]
+%<plain>% Package memoize 2023/10/10 v1.0.0
+%</mmz>
+%<*mmzable>
+%<latex>\ProvidesPackage{memoizable}[2023/10/10 v1.0.0 A programmer's stub for Memoize]
+%<context>%D \module[
+%<context>%D file=t-memoizable.tex,
+%<context>%D version=1.0.0,
+%<context>%D title=Memoizable,
+%<context>%D subtitle=A programmer's stub for Memoize,
+%<context>%D author=Saso Zivanovic,
+%<context>%D date=2023-10-10,
+%<context>%D copyright=Saso Zivanovic,
+%<context>%D license=LPPL,
+%<context>%D ]
+%<context>\writestatus{loading}{ConTeXt User Module / memoizable}
+%<context>\unprotect
+%<context>\startmodule[memoizable]
+%<plain>% Package memoizable 2023/10/10 v1.0.0
+%</mmzable>
+%<*nommz>
+%<latex>\ProvidesPackage{nomemoize}[2023/10/10 v1.0.0 A no-op stub for Memoize]
+%<context>%D \module[
+%<context>%D file=t-nomemoize.tex,
+%<context>%D version=1.0.0,
+%<context>%D title=Memoize,
+%<context>%D subtitle=A no-op stub for Memoize,
+%<context>%D author=Saso Zivanovic,
+%<context>%D date=2023-10-10,
+%<context>%D copyright=Saso Zivanovic,
+%<context>%D license=LPPL,
+%<context>%D ]
+%<context>\writestatus{loading}{ConTeXt User Module / nomemoize}
+%<context>\unprotect
+%<context>\startmodule[nomemoize]
+%<mmz>% Package nomemoize 2023/10/10 v1.0.0
+%</nommz>
+%
+% \paragraph{Required packages} and \hologo{LaTeX}ization of \hologo{plainTeX}
+% and \hologo{ConTeXt}.
+%<*(mmz,mmzable,nommz)&(plain,context)>
+\input miniltx
+%</(mmz,mmzable,nommz)&(plain,context)>
+% Some stuff which is ``missing'' in |miniltx|, copied here from |latex.ltx|.
+%<*mmz&(plain,context)>
+\def\PackageWarning#1#2{{%
+ \newlinechar`\^^J\def\MessageBreak{^^J\space\space#1: }%
+ \message{#1: #2}}}
+%</mmz&(plain,context)>
+% Same as the official definition, but without |\outer|. Needed for record
+% file declarations.
+%<*mmz&plain>
+\def\newtoks{\alloc@5\toks\toksdef\@cclvi}
+\def\newwrite{\alloc@7\write\chardef\sixt@@n}
+%</mmz&plain>
+% |Nomemoize| has to load |pgfopts| as well, and process package options (right
+% away, why not), otherwise \hologo{LaTeX} will complain.
+%<*latex>
+%<mmz,nommz>\RequirePackage{pgfopts} % pgfkeys-based package options
+%<nommz>\pgfkeys{/memoize/package options/.unknown/.code={}}
+%<nommz>\ProcessPgfPackageOptions{/memoize/package options}
+%</latex>
+% I can't really write any code without |etoolbox| \dots
+%<*mmz>
+%<latex>\RequirePackage{etoolbox}
+%<plain,context>\input etoolbox-generic
+% Setup the |memoize| namespace in \hologo{LuaTeX}.
+\ifdefined\luatexversion
+ \directlua{memoize = {}}
+\fi
+% |pdftexcmds.sty| eases access to some PDF primitives, but I cannot manage to
+% load it in \hologo{ConTeXt}, even if it's supposed to be a generic
+% package. So let's load |pdftexcmds.lua| and copy--paste what we need from
+% |pdftexcmds.sty|.
+%<latex>\RequirePackage{pdftexcmds}
+%<plain>\input pdftexcmds.sty
+%<*context>
+\directlua{%
+ require("pdftexcmds")
+ tex.enableprimitives('pdf@', {'draftmode'})
+}
+\long\def\pdf@mdfivesum#1{%
+ \directlua{%
+ oberdiek.pdftexcmds.mdfivesum("\luaescapestring{#1}", "byte")%
+ }%
+}%
+\def\pdf@system#1{%
+ \directlua{%
+ oberdiek.pdftexcmds.system("\luaescapestring{#1}")%
+ }%
+}
+\let\pdf@primitive\primitive
+% Lua function |oberdiek.pdftexcmds.filesize| requires the |kpse| library,
+% which is not loaded in \hologo{ConTeXt},
+% see \url(https://){github.com/latex3/lua-uni-algos/issues/3}, so we define our
+% own filesize function.
+\directlua{%
+ function memoize.filesize(filename)
+ local filehandle = io.open(filename, "r")
+ % We can't easily use |~=|, as |~| is an active character, so the |else|
+ % workaround.
+ if filehandle == nil then
+ else
+ tex.write(filehandle:seek("end"))
+ io.close(filehandle)
+ end
+ end
+}%
+\def\pdf@filesize#1{%
+ \directlua{memoize.filesize("\luaescapestring{#1}")}%
+}
+%</context>
+% Take care of some further differences between the engines.
+\ifdef\pdftexversion{%
+}{%
+ \def\pdfhorigin{1true in}%
+ \def\pdfvorigin{1true in}%
+ \ifdef\XeTeXversion{%
+ \let\quitvmode\leavevmode
+ }{%
+ \ifdef\luatexversion{%
+ \let\pdfpagewidth\pagewidth
+ \let\pdfpageheight\pageheight
+ \def\pdfmajorversion{\pdfvariable majorversion}%
+ \def\pdfminorversion{\pdfvariable minorversion}%
+ }{%
+ \PackageError{memoize}{Support for this TeX engine is not implemented}{}%
+ }%
+ }%
+}
+%
+% In \hologo{ConTeXt}, |\unexpanded| means |\protected|, and the usual
+% |\unexpanded| is available as |\normalunexpanded|. Option one: use dtx
+% guards to produce the correct control sequence. I tried this option. I find
+% it ugly, and I keep forgetting to guard. Option two: |\let| an internal
+% control sequence, like |\mmz@unexpanded|, to the correct thing, and use that
+% all the time. I never tried this, but I find it ugly, too, and I guess I
+% would forget to use the new control sequence, anyway. Option three: use
+% |\unexpanded| in the |.dtx|, and |sed| through the generated \hologo{ConTeXt}
+% files to replace all its occurrences by |\normalunexpanded|. Oh yeah!
+%
+%
+% \paragraph.{Shipout}
+% We will next load our own auxiliary package, CollArgs, but before we do
+% that, we need to grab |\shipout| in \hologo{plainTeX}. The problem is,
+% Memoize needs to hack into the shipout routine, but it has best chances
+% of working as intended if it redefines the \emph{primitive} |\shipout|.
+% However, CollArgs loads |pgfkeys|, which in turn (and perhaps with no for
+% reason) loads |atbegshi|, which redefines |\shipout|. For details, see
+% section~\ref{sec:code:extern}. Below, we first check that the current
+% meaning of |\shipout| is primitive, and then redefine it.
+%
+%<*plain>
+\def\mmz@regular@shipout{%
+ \global\advance\mmzRegularPages1\relax
+ \mmz@primitive@shipout
+}
+\edef\mmz@temp{\string\shipout}%
+\edef\mmz@tempa{\meaning\shipout}%
+\ifx\mmz@temp\mmz@tempa
+ \let\mmz@primitive@shipout\shipout
+ \let\shipout\mmz@regular@shipout
+\else
+ \PackageError{memoize}{Cannot grab \string\shipout, it is already redefined}{}%
+\fi
+%</plain>
+% Our auxiliary package (\MS\ref{sec:ref:collargs}, \S\ref{sec:code:collargs}).
+% We also need it in |nomemoize|, to collect manual environments.
+%<latex>\RequirePackage{advice}
+%<plain>\input advice
+%<context>\input t-advice
+%</mmz>
+%
+% \paragraph.{Loading order} |memoize| and |nomemoize| are mutually exclusive,
+% and |memoizable| must be loaded before either of them. |\mmz@loadstatus|: 1
+% = memoize, 2 = memoizable, 3 = nomemoize.
+%<*(plain,context)&(mmz,nommz,mmzable)>
+\def\ifmmz@loadstatus#1{%
+ \ifnum#1=0\csname mmz@loadstatus\endcsname\relax
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+%</(plain,context)&(mmz,nommz,mmzable)>
+%<*mmz>
+%<latex>\@ifpackageloaded{nomemoize}%
+%<plain,context>\ifmmz@loadstatus{3}%
+{%
+ \PackageError{memoize}{Cannot load the package, as "nomemoize" is already
+ loaded. Memoization will NOT be in effect}{Packages "memoize" and
+ "nomemoize" are mutually exclusive, please load either one or the other.}%
+ %<latex>\pgfkeys{/memoize/package options/.unknown/.code={}}
+ %<latex>\ProcessPgfPackageOptions{/memoize/package options}
+ \endinput
+}{}%
+%<latex>\@ifpackageloaded{memoizable}%
+%<plain,context>\ifmmz@loadstatus{2}%
+{%
+ \PackageError{memoize}{Cannot load the package, as "memoizable" is already
+ loaded}{Package "memoizable" is loaded by packages which support
+ memoization. Memoize must be loaded before all such packages. The
+ compilation log can help you figure out which package loaded "memoizable";
+ please move
+ %<latex>"\string\usepackage{memoize}"
+ %<plain>"\string\input memoize"
+ %<context>"\string\usemodule[memoize]"
+ before the
+ %<latex>"\string\usepackage"
+ %<plain>"\string\input"
+ %<context>"\string\usemodule"
+ of that package.}%
+ %<latex>\pgfkeys{/memoize/package options/.unknown/.code={}}
+ %<latex>\ProcessPgfPackageOptions{/memoize/package options}
+ \endinput
+}{}%
+%<plain,context>\ifmmz@loadstatus{1}{\endinput}{}%
+%<plain,context>\def\mmz@loadstatus{1}%
+%</mmz>
+%<*mmzable>
+%<latex>\@ifpackageloaded{memoize}%
+%<plain,context>\ifmmz@loadstatus{1}%
+{\endinput}{}
+%<latex>\@ifpackageloaded{nomemoize}%
+%<plain,context>\ifmmz@loadstatus{3}%
+{\endinput}{}%
+%<plain,context>\ifmmz@loadstatus{2}{\endinput}{}%
+%<plain,context>\def\mmz@loadstatus{2}%
+%</mmzable>
+%<*nommz>
+%<latex>\@ifpackageloaded{memoize}
+%<plain,context>\ifmmz@loadstatus{1}%
+{%
+ \PackageError{nomemoize}{Cannot load the package, as "memoize" is already
+ loaded; memoization will remain in effect}{Packages "memoize" and
+ "nomemoize" are mutually exclusive, please load either one or the other.}%
+ \endinput }{}%
+%<latex>\@ifpackageloaded{memoizable}%
+%<plain,context>\ifmmz@loadstatus{2}%
+{%
+ \PackageError{nomemoize}{Cannot load the package, as "memoizable" is already
+ loaded}{Package "memoizable" is loaded by packages which support
+ memoization. (No)Memoize must be loaded before all such packages. The
+ compilation log can help you figure out which package loaded
+ "memoizable"; please move
+ %<latex>"\string\usepackage{nomemoize}"
+ %<plain>"\string\input memoize"
+ %<context>"\string\usemodule[memoize]"
+ before the
+ %<latex>"\string\usepackage"
+ %<plain>"\string\input"
+ %<context>"\string\usemodule"
+ of that package.}%
+ \endinput
+}{}%
+%<plain,context>\ifmmz@loadstatus{3}{\endinput}{}%
+%<plain,context>\def\mmz@loadstatus{3}%
+%</nommz>
+%
+%<*mmz>
+%
+% \begin{macro}{\filetotoks}
+% Read \hologo{TeX} file |#2| into token register |#1| (under the current
+% category code regime); |\toksapp| is defined in CollArgs.
+\def\filetotoks#1#2{%
+ \immediate\openin0{#2}%
+ #1={}%
+ \loop
+ \unless\ifeof0
+ \read0 to \totoks@temp
+ % We need the |\expandafter|s for our |\toksapp| macro.
+ \expandafter\toksapp\expandafter#1\expandafter{\totoks@temp}%
+ \repeat
+ \immediate\closein0
+}
+% \end{macro}
+%
+% \paragraph{Other} little things.
+\newif\ifmmz@temp
+\newtoks\mmz@temptoks
+\newbox\mmz@box
+\newwrite\mmz@out
+%
+% \section{The basic configuration}
+% \label{sec:code:configuration}
+%
+% \begin{macro}{\mmzset}
+% The user primarily interacts with |Memoize| through the |pgfkeys|-based
+% configuration macro |\mmzset|, which executes keys in path |/mmz|. In
+% |nomemoize| and |memoizable|, is exists as a no-op.
+\def\mmzset#1{\pgfqkeys{/mmz}{#1}\ignorespaces}
+%</mmz>
+%<nommz,mmzable>\def\mmzset#1{\ignorespaces}
+% \end{macro}
+%
+% \begin{macro}{\mmzset}
+% Any |/mmz| keys used outside of |\mmzset| must be declared by this macro
+% for |nomemoize| package to work.
+%<mmz>\def\nommzkeys#1{}
+%<*nommz,mmzable>
+\def\nommzkeys{\pgfqkeys{/mmz}}
+\pgfqkeys{/mmz}{.unknown/.code={\pgfkeysdef{\pgfkeyscurrentkey}{}}}
+%</nommz,mmzable>
+% \end{macro}
+%
+% \begin{key}{enable, disable}
+% \begin{macro}{\ifmemoize}
+% These keys set \hologo{TeX}-style conditional \cs{ifmemoize}, used as the
+% central on/off switch for the functionality of the package --- it is
+% inspected in |\Memoize| and by run conditions of automemoization handlers.
+%
+% If used in the preamble, the effect of these keys is delayed until the
+% beginning of the document. The delay is implemented through a special
+% style, |begindocument|, which is executed at |begindocument| hook in
+% \hologo{LaTeX}; in other formats, the user must invoke it manually
+% (\MS\ref{sec:ref:loading}).
+%
+% |Nomemoize| does not need the keys themselves, but it does need the
+% underlying conditional --- which will be always false.
+%<mmz,nommz,mmzable>\newif\ifmemoize
+%<*mmz>
+\mmzset{%
+ enable/.style={begindocument/.append code=\memoizetrue},
+ disable/.style={begindocument/.append code=\memoizefalse},
+ begindocument/.append style={
+ enable/.code=\memoizetrue,
+ disable/.code=\memoizefalse,
+ },
+ % Memoize is enabled at the beginning of the document, unless explicitly
+ % disabled by the user in the preamble.
+ enable,
+}
+% \end{macro}
+% \end{key}
+%
+% \begin{key}{normal,readonly,recompile}
+% When Memoize is enabled, it can be in one of three modes
+% (\MS\ref{sec:tut:working-on-a-picture}): normal, readonly, and recompile.
+% The numeric constants are defined below. The mode is stored in
+% |\mmz@mode|, and only matters in |\Memoize| (and
+% |\mmz@process@ccmemo|).\footnote{In fact, this code treats anything but 1
+% and 2 as normal.}
+\def\mmz@mode@normal{0}
+\def\mmz@mode@readonly{1}
+\def\mmz@mode@recompile{2}
+\let\mmz@mode\mmz@mode@normal
+\mmzset{%
+ normal/.code={\let\mmz@mode\mmz@mode@normal},
+ readonly/.code={\let\mmz@mode\mmz@mode@readonly},
+ recompile/.code={\let\mmz@mode\mmz@mode@recompile},
+}
+% \end{key}
+%
+% \begin{key}{path, path/relative, path/dir, path/prefix}
+% Key |path| executes the given keylist in path |/mmz/path|, to determine the
+% full \emph{path prefix} to memo and extern files
+% (\MS\ref{sec:tut:memodir},\ref{sec:memos}): |relative|, true by default,
+% determines whether the location of these files is relative to the current
+% directory; |dir| sets their directory; and |prefix| sets the first, fixed
+% part of their basename; the second part containing the MD5 sum(s) is not
+% under user control, and neither is the suffix. These subkeys will be
+% initialized a bit later, via |no memo dir|.
+\mmzset{%
+ path/.code={\pgfqkeys{/mmz/path}{#1}},
+ path/.cd,
+ relative/.is if=mmz@relativepath,
+ dir/.store in=\mmz@dir,
+ dir/.value required,
+ prefix/.store in=\mmz@prefix,
+ prefix/.value required,
+}
+\newif\ifmmz@relativepath
+% Key |path| concludes by performing two post-path-setting actions: creating
+% the given directory if |mkdir| is in effect, and noting the new path prefix
+% in record files (by eventually executing |record/prefix|, which typically
+% puts a |\mmzPrefix| line in the |.mmz| file). These actions are the reason
+% for having the path setting keys grouped under |path| --- we don't want them
+% to be triggered by changes of the individual components of the path.
+% Similarly, we don't want them triggered by multiple invocations of |path| in
+% the preamble; only the final setting matters, so |path| is only equipped with
+% the action-triggering code at the beginning of the document.
+\mmzset{%
+ begindocument/.append style={
+ path/.append code=\mmz@maybe@mkmemodir\mmz@record@prefix,
+ },
+ % Consequently, the post-path-setting actions must be triggered manually at
+ % the beginning of the document. Below, we trigger directory creation;
+ % |record/prefix| will be called from |record/begin|, which is executed at
+ % the beginning of the document, so it shouldn't be mentioned here.
+ begindocument/.append code=\mmz@maybe@mkmemodir,
+}
+% Define the paths to the memo directory and the prefix.
+\def\mmz@dir@path{\ifmmz@relativepath.\fi/\mmz@dir}
+\def\mmz@prefix@path{\mmz@dir@path/\mmz@prefix}
+% \end{key}
+%
+% \begin{key}{mkdir, mkdir command}
+% Should we create the memo/extern directory if it doesn't exist? And which
+% command should we use to create it? Of course, shell escape must be
+% properly configured for this to work (\MS\ref{sec:shell-escape}).
+% ^^A todo: What about quoting the paths containing spaces on Windows? Will this work?
+\mmzset{
+ mkdir/.is if=mmz@mkdir,
+ mkdir command/.code={\def\mmz@mkdir@command##1{#1}},
+ mkdir command={mkdir "#1"},
+}
+% The underlying conditional \cs{ifmmz@mkdir} is only ever used in
+% |\mmz@maybe@mkmemodir| below, which is itself only executed at the end of
+% |path| and in |begindocument|.
+\newif\ifmmz@mkdir
+\def\mmz@maybe@mkmemodir{%
+ \ifmmz@mkdir
+ \pdf@system{\mmz@mkdir@command{\mmzOutputDirectory\mmz@dir@path}}%
+ \fi
+}
+% \end{key}
+%
+% \begin{key}{memo dir, no memo dir}
+% Shortcuts for two common settings of |path| keys. The default |no memo
+% dir| will place the memos and externs in the current directory, prefixed
+% with |#1.|, where |#1| defaults to (unquoted) |\jobname|. Key |memo dir|
+% places the memos and externs in a dedicated directory, |#1.memo.dir|; the
+% filenames themselves have no prefix. Furthermore, |memo dir| triggers the
+% creation of the directory.
+\mmzset{%
+ memo dir/.style={
+ mkdir,
+ path={
+ relative,
+ dir={#1.memo.dir},
+ prefix={},
+ },
+ },
+ memo dir/.default=\mmzUnquote\jobname,
+ no memo dir/.style={
+ mkdir=false,
+ path={
+ relative,
+ dir={},
+ prefix={#1.},
+ },
+ },
+ no memo dir/.default=\mmzUnquote\jobname,
+ no memo dir,
+}
+% \end{key}
+%
+% \begin{macro}{\mmzUnquote}
+% If the expanded argument is surrounded by double quotes, remove them. This
+% relies on |#1| containing no quotes other than the potential surrounding
+% quotes, which should be the case when applying the macro to |\jobname|. An
+% empty |#1| is dealt with correctly, even if |\jobname| can hardly ever be
+% empty (needs |openout_any=a|).
+%
+% We use this macro when we are passing a filename constructed from
+% |\jobname| to external programs.
+\def\mmzUnquote#1{\expanded{\noexpand\mmz@unquote#1}\mmz@unquote@end}
+\def\mmz@unquote#1{%
+ \ifx\mmz@unquote@end#1%
+ \else
+ \ifx"#1%
+ \expandafter\expandafter\expandafter\mmz@unquote@quotes
+ \else
+ \expandafter\expandafter\expandafter\mmz@unquote@noquotes
+ \expandafter\expandafter\expandafter#1%
+ \fi
+ \fi
+}
+\def\mmz@unquote@quotes#1"\mmz@unquote@end{#1}
+\def\mmz@unquote@noquotes#1\mmz@unquote@end{#1}
+% \end{macro}
+%
+% \begin{key}{ignore spaces}
+% The underlying conditional will be inspected by automemoization handlers,
+% to maybe put |\ignorespaces| after the invocation of the handler.
+\newif\ifmmz@ignorespaces
+\mmzset{
+ ignore spaces/.is if=mmz@ignorespaces,
+}
+% \end{key}
+%
+% \begin{key}{verbatim, verb, no verbatim}
+% These keys are tricky. For one, there's |verbatim|, which sets all
+% characters' category codes to other, and there's |verb|, which leaves
+% braces untouched (well, honestly, it redefines them). But Memoize itself
+% doesn't really care about this detail --- it only uses the underlying
+% conditional \cs{ifmmz@verbatim}. It is CollArgs which cares about the
+% difference between the ``long'' and the ``short'' verbatim, so we need to
+% tell it about it. That's why the verbatim options ``append themselves'' to
+% |\mmzRawCollectorOptions|, which is later passed on to
+% |\CollectArgumentsRaw| as a part of its optional argument.
+\newif\ifmmz@verbatim
+\def\mmzRawCollectorOptions{}
+\mmzset{
+ verbatim/.code={%
+ \def\mmzRawCollectorOptions{\collargsVerbatim}%
+ \mmz@verbatimtrue
+ },
+ verb/.code={%
+ \def\mmzRawCollectorOptions{\collargsVerb}%
+ \mmz@verbatimtrue
+ },
+ no verbatim/.code={%
+ \def\mmzRawCollectorOptions{\collargsNoVerbatim}%
+ \mmz@verbatimfalse
+ },
+}
+% \end{key}
+% \section{Memoization}
+% \label{sec:code:memoization}
+%
+% \subsection{Manual memoization}
+% \label{sec:code:memoization:manual}
+%
+% \begin{macro}{\mmz}
+% The core of this macro will be a simple invocation of |\Memoize|, but to
+% get there, we have to collect the optional argument carefully, because we
+% might have to collect the memoized code verbatim.
+\protected\def\mmz{\futurelet\mmz@temp\mmz@i}
+\def\mmz@i{%
+ % Anyone who wants to call |\Memoize| must open a group, because |\Memoize|
+ % will close a group.
+ \begingroup
+ % As the optional argument occurs after a control sequence (|\mmz|), any
+ % spaces were consumed and we can immediately test for the opening bracket.
+ \ifx\mmz@temp[%]
+ \def\mmz@verbatim@fix{}%
+ \expandafter\mmz@ii
+ \else
+ % If there was no optional argument, the opening brace (or the unlikely
+ % single token) of our mandatory argument is already tokenized. If we are
+ % requested to memoize in a verbatim mode, this non-verbatim tokenization
+ % was wrong, so we will use option |\collargsFixFromNoVerbatim| to ask
+ % CollArgs to fix the situation. (|\mmz@verbatim@fix| will only be used in
+ % the verbatim mode.)
+ \def\mmz@verbatim@fix{\noexpand\collargsFixFromNoVerbatim}%
+ % No optional argument, so we can skip |\mmz@ii|.
+ \expandafter\mmz@iii
+ \fi
+}
+\def\mmz@ii[#1]{%
+ % Apply the options given in the optional argument.
+ \mmzset{#1}%
+ \mmz@iii
+}
+\def\mmz@iii{%
+ % In the non-verbatim mode, we avoid collecting the single mandatory argument
+ % using |\CollectArguments|.
+ \ifmmz@verbatim
+ \expandafter\mmz@do@verbatim
+ \else
+ \expandafter\mmz@do
+ \fi
+}
+% This macro grabs the mandatory argument of |\mmz| and calls |\Memoize|.
+\long\def\mmz@do#1{%
+ \Memoize{#1}{#1}%
+}%
+%
+% The following macro uses |\CollectArgumentsRaw| of package CollArgs
+% (\S\ref{sec:code:collargs}) to grab the argument verbatim; the appropriate
+% verbatim mode triggering raw option was put in |\mmzRawCollectorOptions| by
+% key |verb(atim)|. The macro also |\mmz@verbatim@fix| contains the potential
+% request for a category code fix (\S\ref{sec:code:collargs:fix}).
+\def\mmz@do@verbatim#1{%
+ \expanded{%
+ \noexpand\CollectArgumentsRaw{%
+ \noexpand\collargsCaller{\noexpand\mmz}%
+ \expandonce\mmzRawCollectorOptions
+ \mmz@verbatim@fix
+ }%
+ }{+m}\mmz@do
+}
+% \end{macro}
+%
+% \begin{environment}{memoize}
+% The definition of the manual memoization environment proceeds along the
+% same lines as the definition of |\mmz|, except that we also have to
+% implement space-trimming, and that we will collect the environment using
+% |\CollectArguments| in both the verbatim and the non-verbatim and mode.
+%
+% We define the \hologo{LaTeX}, \hologo{plainTeX} and \hologo{ConTeXt}
+% environments in parallel. The definition of the \hologo{plainTeX} and
+% \hologo{ConTeXt} version is complicated by the fact that space-trimming is
+% affected by the presence vs.\ absence of the optional argument (for
+% purposes of space-trimming, it counts as present even if it is empty).
+%<*latex>
+% We define the \hologo{LaTeX} environment using |\newenvironment|, which
+% kindly grabs any spaces in front of the optional argument, if it exists ---
+% and if doesn't, we want to trim spaces at the beginning of the environment
+% body anyway.
+\newenvironment{memoize}[1][\mmz@noarg]{%
+ % We close the environment right away. We'll collect the environment body,
+ % complete with the end-tag, so we have to reintroduce the end-tag somewhere.
+ % Another place would be after the invocation of |\Memoize|, but that would
+ % put memoization into a double group and |\mmzAfterMemoization| would not work.
+ \end{memoize}%
+ % % We open the group which will be closed by |\Memoize|.
+ \begingroup
+ % As with |\mmz| above, if there was no optional argument, we have to ask
+ % Collargs for a fix. The difference is that, as we have collected the
+ % optional argument via |\newcommand|, we have to test for its presence in a
+ % roundabout way.
+ \def\mmz@temp{#1}%
+ \ifx\mmz@temp\mmz@noarg
+ \def\mmz@verbatim@fix{\noexpand\collargsFixFromNoVerbatim}%
+ \else
+ \def\mmz@verbatim@fix{}%
+ \mmzset{#1}%
+ \fi
+ \mmz@env@iii
+}{}
+\def\mmz@noarg{\mmz@noarg}
+%</latex>
+%<plain>\def\memoize{%
+%<context>\def\startmemoize{%
+%<*plain,context>
+ \begingroup
+ % In \hologo{plainTeX} and \hologo{ConTeXt}, we don't have to worry about any
+ % spaces in front of the optional argument, as the environments are opened by
+ % a control sequence.
+ \futurelet\mmz@temp\mmz@env@i
+}
+\def\mmz@env@i{%
+ \ifx\mmz@temp[%]
+ \def\mmz@verbatim@fix{}%
+ \expandafter\mmz@env@ii
+ \else
+ \def\mmz@verbatim@fix{\noexpand\collargsFixFromNoVerbatim}%
+ \expandafter\mmz@env@iii
+ \fi
+}
+\def\mmz@env@ii[#1]{%
+ \mmzset{#1}%
+ \mmz@env@iii
+}
+%</plain,context>
+\def\mmz@env@iii{%
+ \long\edef\mmz@do##1{%
+ % |\unskip| will ``trim'' spaces at the end of the environment body.
+ \noexpand\Memoize{##1}{##1\unskip}%
+ }%
+ \expanded{%
+ \noexpand\CollectArgumentsRaw{%
+ % |\CollectArgumentsRaw| will adapt the caller to the format automatically.
+ \noexpand\collargsCaller{memoize}%
+ % |verb(atim)| is in here if it was requested.
+ \expandonce\mmzRawCollectorOptions
+ % The category code fix, if needed.
+ \ifmmz@verbatim\mmz@verbatim@fix\fi
+ }%
+ % Spaces at the beginning of the environment body are trimmed by setting
+ % the first argument to |!t<space>| and disappearing it with
+ % |\collargsAppendPostwrap{}|; note that this removes any number of space
+ % tokens. |\CollectArgumentsRaw| automatically adapts the argument type
+ % |b| to the format.
+ %
+ }{&&{\collargsAppendPostwrap{}}!t{ }+b{memoize}}{\mmz@do}%
+}%
+%</mmz>
+% \end{environment}
+%
+% \begin{macro}{\nommz}
+% We throw away the optional argument if present, and replace the opening
+% brace with begin-group plus |\memoizefalse|. This way, the ``argument'' of
+% |\nommz| will be processed in a group (with Memoize disabled) and even the
+% verbatim code will work because the ``argument'' will not have been
+% tokenized.
+%
+% As a user command, |\nommz| has to make it into package |nomemoize| as
+% well, and we'll |\let| |\mmz| equal it there; it is not needed in
+% |mmzable|.
+%<*mmz,nommz>
+\protected\def\nommz#1#{%
+ \afterassignment\nommz@i
+ \let\mmz@temp
+}
+\def\nommz@i{%
+ \bgroup
+ \memoizefalse
+}
+%<nommz>\let\mmz\nommz
+% \end{macro}
+%
+% \begin{environment}{nomemoize}
+% We throw away the optional argument and take care of the spaces at the
+% beginning and at the end of the body.
+%<*latex>
+\newenvironment{nomemoize}[1][]{%
+ \memoizefalse
+ \ignorespaces
+}{%
+ \unskip
+}
+%</latex>
+%<*plain,context>
+%<plain>\def\nomemoize{%
+%<context>\def\startnomemoize{%
+% Start a group to delimit |\memoizefalse|.
+ \begingroup
+ \memoizefalse
+ \futurelet\mmz@temp\nommz@env@i
+}
+\def\nommz@env@i{%
+ \ifx\mmz@temp[%]
+ \expandafter\nommz@env@ii
+ % No optional argument, no problems with spaces.
+ \fi
+}
+\def\nommz@env@ii[#1]{%
+ \ignorespaces
+}
+%<plain>\def\endnomemoize{%
+%<context>\def\stopnomemoize{%
+ \endgroup
+ \unskip
+}
+%</plain,context>
+%<*nommz>
+%<plain,latex>\let\memoize\nomemoize
+%<plain,latex>\let\endmemoize\endnomemoize
+%<context>\let\startmemoize\startnomemoize
+%<context>\let\stopmemoize\stopnomemoize
+%</nommz>
+% \end{environment}
+%
+% \subsection{The memoization process}
+% \label{sec:code:memoization-process}
+%
+% \begin{macro}{\ifmemoizing}
+% This conditional is set to true when we start memoization (but not when
+% we start regular compilation or utilization); it should never be set
+% anywhere else. It is checked by |\Memoize| to prevent nested
+% memoizations, deployed in advice run conditions set by |run only if
+% memoizing|, etc.
+\newif\ifmemoizing
+% \end{macro}
+%
+% \begin{macro}{\ifinmemoize}
+% This conditional is set to true when we start either memoization or
+% regular compilation (but not when we start utilization); it should never
+% be set anywhere else. It is deployed in the default advice run conditions,
+% making sure that automemoized commands are not handled even when we're
+% regularly compiling some code submitted to memoization.
+\newif\ifinmemoize
+% \end{macro}
+%
+% \begin{macro}{\mmz@maybe@scantokens}
+% An auxiliary macro which rescans the given
+% code using |\scantokens| if the verbatim mode is active. We also need it
+% in NoMemoize, to properly grab verbatim manually memoized code.
+%</mmz,nommz>
+%<*mmz>
+\def\mmz@maybe@scantokens{%
+ \ifmmz@verbatim
+ \expandafter\mmz@scantokens
+ \else
+ \expandafter\@firstofone
+ \fi
+}
+% Without |\newlinechar=13|, |\scantokens| would see receive the entire
+% argument as one long line --- but it would not \emph{see} the entire
+% argument, but only up to the first newline character, effectively losing most
+% of the tokens. (We need to manually save and restore |\newlinechar| because
+% we don't want to execute the memoized code in yet another group.)
+\long\def\mmz@scantokens#1{%
+ \expanded{%
+ \newlinechar=13
+ \unexpanded{\scantokens{#1\endinput}}%
+ \newlinechar=\the\newlinechar
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\Memoize}
+% Memoization is invoked by executing |\Memoize|. This macro is a decision
+% hub. It test for the existence of the memos and externs associated with
+% the memoized code, and takes the appropriate action (memoization:
+% |\mmz@memoize|; regular compilation: |\mmz@compile|, utilization:
+% |\mmz@process@cmemo| plus |\mmz@process@ccmemo| plus further complications)
+% depending on the memoization mode (normal, readonly, recompile). Note that
+% one should open a \hologo{TeX} group prior to executing |\Memoize|, because
+% |\Memoize| will close a group (\MS\ref{sec:Memoize}).
+%
+% |\Memoize| takes two arguments, which contain two potentially different
+% versions of the code submitted to memoization: |#1| contains the code which
+% \meta{code MD5 sum} is computed off of, while |#2| contains the code which
+% is actually executed during memoization and regular compilation. The
+% arguments will contain the same code in the case of manual memoization, but
+% they will differ in the case of automemoization, where the executable code
+% will typically prefixed by |\AdviceOriginal|. As the two
+% codes will be used not only by |\Memoize| but also by macros called from
+% |\Memoize|, |\Memoize| stores them into dedicated toks registers, declared
+% below.
+\newtoks\mmz@mdfive@source
+\newtoks\mmz@exec@source
+% Finally, the definition of the macro. In package NoMemoize, we should simply
+% execute the code in the second argument. But in Memoize, we have work to do.
+\let\Memoize\@secondoftwo
+\long\def\Memoize#1#2{%
+ % We store the first argument into token register |\mmz@mdfive@source|
+ % because we might have to include it in tracing info (when |trace| is in
+ % effect), or paste it into the c-memo (depending on |include source in
+ % cmemo|).
+ \mmz@mdfive@source{#1}%
+ % We store the executable code in |\mmz@exec@source|. In the verbatim mode,
+ % the code will have to be rescanned. This is implemented by
+ % |\mmz@maybe@scantokens|, and we wrap the code into this macro right away,
+ % once and for all. Even more, we pre-expand |\mmz@maybe@scantokens| (three
+ % times), effectively applying the current \cs{ifmmz@verbatim} and
+ % eliminating the need to save and restore this conditional in
+ % |\mmz@compile|, which (regularly) compiles the code \emph{after} closing
+ % the |\Memoize| group --- after this pre-expansion, |\mmz@exec@source| will
+ % contain either |\mmz@scantokens{...}| or |\@firstofone{...}|.
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter
+ \mmz@exec@source
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter
+ {%
+ \mmz@maybe@scantokens{#2}%
+ }%
+ \mmz@trace@Memoize
+ % In most branches below, we end up with regular compilation, so let this be
+ % the default action.
+ \let\mmz@action\mmz@compile
+ % If Memoize is disabled, or if memoization is currently taking place, we
+ % will perform a regular compilation.
+ \ifmemoizing
+ \else
+ \ifmemoize
+ % Compute \meta{code md5sum} off of the first argument, and globally
+ % store it into |\mmz@code@mdfivesum| --- globally, because we need it in
+ % utilization to include externs, but the |\Memoize| group is closed (by
+ % |\mmzMemo|) while inputting the cc-memo.
+ \xdef\mmz@code@mdfivesum{\pdf@mdfivesum{\the\mmz@mdfive@source}}%
+ \mmz@trace@code@mdfive
+ % Recompile mode forces memoization.
+ \ifnum\mmz@mode=\mmz@mode@recompile\relax
+ \ifnum\pdf@draftmode=0
+ \let\mmz@action\mmz@memoize
+ \fi
+ \else
+ % In the normal and the readonly mode, we try to utilize the memos. The
+ % c-memo comes first. If the c-memo does not exist (or if something is
+ % wrong with it), |\mmz@process@cmemo| (defined in
+ % \S\ref{sec:code:c-memo}) will set |\ifmmz@abort| to true. It might
+ % also set |\ifmmzUnmemoizable| which means we should compile normally
+ % regardless of the mode.
+ \mmz@process@cmemo
+ \ifmmzUnmemoizable
+ \mmz@trace@cmemo@unmemoizable
+ \else
+ \ifmmz@abort
+ % If there is no c-memo, or it is invalid, we memoize, unless the
+ % read-only mode is in effect.
+ \mmz@trace@process@cmemo@fail
+ \ifnum\mmz@mode=\mmz@mode@readonly\relax
+ \else
+ \ifnum\pdf@draftmode=0
+ \let\mmz@action\mmz@memoize
+ \fi
+ \fi
+ \else
+ \mmz@trace@process@cmemo@ok
+ % If the c-memo was fine, the formal action decided upon is to try
+ % utilizing the cc-memo. If it exists and everything is fine with
+ % it, |\mmz@process@ccmemo| (defined in
+ % section~\ref{sec:code:cc-memo}) will utilize it, i.e.\ the core
+ % of the cc-memo (the part following |\mmzMemo|) will be executed
+ % (typically including the single extern). Otherwise,
+ % |\mmz@process@ccmemo| will trigger either memoization (in the
+ % normal mode) or regular compilation (in the readonly mode). This
+ % final decision is left to |\mmz@process@ccmemo| because if we
+ % made it here, the code would get complicated, as the cc-memo must
+ % be processed outside the |\Memoize| group and all the
+ % conditionals in this macro.
+ \let\mmz@action\mmz@process@ccmemo
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \mmz@action
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@compile}
+% This macro performs regular compilation --- this is signalled to the
+% memoized code and the memoization driver by setting \cs{ifinmemoize} to
+% true for the duration of the compilation; \cs{ifmemoizing} is not touched.
+% The group opened prior to the invocation of |\Memoize| is closed before
+% executing the code in |\mmz@exec@source|, so that compiling the code has
+% the same local effect as if was not submitted to memoization; it is closing
+% this group early which complicates the restoration of \cs{ifinmemoize} at
+% the end of compilation. Note that |\mmz@exec@source| is already set to
+% properly deal with the current verbatim mode, so any further inspection of
+% \cs{ifmmz@verbatim} is unnecessary; the same goes for
+% \cs{ifmmz@ignorespaces}, which was (or at least should be) taken care of by
+% whoever called |\Memoize|.
+\def\mmz@compile{%
+ \mmz@trace@compile
+ \expanded{%
+ \endgroup
+ \noexpand\inmemoizetrue
+ \the\mmz@exec@source
+ \ifinmemoize\noexpand\inmemoizetrue\else\noexpand\inmemoizefalse\fi
+ }%
+}
+% \end{macro}
+% \begin{luafun}{abortOnError}
+% \begin{macro}{\mmz@lua@atbeginmemoization,\mmz@lua@atendmemoization}
+% In \hologo{LuaTeX}, we can whether an error occurred during memoization,
+% and abort if it did. (We're going through |memoize.abort|, because
+% |tex.print| does not seem to work during error handling.) We omit all
+% this in \hologo{ConTeXt}, as it appears to stop on any error?
+%<*!context>
+\ifdefined\luatexversion
+ \directlua{%
+ luatexbase.add_to_callback(
+ "show_error_message",
+ function()
+ memoize.abort = true
+ texio.write_nl(status.lasterrorstring)
+ end,
+ "Abort memoization on error"
+ )
+ }%
+ \def\mmz@lua@atbeginmemoization{%
+ \directlua{memoize.abort = false}%
+ }%
+ \def\mmz@lua@atendmemoization{%
+ \directlua{%
+ if memoize.abort then
+ tex.print("\noexpand\\mmzAbort")
+ end
+ }%
+ }%
+\else
+%</!context>
+ \let\mmz@lua@atbeginmemoization\relax
+ \let\mmz@lua@atendmemoization\relax
+%<!context>\fi
+% \end{macro}
+% \end{luafun}
+% \begin{macro}{\mmz@memoize}
+% This macro performs memoization --- this is signalled to the memoized code
+% and the memoization driver by setting both \cs{ifinmemoize} and
+% \cs{ifinmemoizing} to true.
+\def\mmz@memoize{%
+ \mmz@trace@memoize
+ \memoizingtrue
+ \inmemoizetrue
+ % Initialize the various macros and registers used in memoization (to be
+ % described below, or later). Note that most of these are global, as they
+ % might be adjusted arbitrarily deep within the memoized code.
+ \edef\memoizinggrouplevel{\the\currentgrouplevel}%
+ \global\mmz@abortfalse
+ \global\mmzUnmemoizablefalse
+ \global\mmz@seq 0
+ \global\setbox\mmz@tbe@box\vbox{}%
+ \global\mmz@ccmemo@resources{}%
+ \global\mmzCMemo{}%
+ \global\mmzCCMemo{}%
+ \global\mmzContextExtra{}%
+ \gdef\mmzAtEndMemoizationExtra{}%
+ \gdef\mmzAfterMemoizationExtra{}%
+ \mmz@lua@atbeginmemoization
+ % Execute the pre-memoization hook, the memoized code (wrapped in the
+ % driver), and the post-memoization hook.
+ \mmzAtBeginMemoization
+ \mmzDriver{\the\mmz@exec@source}%
+ \mmzAtEndMemoization
+ \mmzAtEndMemoizationExtra
+ \mmz@lua@atendmemoization
+ \ifmmzUnmemoizable
+ % To permanently prevent memoization, we have to write down the c-memo
+ % (containing |\mmzUnmemoizabletrue|). We don't need the extra context in
+ % this case.
+ \global\mmzContextExtra{}%
+ \gtoksapp\mmzCMemo{\global\mmzUnmemoizabletrue}%
+ \mmz@write@cmemo
+ \mmz@trace@endmemoize@unmemoizable
+ \PackageWarning{memoize}{Marking this code as unmemoizable}%
+ \else
+ \ifmmz@abort
+ % If memoization was aborted, we create an empty c-memo, to make sure that
+ % no leftover c-memo tricks Memoize into thinking that the code was
+ % successfully memoized.
+ \mmz@trace@endmemoize@aborted
+ \PackageWarning{memoize}{Memoization was aborted}%
+ \mmz@write@empty@cmemo
+ \else
+ % If memoization was not aborted, we compute the \meta{context md5sum},
+ % open and write out the memos, and shipout the externs (as pages into the
+ % document).
+ \mmz@compute@context@mdfivesum
+ \mmz@write@cmemo
+ \mmz@write@ccmemo
+ \mmz@shipout@externs
+ \mmz@trace@endmemoize@ok
+ \fi
+ \fi
+ % After closing the group, we execute the final, after-memoization hook (we
+ % pre-expand the regular macro; the extra macro was assigned to globally). In
+ % the after-memoization code, |\mmzIncludeExtern| points to a macro which can
+ % include the extern from |\mmz@tbe@box|, which makes it possible to typeset
+ % the extern by dropping the contents of |\mmzCCMemo| into this hook --- but
+ % note that this will only work if |\ifmmzkeepexterns| was in effect at the
+ % end of memoization.
+ \expandafter\endgroup
+ \expandafter\let
+ \expandafter\mmzIncludeExtern\expandafter\mmz@include@extern@from@tbe@box
+ \mmzAfterMemoization
+ \mmzAfterMemoizationExtra
+}
+% \end{macro}
+%
+% \begin{macro}{\memoizinggrouplevel}
+% This macro stores the group level at the beginning of memoization. It is
+% deployed by |\IfMemoizing|, normally used by integrated drivers.
+\def\memoizinggrouplevel{-1}%
+% \end{macro}
+%
+% \begin{macro}{\mmzAbort}
+% Memoized code may execute this macro to abort memoization.
+\def\mmzAbort{\global\mmz@aborttrue}
+% \end{macro}
+%
+% \begin{macro}{\ifmmz@abort}
+% This conditional serves as a signal that something went wrong during
+% memoization (where it is set to true by |\mmzAbort|), or c(c)-memo
+% processing. The assignment to this conditional should always be global
+% (because it may be set during memoization).
+\newif\ifmmz@abort
+% \end{macro}
+%
+% \begin{macro}{\mmzUnmemoizable}
+% Memoized code may execute |\mmzUnmemoizable| to abort memoization and mark
+% (in the c-memo) that memoization should never be attempted again. The
+% c-memo is composed by |\mmz@memoize|.
+\def\mmzUnmemoizable{\global\mmzUnmemoizabletrue}
+% \end{macro}
+%
+% \begin{macro}{\ifmmzUnmemoizable}
+% This conditional serves as a signal that the code should never be
+% memoized. It can be set (a) during memoization (that's why it should be
+% assigned globally), after which it is inspected by |\mmz@memoize|, and
+% (b) from the c-memo, in which case it is inspected by |\Memoize|.
+\newif\ifmmzUnmemoizable
+% \end{macro}
+%
+% \begin{macro}{\mmzAtBeginMemoization,\mmzAtEndMemoization,\mmzAfterMemoization}
+% \begin{key}{at begin memoization, at end memoization, after memoization}
+% The memoization hooks and their keys. The hook macros may be set either
+% before or during memoization. In the former case, one should modify the
+% primary macro (|\mmzAtBeginMemoization|, |\mmzAtEndMemoization|,
+% |\mmzAfterMemoization|), and the assignment should be local. In the
+% latter case, one should modify the extra macro
+% (|\mmzAtEndMemoizationExtra|, |\mmzAfterMemoizationExtra|; there is no
+% |\mmzAtBeginMemoizationExtra|), and the assignment should be global. The
+% keys automatically adapt to the situation, by appending either to the
+% primary or the the extra macro; if |at begin memoization| is used during
+% memoization, the given code is executed immediately. We will use this
+% ``extra'' approach and the auto-adapting keys for other options, like
+% |context|, as well.
+\def\mmzAtBeginMemoization{}
+\def\mmzAtEndMemoization{}
+\def\mmzAfterMemoization{}
+\mmzset{
+ at begin memoization/.code={%
+ \ifmemoizing
+ \expandafter\@firstofone
+ \else
+ \expandafter\appto\expandafter\mmzAtBeginMemoization
+ \fi
+ {#1}%
+ },
+ at end memoization/.code={%
+ \ifmemoizing
+ \expandafter\gappto\expandafter\mmzAtEndMemoizationExtra
+ \else
+ \expandafter\appto\expandafter\mmzAtEndMemoization
+ \fi
+ {#1}%
+ },
+ after memoization/.code={%
+ \ifmemoizing
+ \expandafter\gappto\expandafter\mmzAfterMemoizationExtra
+ \else
+ \expandafter\appto\expandafter\mmzAfterMemoization
+ \fi
+ {#1}%
+ },
+}
+% \end{key}
+% \end{macro}
+%
+% \begin{key}{driver}
+% This key sets the (formal) memoization driver. The function of the driver
+% is to produce the memos and externs while executing the submitted code.
+\mmzset{
+ driver/.store in=\mmzDriver,
+ driver=\mmzSingleExternDriver,
+}
+% \end{key}
+%
+% \begin{macro}{\ifmmzkeepexterns}
+% This conditional causes Memoize not to empty out |\mmz@tbe@box|, holding
+% the externs collected during memoization, while shipping them out.
+\newif\ifmmzkeepexterns
+% \end{macro}
+%
+% \begin{macro}{\mmzSingleExternDriver}
+% The default memoization driver externalizes the submitted code. It always
+% produces exactly one extern, and including the extern will be the only
+% effect of inputting the cc-memo (unless the memoized code contained some
+% commands, like |\label|, which added extra instructions to the cc-memo.)
+% The macro (i) adds |\quitvmode| to the cc-memo, if we're capturing into a
+% horizontal box, and it puts it to the very front, so that it comes before
+% any |\label| and |\index| replications, guaranteeing (hopefully) that they
+% refer to the correct page; (ii) takes the code and typesets it in a box
+% (|\mmz@box|); (iii) submits the box for externalization; (iv) adds the
+% extern-inclusion code to the cc-memo, and (v) puts the box into the
+% document (again prefixing it with |\quitvmode| if necessary). (The listing
+% region markers help us present this code in the manual.)
+% \begin{listingregion}{single-extern-driver.tex}
+\long\def\mmzSingleExternDriver#1{%
+ \xtoksapp\mmzCCMemo{\mmz@maybe@quitvmode}%
+ \setbox\mmz@box\mmz@capture{#1}%
+ \mmzExternalizeBox\mmz@box\mmz@temptoks
+ \xtoksapp\mmzCCMemo{\the\mmz@temptoks}%
+ \mmz@maybe@quitvmode\box\mmz@box
+}
+% \end{listingregion}
+% \end{macro}
+%
+% \begin{key}{capture}
+% The default memoization driver uses |\mmz@capture| and
+% |\mmz@maybe@quitvmode|, which are set by this key. |\mmz@maybe@quitvmode|
+% will be expanded, but for \hologo{XeTeX}, we have defined |\quitvmode| as a
+% synonym for |\leavevmode|, which is a macro rather than a primitive, so we
+% have to prevent its expansion in that case. It is easiest to just add
+% |\noexpand|, regardless of the engine used.
+\mmzset{
+ capture/.is choice,
+ capture/hbox/.code={%
+ \let\mmz@capture\hbox
+ \def\mmz@maybe@quitvmode{\noexpand\quitvmode}%
+ },
+ capture/vbox/.code={%
+ \let\mmz@capture\vbox
+ \def\mmz@maybe@quitvmode{}%
+ },
+ capture=hbox,
+}
+% \end{key}
+% The memoized code may be memoization-aware; in such a case, we say that the
+% driver is \emph{integrated} into the code. Code containing an integrated
+% driver must take care to execute it only when memoizing, and not during a
+% regular compilation. The following key and macro can help here, see
+% \MS\ref{sec:memoization-complex-single-driver} for details.
+%
+% \begin{mmzautokey}{integrated driver}
+% This is an advice key, residing in |/mmz/auto|. Given \meta{suffix} as the
+% only argument, it declares conditional \cs{ifmemoizing}\meta{suffix}, and
+% sets the driver for the automemoized command to a macro which sets this
+% conditional to true. The declared conditional is \emph{internal} and
+% should not be used directly, but only via |\IfMemoizing| --- because it
+% will not be declared when package NoMemoize or only Memoizable is loaded.
+\mmzset{
+ auto/integrated driver/.style={
+ after setup={\expandafter\newif\csname ifmmz@memoizing#1\endcsname},
+ driver/.expand once={%
+ \csname mmz@memoizing#1true\endcsname
+ % Without this, we would introduce an extra group around the memoized
+ % code.
+ \@firstofone
+ }%
+ },
+}
+% \end{mmzautokey}
+%
+% \begin{macro}{\IfMemoizing}
+% Without the optional argument, the condition is satisfied when the internal
+% conditional \cs{ifmemoizing}\meta{suffix}, declared by |integrated driver|,
+% is true. With the optional argument \meta{offset}, the current group level
+% must additionally match the memoizing group level, modulo \meta{offset} ---
+% this makes sure that the conditional comes out as false in a regular
+% compilation embedded in a memoization.
+\newcommand\IfMemoizing[2][\mmz@Ifmemoizing@nogrouplevel]{%>\fi
+\csname ifmmz@memoizing#2\endcsname%>\if
+ % One |\relax| is for the |\numexpr|, another for |\ifnum|. Complications
+ % arise when |#1| is the optional argument default (defined below). In
+ % that case, the content of |\mmz@Ifmemoizing@nogrouplevel| closes off the
+ % |\ifnum| conditional (with both the true and the false branch empty), and
+ % opens up a new one, |\iftrue|. Effectively, we're not testing for the
+ % group level match.
+ \ifnum\currentgrouplevel=\the\numexpr\memoizinggrouplevel+#1\relax\relax
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \else
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \fi
+\else
+ \expandafter\@secondoftwo
+\fi
+}
+\def\mmz@Ifmemoizing@nogrouplevel{0\relax\relax\fi\iftrue}
+% \end{macro}
+%
+% \paragraph.{Tracing} We populate the hooks which send the tracing info to the
+% terminal.
+\def\mmz@trace#1{\immediate\write16{[tracing memoize] #1}}
+\def\mmz@trace@context{\mmz@trace{\space\space
+ Context: "\expandonce{\mmz@context@key}" --> \mmz@context@mdfivesum}}
+\def\mmz@trace@Memoize@on{%
+ \mmz@trace{%
+ Entering \noexpand\Memoize (%
+ \ifmemoize enabled\else disabled\fi,
+ \ifnum\mmz@mode=\mmz@mode@recompile recompile\fi
+ \ifnum\mmz@mode=\mmz@mode@readonly readonly\fi
+ \ifnum\mmz@mode=\mmz@mode@normal normal\fi
+ \space mode) on line \the\inputlineno
+ }%
+ \mmz@trace{\space\space Code: \the\mmz@mdfive@source}%
+}
+\def\mmz@trace@code@mdfive@on{\mmz@trace{\space\space
+ Code md5sum: \mmz@code@mdfivesum}}
+\def\mmz@trace@compile@on{\mmz@trace{\space\space Compiling}}
+\def\mmz@trace@memoize@on{\mmz@trace{\space\space Memoizing}}
+\def\mmz@trace@endmemoize@ok@on{\mmz@trace{\space\space
+ Memoization completed}}%
+\def\mmz@trace@endmemoize@aborted@on{\mmz@trace{\space\space
+ Memoization was aborted}}
+\def\mmz@trace@endmemoize@unmemoizable@on{\mmz@trace{\space\space
+ Marking this code as unmemoizable}}
+% No need for |\mmz@trace@endmemoize@fail|, as abortion results in a package
+% warning anyway.
+\def\mmz@trace@process@cmemo@on{\mmz@trace{\space\space
+ Attempting to utilize c-memo \mmz@cmemo@path}}
+\def\mmz@trace@process@no@cmemo@on{\mmz@trace{\space\space
+ C-memo does not exist}}
+\def\mmz@trace@process@cmemo@ok@on{\mmz@trace{\space\space
+ C-memo was processed successfully}\mmz@trace@context}
+\def\mmz@trace@process@cmemo@fail@on{\mmz@trace{\space\space
+ C-memo input failed}}
+\def\mmz@trace@cmemo@unmemoizable@on{\mmz@trace{\space\space
+ This code was marked as unmemoizable}}
+\def\mmz@trace@process@ccmemo@on{\mmz@trace{\space\space
+ Attempting to utilize cc-memo \mmz@ccmemo@path\space
+ (\ifmmz@direct@ccmemo@input\else in\fi direct input)}}
+\def\mmz@trace@resource@on#1{\mmz@trace{\space\space
+ Extern file does not exist: #1}}
+\def\mmz@trace@process@ccmemo@ok@on{%
+ \mmz@trace{\space\space Utilization successful}}
+\def\mmz@trace@process@no@ccmemo@on{%
+ \mmz@trace{\space\space CC-memo does not exist}}
+\def\mmz@trace@process@ccmemo@fail@on{%
+ \mmz@trace{\space\space Cc-memo input failed}}
+%
+% \begin{key}{tracing}
+% \begin{macro}{\mmzTracingOn,\mmzTracingOff}
+% The user interface for switching the tracing on and off; initially, it is
+% off. Note that there is no underlying conditional. The off version
+% simply |\let|s all the tracing hooks to |\relax|, so that the overhead of
+% having the tracing functionality available is negligible.
+\mmzset{%
+ trace/.is choice,
+ trace/.default=true,
+ trace/true/.code=\mmzTracingOn,
+ trace/false/.code=\mmzTracingOff,
+}
+\def\mmzTracingOn{%
+ \let\mmz@trace@Memoize\mmz@trace@Memoize@on
+ \let\mmz@trace@code@mdfive\mmz@trace@code@mdfive@on
+ \let\mmz@trace@compile\mmz@trace@compile@on
+ \let\mmz@trace@memoize\mmz@trace@memoize@on
+ \let\mmz@trace@process@cmemo\mmz@trace@process@cmemo@on
+ \let\mmz@trace@endmemoize@ok\mmz@trace@endmemoize@ok@on
+ \let\mmz@trace@endmemoize@unmemoizable\mmz@trace@endmemoize@unmemoizable@on
+ \let\mmz@trace@endmemoize@aborted\mmz@trace@endmemoize@aborted@on
+ \let\mmz@trace@process@cmemo\mmz@trace@process@cmemo@on
+ \let\mmz@trace@process@cmemo@ok\mmz@trace@process@cmemo@ok@on
+ \let\mmz@trace@process@no@cmemo\mmz@trace@process@no@cmemo@on
+ \let\mmz@trace@process@cmemo@fail\mmz@trace@process@cmemo@fail@on
+ \let\mmz@trace@cmemo@unmemoizable\mmz@trace@cmemo@unmemoizable@on
+ \let\mmz@trace@process@ccmemo\mmz@trace@process@ccmemo@on
+ \let\mmz@trace@resource\mmz@trace@resource@on
+ \let\mmz@trace@process@ccmemo@ok\mmz@trace@process@ccmemo@ok@on
+ \let\mmz@trace@process@no@ccmemo\mmz@trace@process@no@ccmemo@on
+ \let\mmz@trace@process@ccmemo@fail\mmz@trace@process@ccmemo@fail@on
+}
+\def\mmzTracingOff{%
+ \let\mmz@trace@Memoize\relax
+ \let\mmz@trace@code@mdfive\relax
+ \let\mmz@trace@compile\relax
+ \let\mmz@trace@memoize\relax
+ \let\mmz@trace@process@cmemo\relax
+ \let\mmz@trace@endmemoize@ok\relax
+ \let\mmz@trace@endmemoize@unmemoizable\relax
+ \let\mmz@trace@endmemoize@aborted\relax
+ \let\mmz@trace@process@cmemo\relax
+ \let\mmz@trace@process@cmemo@ok\relax
+ \let\mmz@trace@process@no@cmemo\relax
+ \let\mmz@trace@process@cmemo@fail\relax
+ \let\mmz@trace@cmemo@unmemoizable\relax
+ \let\mmz@trace@process@ccmemo\relax
+ \let\mmz@trace@resource\@gobble
+ \let\mmz@trace@process@ccmemo@ok\relax
+ \let\mmz@trace@process@no@ccmemo\relax
+ \let\mmz@trace@process@ccmemo@fail\relax
+}
+\mmzTracingOff
+% \end{macro}
+% \end{key}
+%
+%</mmz>
+%<nommz,mmzable>\newcommand\IfMemoizing[2][]{\@secondoftwo}
+%<*mmz>
+%
+% \subsection{Context}
+% \label{sec:code:context}
+%
+% \begin{macro}{\mmzContext,\mmzContextExtra}
+% The context expression is stored in two token registers. Outside
+% memoization, we will locally assign to |\mmzContext|; during memoization,
+% we will globally assign to |\mmzContextExtra|.
+\newtoks\mmzContext
+\newtoks\mmzContextExtra
+% \end{macro}
+% \begin{key}{context, clear context}
+% The user interface keys for context manipulation hide the complexity
+% underlying the context storage from the user.
+\mmzset{%
+ context/.code={%
+ \ifmemoizing
+ \expandafter\gtoksapp\expandafter\mmzContextExtra
+ \else
+ \expandafter\toksapp\expandafter\mmzContext
+ \fi
+ % We append a comma to the given context chunk, for disambiguation.
+ {#1,}%
+ },
+ clear context/.code={%
+ \ifmemoizing
+ \expandafter\global\expandafter\mmzContextExtra
+ \else
+ \expandafter\mmzContext
+ \fi
+ {}%
+ },
+ clear context/.value forbidden,
+ % \end{key}
+ % \begin{key}{meaning to context, csname meaning to context, key meaning to
+ % context, key value to context, /handlers/.meaning to context,
+ % /handlers/.value to context}
+ % Utilities to put the meaning of various stuff into |context|.
+ meaning to context/.code={\forcsvlist\mmz@mtoc{#1}},
+ csname meaning to context/.code={\mmz@mtoc@cs{#1}},
+ key meaning to context/.code={\forcsvlist\mmz@mtoc\mmz@mtoc@keycmd{#1}},
+ key value to context/.code={\forcsvlist\mmz@mtoc@key{#1}},
+ /handlers/.meaning to context/.code={%
+ \expanded{\noexpand\mmz@mtoc@cs{pgfk@\pgfkeyscurrentpath/.@cmd}}},
+ /handlers/.value to context/.code={%
+ \expanded{\noexpand\mmz@mtoc@cs{pgfk@\pgfkeyscurrentpath}}},
+}
+\def\mmz@mtoc#1{%
+ \collargs@cs@cases{#1}%
+ {\mmz@mtoc@cmd{#1}}%
+ {\mmz@mtoc@error@notcsorenv{#1}}%
+ {%
+ \mmz@mtoc@cs{%
+ %<context>start%
+ #1}%
+ \mmz@mtoc@cs{%
+ %<latex,plain>end%
+ %<context>stop%
+ #1}%
+ }%
+}
+\def\mmz@mtoc@cmd#1{%
+ \begingroup
+ \escapechar=-1
+ \expandafter\endgroup
+ \expandafter\mmz@mtoc@cs\expandafter{\string#1}%
+}
+\def\mmz@mtoc@cs#1{%
+ \pgfkeysvalueof{/mmz/context/.@cmd}%
+ \expandafter\string\csname#1\endcsname={\expandafter\meaning\csname#1\endcsname}%
+ \pgfeov
+}
+\def\mmz@mtoc@key#1{\mmz@mtoc@cs{pgfk@#1}}
+\def\mmz@mtoc@key#1{\mmz@mtoc@cs{pgfk@#1/.@cmd}}
+\def\mmz@mtoc@error@notcsorenv#1{%
+ \PackageError{memoize}{'\detokenize{#1}' passed to key 'meaning to context' is neither a command nor an environment}{}%
+}
+% \end{key}
+%
+%
+% \subsection{C-memos}
+% \label{sec:code:c-memo}
+%
+% \paragraph{The path} to a c-memo consists of the path prefix, the MD5 sum of
+% the memoized code, and suffix |.memo|.
+\def\mmz@cmemo@path{\mmz@prefix@path\mmz@code@mdfivesum.memo}
+% \begin{macro}{\mmzCMemo}
+% The additional, free-form content of the c-memo is collected in this token
+% register.
+\newtoks\mmzCMemo
+% \end{macro}
+%
+% \begin{key}{include source in cmemo}
+% \begin{macro}{\ifmmz@include@source}
+% Should we include the memoized code in
+% the c-memo? By default, yes. \bigskip
+\mmzset{%
+ include source in cmemo/.is if=mmz@include@source,
+}
+\newif\ifmmz@include@source
+\mmz@include@sourcetrue
+% \end{macro}
+% \end{key}
+%
+% \begin{macro}{\mmz@write@cmemo}
+% This macro creates the c-memo from the contents of |\mmzContextExtra| and
+% |\mmzCMemo|.
+\def\mmz@write@cmemo{%
+ % Open the file for writing.
+ \immediate\openout\mmz@out{\mmz@cmemo@path}%
+ % The memo starts with the |\mmzMemo| marker (a signal that the memo is valid).
+ \immediate\write\mmz@out{\noexpand\mmzMemo}%
+ % We store the content of |\mmzContextExtra| by writing out a command that
+ % will (globally) assign its content back into this register.
+ \immediate\write\mmz@out{%
+ \global\mmzContextExtra{\the\mmzContextExtra}\collargs@percentchar
+ }%
+ % Write out the free-form part of the c-memo.
+ \immediate\write\mmz@out{\the\mmzCMemo\collargs@percentchar}%
+ % When |include source in cmemo| is in effect, add the memoized code, hiding
+ % it behind the |\mmzSource| marker.
+ \ifmmz@include@source
+ \immediate\write\mmz@out{\noexpand\mmzSource}%
+ \immediate\write\mmz@out{\the\mmz@mdfive@source}%
+ \fi
+ % Close the file.
+ \immediate\closeout\mmz@out
+ % Record that we wrote a new c-memo.
+ \pgfkeysalso{/mmz/record/new cmemo={\mmz@cmemo@path}}%
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@write@empty@cmemo}
+% This macro is used to create an empty c-memo on aborted memoization, to
+% make sure that no leftover c-memo tricks Memoize into thinking that the
+% code was successfully memoized.
+\def\mmz@write@empty@cmemo{%
+ \immediate\openout\mmz@out{\mmz@cmemo@path}%
+ \immediate\closeout\mmz@out
+}
+% \end{macro}
+%
+%
+% \begin{macro}{\mmzSource}
+% The c-memo memoized code marker. This macro is synonymous with |\endinput|,
+% so the source following it is ignored when inputting the c-memo.
+\let\mmzSource\endinput
+% \end{macro}
+%
+% \begin{macro}{\mmz@process@cmemo}
+% This macro inputs the c-memo, which will update the context code, which we
+% can then compute the MD5 sum of.
+\def\mmz@process@cmemo{%
+ \mmz@trace@process@cmemo
+ % |\ifmmz@abort| serves as a signal that the c-memo exists and is of correct
+ % form.
+ \global\mmz@aborttrue
+ % If c-memo sets |\ifmmzUnmemoizable|, we will compile regularly.
+ \global\mmzUnmemoizablefalse
+ \def\mmzMemo{\global\mmz@abortfalse}%
+ % Just a safeguard \dots\ c-memo assigns to |\mmzContextExtra| anyway.
+ \global\mmzContextExtra{}%
+ % Input the c-memo, if it exists, and record that we have used it.
+ \IfFileExists{\mmz@cmemo@path}{%
+ \input{\mmz@cmemo@path}%
+ \pgfkeysalso{/mmz/record/used cmemo={\mmz@cmemo@path}}%
+ }{%
+ \mmz@trace@process@no@cmemo
+ }%
+ % Compute the context MD5 sum.
+ \mmz@compute@context@mdfivesum
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@compute@context@mdfivesum}
+% This macro computes the MD5 sum of the concatenation of |\mmzContext| and
+% |\mmzContextExtra|, and writes out the tracing info when |trace context| is
+% in effect. The argument is the tracing note.
+% \end{macro}
+\def\mmz@compute@context@mdfivesum{%
+ \xdef\mmz@context@key{\the\mmzContext\the\mmzContextExtra}%
+ % A special provision for padding, which occurs in the context by default,
+ % and may contain otherwise undefined macros referring to the extern
+ % dimensions. We make sure that when we expand the context key,
+ % |\mmz@paddings| contains the stringified |\width| etc., while these macros
+ % (which may be employed by the end user in the context expression), are
+ % returned to their original definitions.
+ \begingroup
+ \begingroup
+ \def\width{\string\width}%
+ \def\height{\string\height}%
+ \def\depth{\string\depth}%
+ \edef\mmz@paddings{\mmz@paddings}%
+ \expandafter\endgroup
+ \expandafter\def\expandafter\mmz@paddings\expandafter{\mmz@paddings}%
+ % We pre-expand the concatenated context, for tracing\slash inclusion in the
+ % cc-memo. In \hologo{LaTeX}, we protect the expansion, as the context
+ % expression may contain whatever.
+ %<latex>\protected@xdef
+ %<!latex>\xdef
+ \mmz@context@key{\mmz@context@key}%
+ \endgroup
+ % Compute the MD5 sum. We have to assign globally, because this macro is (also)
+ % called after inputting the c-memo, while the resulting MD5 sum is used to
+ % input the cc-memo, which happens outside the |\Memoize| group.
+ % |\mmz@context@mdfivesum|.
+ \xdef\mmz@context@mdfivesum{\pdf@mdfivesum{\expandonce\mmz@context@key}}%
+}
+%
+%
+% \subsection{Cc-memos}
+% \label{sec:code:cc-memo}
+%
+% \paragraph{The path} to a cc-memo consists of the path prefix, the
+% hyphen-separated MD5 sums of the memoized code and the (evaluated) context,
+% and suffix |.memo|.
+\def\mmz@ccmemo@path{%
+ \mmz@prefix@path\mmz@code@mdfivesum-\mmz@context@mdfivesum.memo}
+%
+% \paragraph{The structure} of a cc-memo:
+% \begin{itemize}
+% \item the list of resources consisting of calls to |\mmzResource|;
+% \item the core memo code (which includes the externs when executed),
+% introduced by marker |\mmzMemo|; and,
+% \item optionally, the context expansion, introduced by marker
+% |\mmzThisContext|.
+% \end{itemize}
+%
+% We begin the cc-memo with a list of extern files included by the core memo
+% code so that we can check whether these files exist prior to executing the
+% core memo code. Checking this on the fly, while executing the core memo
+% code, would be too late, as that code is arbitrary (and also executed outside
+% the |\Memoize| group).
+%
+% \begin{macro}{\mmzCCMemo}
+% During memoization, the core content of the cc-memo is collected into this
+% token register.
+\newtoks\mmzCCMemo
+% \end{macro}
+%
+% \begin{key}{include context in ccmemo}
+% \begin{macro}{\ifmmz@include@context}
+% Should we include the context expansion in the cc-memo? By default, no.
+% \bigskip
+\newif\ifmmz@include@context
+\mmzset{%
+ include context in ccmemo/.is if=mmz@include@context,
+}
+% \end{macro}
+% \end{key}
+%
+% \begin{key}{direct ccmemo input}
+% \begin{macro}{\ifmmz@direct@ccmemo@input}
+% When this conditional is false, the
+% cc-memo is read indirectly, via a token register, to facilitate
+% inverse search. \bigskip
+\newif\ifmmz@direct@ccmemo@input
+\mmzset{%
+ direct ccmemo input/.is if=mmz@direct@ccmemo@input,
+}
+% \end{macro}
+% \end{key}
+%
+% \begin{macro}{\mmz@write@ccmemo}
+% This macro creates the cc-memo from the list of resources in
+% |\mmz@ccmemo@resources| and the contents of |\mmzCCMemo|.
+\def\mmz@write@ccmemo{%
+ % Open the cc-memo file for writing. Note that the filename contains the
+ % context MD5 sum, which can only be computed after memoization, as the
+ % memoized code can update the context. This is one of the two reasons why
+ % we couldn't write the cc-memo directly into the file, but had to collect
+ % its contents into token register |\mmzCCMemo|.
+ \immediate\openout\mmz@out{\mmz@ccmemo@path}%
+ % Token register |\mmz@ccmemo@resources| consists of calls to
+ % |\mmz@ccmemo@append@resource|, so the following code writes down the list
+ % of created externs into the cc-memo. Wanting to have this list at the top
+ % of the cc-memo is the other reason for the roundabout creation of the
+ % cc-memo --- the resources become known only during memoization, as well.
+ \begingroup
+ \the\mmz@ccmemo@resources
+ \endgroup
+ % Write down the content of |\mmzMemo|, but first introduce it by the
+ % |\mmzMemo| marker.
+ \immediate\write\mmz@out{\noexpand\mmzMemo}%
+ \immediate\write\mmz@out{\the\mmzCCMemo\collargs@percentchar}%
+ % Write down the context tracing info when |include context in ccmemo| is in
+ % effect.
+ \ifmmz@include@context
+ \immediate\write\mmz@out{\noexpand\mmzThisContext}%
+ \immediate\write\mmz@out{\expandonce{\mmz@context@key}}%
+ \fi
+ % Insert the end-of-file marker and close the file.
+ \immediate\write\mmz@out{\noexpand\mmzEndMemo}%
+ \immediate\closeout\mmz@out
+ % Record that we wrote a new cc-memo.
+ \pgfkeysalso{/mmz/record/new ccmemo={\mmz@ccmemo@path}}%
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@ccmemo@append@resource}
+% Append the resource to the cc-memo (we are nice to external utilities and
+% put each resource on its own line). |#1| is the sequential number of the
+% extern belonging to the memoized code; below, we assign it to |\mmz@seq|,
+% which appears in |\mmz@extern@name|. Note that |\mmz@extern@name| only
+% contains the extern filename --- without the path, so that externs can be
+% used by several projects, or copied around.
+\def\mmz@ccmemo@append@resource#1{%
+ \mmz@seq=#1\relax
+ \immediate\write\mmz@out{%
+ \string\mmzResource{\mmz@extern@name}\collargs@percentchar}%
+}
+% \end{macro}
+%
+% \begin{macro}{\mmzResource}
+% A list of these macros is located at the top of a cc-memo. The macro
+% checks for the existence of the extern file, given as |#1|. If the extern
+% does not exist, we redefine |\mmzMemo| to |\endinput|, so that the core
+% content of the cc-memo is never executed; see also |\mmz@process@ccmemo|
+% above.
+\def\mmzResource#1{%
+ % We check for existence using |\pdffilesize|, because an empty PDF, which
+ % might be produced by a failed \hologo{TeX}-based extraction, should count
+ % as no file. The |0| behind |\ifnum| is there because |\pdffilesize|
+ % returns an empty string when the file does not exist.
+ \ifnum0\pdf@filesize{\mmz@dir@path/#1}=0
+ \ifmmz@direct@ccmemo@input
+ \let\mmzMemo\endinput
+ \else
+ % With indirect cc-memo input, we simulate end-of-input by grabbing
+ % everything up to the end-of-memo marker. In the indirect cc-memo
+ % input, a |\par| token shows up after |\mmzEndMemo|, I'm not sure why
+ % (|\everyeof={}| does not help).
+ \long\def\mmzMemo##1\mmzEndMemo\par{}%
+ \fi
+ \mmz@trace@resource{#1}%
+ \fi
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@process@ccmemo,\mmzThisContext,\mmzEndMemo}
+% This macro processes the cc-memo.
+\def\mmz@process@ccmemo{%
+ \mmz@trace@process@ccmemo
+ % The following conditional signals whether cc-memo was successfully
+ % utilized. If the cc-memo file does not exist, |\ifmmz@abort| will remain
+ % true. If it exists, it is headed by the list of resources. If a
+ % resource check fails, |\mmzMemo| (which follows the list of resources) is
+ % redefined to |\endinput|, so |\ifmmz@abort| remains true. However, if
+ % all resource checks are successful, |\mmzMemo| marker is reached with
+ % the below definition in effect, so |\ifmmz@abort| becomes false. Note
+ % that this marker also closes the |\Memoize| group, so that the core
+ % cc-memo content is executed in the original group --- and that this
+ % does not happen if anything goes wrong!
+ \global\mmz@aborttrue
+ % Note that |\mmzMemo| may be redefined by |\mmzResource| upon an unavailable
+ % extern file.
+ \def\mmzMemo{%
+ \endgroup
+ \global\mmz@abortfalse
+ % We |\let| the control sequence used for extern inclusion in the cc-memo to
+ % the macro which includes the extern from the extern file.
+ \let\mmzIncludeExtern\mmz@include@extern
+ }%
+ % Define |\mmzEndMemo| wrt |\ifmmz@direct@ccmemo@input|, whose value will be
+ % lost soon because |\mmMemo| will close the group --- that's also why this
+ % definition is global.
+ \xdef\mmzEndMemo{%
+ \ifmmz@direct@ccmemo@input
+ \noexpand\endinput
+ \else
+ % In the indirect cc-memo input, a |\par| token shows up after
+ % |\mmzEndMemo|, I'm not sure why (|\everyeof={}| does not help).
+ \unexpanded{%
+ \def\mmz@temp\par{}%
+ \mmz@temp
+ }%
+ \fi
+ }%
+ % The cc-memo context marker, again wrt |\ifmmz@direct@ccmemo@input| and
+ % globally. With direct cc-memo input, this macro is synonymous with
+ % |\endinput|, so the (expanded) context following it is ignored when
+ % inputting the cc-memo. With indirect input, we simulate end-of-input by
+ % grabbing everything up to the end-of-memo marker (plus gobble the |\par|
+ % mentioned above).
+ \xdef\mmzThisContext{%
+ \ifmmz@direct@ccmemo@input
+ \noexpand\endinput
+ \else
+ \unexpanded{%
+ \long\def\mmz@temp##1\mmzEndMemo\par{}%
+ \mmz@temp
+ }%
+ \fi
+ }%
+ % Input the cc-memo if it exists.
+ \IfFileExists{\mmz@ccmemo@path}{%
+ \ifmmz@direct@ccmemo@input
+ \input{\mmz@ccmemo@path}%
+ \else
+ % Indirect cc-memo input reads the cc-memo into a token register and
+ % executes the contents of this register.
+ \filetotoks\toks@{\mmz@ccmemo@path}%
+ \the\toks@
+ \fi
+ % Record that we have used the cc-memo.
+ \pgfkeysalso{/mmz/record/used ccmemo={\mmz@ccmemo@path}}%
+ }{%
+ \mmz@trace@process@no@ccmemo
+ }%
+ \ifmmz@abort
+ % The cc-memo doesn't exist, or some of the resources don't. We need to
+ % memoize, but we'll do it only if |readonly| is not in effect, otherwise
+ % we'll perform a regular compilation. (Note that we are still in the group
+ % opened prior to executing |\Memoize|.)
+ \mmz@trace@process@ccmemo@fail
+ \ifnum\mmz@mode=\mmz@mode@readonly\relax
+ \expandafter\expandafter\expandafter\mmz@compile
+ \else
+ \expandafter\expandafter\expandafter\mmz@memoize
+ \fi
+ \else
+ \mmz@trace@process@ccmemo@ok
+ \fi
+}
+% \end{macro}
+%
+% \subsection{The externs}
+% \label{sec:code:extern}
+%
+% \paragraph{The path} to an extern is like the path to a cc-memo, modulo
+% suffix |.pdf|, of course. However, in case memoization of a chunk produces
+% more than one extern, the filename of any non-first extern includes
+% |\mmz@seq|, the sequential number of the extern as well (we start the
+% numbering at $0$). We will have need for several parts of the full path to
+% an extern: the basename, the filename, the path without the suffix, and the
+% full path.
+\newcount\mmz@seq
+\def\mmz@extern@basename{%
+ \mmz@prefix\mmz@code@mdfivesum-\mmz@context@mdfivesum
+ \ifnum\mmz@seq>0 -\the\mmz@seq\fi
+}
+\def\mmz@extern@name{\mmz@extern@basename.pdf}
+\def\mmz@extern@basepath{\mmz@dir@path/\mmz@extern@basename}
+\def\mmz@extern@path{\mmz@extern@basepath.pdf}
+%
+% \begin{key}{padding left, padding right, padding top, padding bottom}
+% These options set the amount of space surrounding the bounding box of the
+% externalized graphics in the resulting PDF, i.e.\ in the extern file. This
+% allows the user to deal with \TikZ; overlays, |\rlap| and |\llap|, etc.
+\mmzset{
+ padding left/.store in=\mmz@padding@left,
+ padding right/.store in=\mmz@padding@right,
+ padding top/.store in=\mmz@padding@top,
+ padding bottom/.store in=\mmz@padding@bottom,
+% \end{key}
+%
+% \begin{key}{padding}
+% A shortcut for setting all four paddings at once.
+ padding/.style={
+ padding left=#1, padding right=#1,
+ padding top=#1, padding bottom=#1
+ },
+ % The default padding is what \hologo{pdfTeX} puts around the page anyway, 1
+ % inch, but we'll use |1 in| rather than |1 true in|, which is the true
+ % default value of |\pdfhorigin| and |\pdfvorigin|, as we want the padding to
+ % adjust with magnification.
+ padding=1in,
+% \end{key}
+%
+ % \begin{key}{padding to context}
+ % This key adds padding to the context. Note that we add the padding
+ % expression (|\mmz@paddings|, defined below, refers to all the individual
+ % padding macros), not the actual value (at the time of expansion). This
+ % is so because |\width|, |\height| and |\depth| are not defined outside
+ % extern shipout routines, and the context is evaluated elsewhere.
+ padding to context/.style={
+ context={padding=(\mmz@paddings)},
+ },
+ % \end{key}
+ %
+ % Padding nearly always belongs into the context --- the exception being
+ % memoized code which produces no externs (\MS\ref{sec:pure-memoization}) ---
+ % so we execute this key immediately.
+ padding to context,
+}
+\def\mmz@paddings{%
+ \mmz@padding@left,\mmz@padding@bottom,\mmz@padding@right,\mmz@padding@top
+}
+%
+% \begin{macro}{\mmzExternalizeBox}
+% This macro is the public interface to externalization. In Memoize itself,
+% it is called from the default memoization driver, |\mmzSingleExternDriver|,
+% but it should be called by any driver that wishes to produce an extern, see
+% \MS\ref{sec:memoization-drivers} for details. It takes two arguments:
+% \begin{enumerate}[\tt\#1]
+% \item The box that we want to externalize. It's content will remain intact.
+% The box may be given either as a control sequence, declared via |\newbox|,
+% or as box number (say, 0).
+% \item The token register which will receive the code that includes the extern
+% into the document; it is the responsibility of the memoization driver to
+% (globally) include the contents of the register in the cc-memo, i.e.\ in
+% token register |\mmzCCMemo|. This argument may be either a control
+% sequence, declared via |\newtoks|, or a |\toks|\meta{token register
+% number}.
+% \end{enumerate}
+\def\mmzExternalizeBox#1#2{%
+ \begingroup
+ % A courtesy to the user, so they can define padding in terms of the size of
+ % the externalized graphics.
+ \def\width{\wd#1 }%
+ \def\height{\ht#1 }%
+ \def\depth{\dp#1 }%
+ % Store the extern-inclusion code in a temporary macro, which will be
+ % smuggled out of the group.
+ \xdef\mmz@global@temp{%
+ % Executing |\mmzIncludeExtern| from the cc-memo will include the extern
+ % into the document.
+ \noexpand\mmzIncludeExtern
+ % |\mmzIncludeExtern| identifies the extern by its sequence number,
+ % |\mmz@seq|.
+ {\the\mmz@seq}%
+ % What kind of box? We |\noexpand| the answer just in case someone
+ % redefined them.
+ \ifhbox#1\noexpand\hbox\else\noexpand\vbox\fi
+ % The dimensions of the extern.
+ {\the\wd#1}%
+ {\the\ht#1}%
+ {\the\dp#1}%
+ % The padding values.
+ {\the\dimexpr\mmz@padding@left}%
+ {\the\dimexpr\mmz@padding@bottom}%
+ {\the\dimexpr\mmz@padding@right}%
+ {\the\dimexpr\mmz@padding@top}%
+ }%
+ % Prepend the new extern box into the global extern box where we collect all
+ % the externs of this memo. Note that we |\copy| the extern box, retaining
+ % its content --- we will also want to place the extern box in its regular
+ % place in the document.
+ \global\setbox\mmz@tbe@box\vbox{\copy#1\unvbox\mmz@tbe@box}%
+ % Add the extern to the list of resources, which will be included at the top
+ % of the cc-memo, to check whether the extern files exists at the time the
+ % cc-memo is utilized. In the cc-memo, the list will contain full extern
+ % filenames, which are currently unknown, but no matter; right now, providing
+ % the extern sequence number suffices, the full extern filename will be
+ % produced at the end of memoization, once the context MD5 sum is known.
+ \xtoksapp\mmz@ccmemo@resources{%
+ \noexpand\mmz@ccmemo@append@resource{\the\mmz@seq}%
+ }%
+ % Increment the counter containing the sequence number of the extern within
+ % this memo.
+ \global\advance\mmz@seq1
+ % Assign the extern-including code into the token register given in |#2|.
+ % This register may be given either as a control sequence or as
+ % |\toks|\meta{token register number}, and this is why we have temporarily
+ % stored the code (into |\mmz@global@temp|) globally: a local storage with
+ % |\expandafter\endgroup\expandafter| here would fail with the receiving
+ % token register given as |\toks|\meta{token register number}.
+ \endgroup
+ #2\expandafter{\mmz@global@temp}%
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@ccmemo@resources}
+% This token register, populated by |\mmz@externalize@box| and used by
+% |\mmz@write@ccmemo|, holds the list of externs produced by memoization of
+% the current chunk.
+\newtoks\mmz@ccmemo@resources
+% \end{macro}
+%
+% \begin{macro}{\mmz@tbe@box}
+% |\mmz@externalize@box| does not directly dump the extern into the document
+% (as a special page). Rather, the externs are collected into
+% |\mmz@tbe@box|, whose contents are dumped into the document at the end of
+% memoization of the current chunk. In this way, we guarantee that aborted
+% memoization does not pollute the document.
+\newbox\mmz@tbe@box
+% \end{macro}
+%
+% \begin{macro}{\mmz@shipout@externs}
+% This macro is executed at the end of
+% memoization, when the externs are waiting for us in |\mmz@tbe@box| and need
+% to be dumped into the document. It loops through the contents of
+% |\mmz@tbe@box|,\footnote{The looping code is based on TeX.SE
+% answer \url(https://){tex.stackexchange.com/a/25142/16819} by Bruno Le
+% Floch.}, putting each extern into |\mmz@box| and calling
+% |\mmz@shipout@extern|. Note that the latter macro is executed within the
+% group opened by |\vbox| below.
+\def\mmz@shipout@externs{%
+ \global\mmz@seq 0
+ \setbox\mmz@box\vbox{%
+ % Set the macros below to the dimensions of the extern box, so that the
+ % user can refer to them in the padding specification (which is in turn
+ % used in the page setup in |\mmz@shipout@extern|).
+ \def\width{\wd\mmz@box}%
+ \def\height{\ht\mmz@box}%
+ \def\depth{\dp\mmz@box}%
+ \vskip1pt
+ \ifmmzkeepexterns\expandafter\unvcopy\else\expandafter\unvbox\fi\mmz@tbe@box
+ \@whilesw\ifdim0pt=\lastskip\fi{%
+ \setbox\mmz@box\lastbox
+ \mmz@shipout@extern
+ }%
+ }%
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@shipout@extern}
+% This macro ships out a single extern, which
+% resides in |\mmz@box|, and records the creation of the new extern.
+\def\mmz@shipout@extern{%
+ % Calculate the expected width and height. We have to do this now, before we
+ % potentially adjust the box size and paddings for magnification.
+ \edef\expectedwidth{\the\dimexpr
+ (\mmz@padding@left) + \wd\mmz@box + (\mmz@padding@right)}%
+ \edef\expectedheight{\the\dimexpr
+ (\mmz@padding@top) + \ht\mmz@box + \dp\mmz@box + (\mmz@padding@bottom)}%
+ % Apply the inverse magnification, if |\mag| is not at the default
+ % value. We'll do this in a group, which will last until shipout.
+ \begingroup
+ \ifnum\mag=1000
+ \else
+ \mmz@shipout@mag
+ \fi
+ % Setup the geometry of the extern page. In \hologo{plainTeX} and
+ % \hologo{LaTeX}, setting |\pdfpagewidth| and |\pdfpageheight| seems to do
+ % the trick of setting the extern page dimensions. In \hologo{ConTeXt},
+ % however, the resulting extern page ends up with the PDF |/CropBox|
+ % specification of the current regular page, which is then used (ignoring our
+ % |mediabox| requirement) when we're including the extern into the document
+ % by |\mmzIncludeExtern|. Typically, this results in a page-sized extern.
+ % I'm not sure how to deal with this correctly. In the workaround below, we
+ % use Lua function |backends.codeinjections.setupcanvas| to set up page
+ % dimensions: we first remember the current page dimensions
+ % (|\edef\mmz@temp|), then set up the extern page dimensions
+ % (|\expanded{...}|), and finally, after shipping
+ % out the extern page, revert to the current page dimensions by executing
+ % |\mmz@temp| at the very end of this macro.
+ %<*plain,latex>
+ \pdfpagewidth\dimexpr
+ (\mmz@padding@left) + \wd\mmz@box + (\mmz@padding@right)\relax
+ \pdfpageheight\dimexpr
+ (\mmz@padding@top) + \ht\mmz@box + \dp\mmz@box+ (\mmz@padding@bottom)\relax
+ %</plain,latex>
+ %<*context>
+ \edef\mmz@temp{%
+ \noexpand\directlua{
+ backends.codeinjections.setupcanvas({
+ paperwidth=\the\numexpr\pagewidth,
+ paperheight=\the\numexpr\pageheight
+ })
+ }%
+ }%
+ \expanded{%
+ \noexpand\directlua{
+ backends.codeinjections.setupcanvas({
+ paperwidth=\the\numexpr\dimexpr
+ \mmz@padding@left + \wd\mmz@box + \mmz@padding@right\relax,
+ paperheight=\the\numexpr\dimexpr
+ \mmz@padding@top + \ht\mmz@box + \dp\mmz@box+ \mmz@padding@bottom\relax
+ })
+ }%
+ }%
+ %</context>
+ %
+ % We complete the page setup by setting the content offset.
+ \hoffset\dimexpr\mmz@padding@left - \pdfhorigin\relax
+ \voffset\dimexpr\mmz@padding@top - \pdfvorigin\relax
+ % We shipout the extern page using the |\shipout| primitive, so that the
+ % extern page is not modified, or even registered, by the shipout code of the
+ % format or some package. I can't imagine those shipout routines ever
+ % needing to know about the extern page. In fact, most often knowing about
+ % it would be undesirable. For example, \hologo{LaTeX} and \hologo{ConTeXt}
+ % count the ``real'' pages, but usually to know whether they are shipping out
+ % an odd or an even page, or to make the total number of pages available to
+ % subsequent compilations. Taking the extern pages into account would
+ % disrupt these mechanisms.
+ %
+ % Another thing: delayed |\write|s. We have to make sure that any
+ % \hologo{LaTeX}-style protected stuff in those is not expanded. We don't
+ % bother introducing a special group, as we'll close the |\mag| group right
+ % after the shipout anyway.
+ %<latex>\let\protect\noexpand
+ \pdf@primitive\shipout\box\mmz@box
+ %<context>\mmz@temp
+ \endgroup
+ % Advance the counter of shipped-out externs. We do this before preparing
+ % the recording information below, because the extern extraction tools expect
+ % the extern page numbering to start with $1$.
+ \global\advance\mmzExternPages1
+ % Prepare the macros which may be used in |record/<type>/new extern| code.
+ \edef\externbasepath{\mmz@extern@basepath}%
+ % Adding up the counters below should result in the real page number of the
+ % extern. Macro |\mmzRegularPages| holds the number of pages which were
+ % shipped out so far using the regular shipout routine of the format;
+ % |\mmzExternPages| holds the number of shipped-out extern pages; and
+ % |\mmzExtraPages| holds, or at least should hold, the number of pages
+ % shipped out using any other means.
+ \edef\pagenumber{\the\numexpr\mmzRegularPages
+ % In \hologo{LaTeX}, the |\mmzRegularPages| holds to number of pages
+ % already shipped out. In \hologo{ConTeXt}, the counter is already
+ % increased while processing the page, so we need to subtract $1$.
+%<context> -1%
+ +\mmzExternPages+\mmzExtraPages}%
+ % Record the creation of the new extern. We do this after shipping out the
+ % extern page, so that the recording mechanism can serve as an after-shipout
+ % hook, for the unlikely situation that some package really needs to do
+ % something when our shipout happens. Note that we absolutely refuse to
+ % provide a before-shipout hook, because we can't allow anyone messing with
+ % our extern, and that using this after-shipout ``hook'' is unnecessary for
+ % counting extern shipouts, as we already provide this information in the
+ % public counter |\mmzExternPages|.
+ \mmzset{record/new extern/.expanded=\mmz@extern@path}%
+ % Advance the sequential number of the extern, in the context of the current
+ % memoized code chunk. This extern numbering starts at 0, so we only do this
+ % after we wrote the cc-memo and called |record/new extern|.
+ \global\advance\mmz@seq1
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@shipout@mag}
+% This macro applies the inverse magnification, so that the extern ends up
+% with its natural size on the extern page.
+\def\mmz@shipout@mag{%
+ % We scale the extern box using the PDF primitives: |q| and |Q| save and
+ % restore the current graphics state; |cm| applies the given coordinate
+ % transformation matrix. ($a$ $b$ $c$ $d$ $e$ $f$ |cm| transforms $(x,y)$
+ % into $(ax+cy+e,bx+dy+f)$.)
+ \setbox\mmz@box\hbox{%
+ \pdfliteral{q \mmz@inverse@mag\space 0 0 \mmz@inverse@mag\space 0 0 cm}%
+ \copy\mmz@box\relax
+ \pdfliteral{Q}%
+ }%
+ % We first have to scale the paddings, as they might refer to the |\width|
+ % etc.\ of the extern.
+ \dimen0=\dimexpr\mmz@padding@left\relax
+ \edef\mmz@padding@left{\the\dimexpr\mmz@inverse@mag\dimen0}%
+ \dimen0=\dimexpr\mmz@padding@bottom\relax
+ \edef\mmz@padding@bottom{\the\dimexpr\mmz@inverse@mag\dimen0}%
+ \dimen0=\dimexpr\mmz@padding@right\relax
+ \edef\mmz@padding@right{\the\dimexpr\mmz@inverse@mag\dimen0}%
+ \dimen0=\dimexpr\mmz@padding@top\relax
+ \edef\mmz@padding@top{\the\dimexpr\mmz@inverse@mag\dimen0}%
+ % Scale the extern box.
+ \wd\mmz@box=\mmz@inverse@mag\wd\mmz@box\relax
+ \ht\mmz@box=\mmz@inverse@mag\ht\mmz@box\relax
+ \dp\mmz@box=\mmz@inverse@mag\dp\mmz@box\relax
+}
+% \end{macro}
+%
+% \begin{macro}{\mmz@inverse@mag}
+% The inverse magnification factor, i.e.\ the number we have to multiply the
+% extern dimensions with so that they will end up in their natural size. We
+% compute it, once and for all, at the beginning of the document. To do
+% that, we borrow the little macro |\Pgf@geT| from |pgfutil-common| (but
+% rename it).
+{\catcode`\p=12\catcode`\t=12\gdef\mmz@Pgf@geT#1pt{#1}}
+\mmzset{begindocument/.append code={%
+ \edef\mmz@inverse@mag{\expandafter\mmz@Pgf@geT\the\dimexpr 1000pt/\mag}%
+ }}
+% \end{macro}
+%
+% \begin{macro}{\mmzRegularPages}
+% This counter holds the number of pages shipped out by the format's shipout
+% routine. \hologo{LaTeX} and \hologo{ConTeXt} keep track of this in
+% dedicated counters, so we simply use those. In \hologo{plainTeX}, we have
+% to hack the |\shipout| macro to install our own counter. In fact, we
+% already did this while loading the required packages, in order to avoid it
+% being redefined by |atbegshi| first. All that is left to do here is to
+% declare the counter.
+%<latex>\let\mmzRegularPages\ReadonlyShipoutCounter
+%<context>\let\mmzRegularPages\realpageno
+%<plain>\newcount\mmzRegularPages
+% \end{macro}
+%
+% \begin{macro}{\mmzExternPages}
+% This counter holds the number of extern pages shipped out so far.
+\newcount\mmzExternPages
+% \end{macro}
+%
+% The total number of new externs is announced at the end of the compilation,
+% so that \hologo{TeX} editors, |latexmk| and such can propose recompilation.
+\mmzset{
+ enddocument/afterlastpage/.append code={%
+ \ifnum\mmzExternPages>0
+ \PackageWarning{memoize}{The compilation produced \the\mmzExternPages\space
+ new extern\ifnum\mmzExternPages>1 s\fi.}%
+ \fi
+ },
+}
+%
+% \begin{macro}{\mmzExtraPages}
+% This counter will probably remain at zero forever. It should be advanced by
+% any package which (like Memoize) ships out pages bypassing the regular
+% shipout routine of the format.
+\newcount\mmzExtraPages
+% \end{macro}
+%
+% \begin{macro}{\mmz@include@extern}
+% This macro, called from cc-memos as |\mmzIncludeExtern|, inserts an extern
+% file into the document. |#1| is the sequential number, |#2| is either
+% |\hbox| or |\vbox|, |#3|, |#4| and |#5| are the (expected) width, height
+% and the depth of the externalized box; |#6|--|#9| are the paddings (left,
+% bottom, right, and top).
+\def\mmz@include@extern#1#2#3#4#5#6#7#8#9{%
+ % Set the extern sequential number, so that we open the correct extern file
+ % (|\mmz@extern@basename|).
+ \mmz@seq=#1\relax
+ % Use the primitive PDF graphics inclusion commands to include the extern
+ % file. Set the correct depth or the resulting box, and shift it as
+ % specified by the padding.
+ \setbox\mmz@box=#2{%
+ \setbox0=\hbox{%
+ \lower\dimexpr #5+#7\relax\hbox{%
+ \hskip -#6\relax
+ \setbox0=\hbox{%
+ \mmz@insertpdfpage{\mmz@extern@path}{1}%
+ }%
+ \unhbox0
+ }%
+ }%
+ \wd0 \dimexpr\wd0-#8\relax
+ \ht0 \dimexpr\ht0-#9\relax
+ \dp0 #5\relax
+ \box0
+ }%
+ % Check whether the size of the included extern is as expected. There is no
+ % need to check |\dp|, we have just set it. (|\mmz@if@roughly@equal| is
+ % defined in section~\ref{sec:code:extract:tex}.)
+ \mmz@tempfalse
+ \mmz@if@roughly@equal{\mmz@tolerance}{#3}{\wd\mmz@box}{%
+ \mmz@if@roughly@equal{\mmz@tolerance}{#4}{\ht\mmz@box}{%
+ \mmz@temptrue
+ }{}}{}%
+ \ifmmz@temp
+ \else
+ \mmz@use@memo@warning{\mmz@extern@path}{#3}{#4}{#5}%
+ \fi
+ % Use the extern box, with the precise size as remembered at memoization.
+ \wd\mmz@box=#3\relax
+ \ht\mmz@box=#4\relax
+ \box\mmz@box
+ % Record that we have used this extern.
+ \pgfkeysalso{/mmz/record/used extern={\mmz@extern@path}}%
+}
+% \end{macro}
+\def\mmz@use@memo@warning#1#2#3#4{%
+ \PackageWarning{memoize}{Unexpected size of extern "#1";
+ expected #2\space x \the\dimexpr #3+#4\relax,
+ got \the\wd\mmz@box\space x \the\dimexpr\the\ht\mmz@box+\the\dp\mmz@box\relax}%
+}
+% \begin{macro}{\mmz@insertpdfpage}
+% This macro inserts a page from the PDF into the document. We define it
+% according to which engine is being used. Note that \hologo{ConTeXt} always
+% uses \hologo{LuaTeX}.
+%<latex,plain>\ifdef\luatexversion{%
+ \def\mmz@insertpdfpage#1#2{% #1 = filename, #2 = page number
+ \saveimageresource page #2 mediabox {#1}%
+ \useimageresource\lastsavedimageresourceindex
+ }%
+%<*latex,plain>
+}{%
+ \ifdef\XeTeXversion{%
+ \def\mmz@insertpdfpage#1#2{%
+ \XeTeXpdffile #1 page #2 media
+ }%
+ }{% pdfLaTeX
+ \def\mmz@insertpdfpage#1#2{%
+ \pdfximage page #2 mediabox {#1}%
+ \pdfrefximage\pdflastximage
+ }%
+ }%
+}
+%</latex,plain>
+% \end{macro}
+%
+% \begin{macro}{\mmz@include@extern@from@tbe@box}
+% Include the extern number |#1| residing in |\mmz@tbe@box| into the
+% document. This helper macro makes it possible for a complex memoization
+% driver to process the cc-memo right after memoization --- by using the
+% |\mmzkeepexternstrue\xtoksapp\mmzAfterMemoizationExtra{\the\mmzCCMemo}|
+% trick --- to ensure that the result of the memoizing compilation matches
+% the result of inputting the cc-memo. The rest of the arguments are
+% gobbled, as we don't have to do any size adjustment or checking here, and
+% the box is of the correct type.
+\def\mmz@include@extern@from@tbe@box#1#2#3#4#5#6#7#8#9{%
+ \setbox0\vbox{%
+ \@tempcnta#1\relax
+ \vskip1pt
+ \unvcopy\mmz@tbe@box
+ \@whilenum\@tempcnta>0\do{%
+ \setbox0\lastbox
+ \advance\@tempcnta-1\relax
+ }%
+ \global\setbox1\lastbox
+ \@whilesw\ifdim0pt=\lastskip\fi{%
+ \setbox0\lastbox
+ }%
+ \box\mmz@box
+ }%
+ \box1
+}
+% \end{macro}
+%
+% \section{Extraction}
+% \label{sec:code:extract}
+%
+% \subsection{Extraction mode and method}
+% \label{sec:code:extraction-mode-method}
+%
+% \begin{key}{extract}
+% This key selects the extraction mode and method. It normally occurs in the
+% package options list, less commonly in the preamble, and never in the
+% document body.
+\def\mmzvalueof#1{\pgfkeysvalueof{/mmz/#1}}
+\mmzset{
+ extract/.estore in=\mmz@extraction@method,
+ extract/.value required,
+ begindocument/.append style={extract/.code=\mmz@preamble@only@warning},
+ % \end{key}
+ %
+ % \begin{key}{extract/perl, extract/python}
+ % Any other value will select internal extraction with the given method.
+ % Memoize ships with two extraction scripts, a Perl script and a Python
+ % script, which are selected by |extract=perl| (the default) and
+ % |extract=python|, respectively. We run the scripts in verbose mode
+ % (without |-q|), and keep the |.mmz| file as is, i.e.\ we're not commenting
+ % out the |\mmzNewExtern| lines, because we're about to overwrite it
+ % anyway. We also request the log file, which will contain
+ % |\mmzExtractionSuccessful| if extraction was successful.
+ extract/perl/.code={%
+ \mmz@clear@extraction@log
+ \pdf@system{%
+ \mmzvalueof{perl extraction command}\space
+ \mmzvalueof{perl extraction options}%
+ }%
+ \mmz@check@extraction@log{perl}%
+ \def\mmz@mkdir@command##1{\mmzvalueof{perl extraction command}\space --mkdir "##1"}%
+ },
+ perl extraction command/.initial=memoize-extract.pl,
+ perl extraction options/.initial={%
+% \begin{listingregion}{perl-extraction-options.tex}
+ -e -l "\mmzOutputDirectory\mmzUnquote\jobname.mmz.log" -w
+ %<latex>"\string\PackageWarning{memoize (perl-based extraction)}{\string\warningtext}"
+ %<plain>"\string\warning{memoize (perl-based extraction): \string\warningtext}"
+ %<context>"\string\warning{memoize (perl-based extraction): \string\warningtext}"
+ "\mmzOutputDirectory\mmzUnquote\jobname.mmz"
+% \end{listingregion}
+ },
+ extract=perl,
+ extract/python/.code={%
+ \mmz@clear@extraction@log
+ \pdf@system{%
+ \mmzvalueof{python extraction command}\space
+ \mmzvalueof{python extraction options}%
+ }%
+ \mmz@check@extraction@log{python}%
+ \def\mmz@mkdir@command##1{\mmzvalueof{python extraction command}\space --mkdir "##1"}%
+ },
+ python extraction command/.initial=memoize-extract.py,
+ python extraction options/.initial={%
+ -e -l "\mmzOutputDirectory\mmzUnquote\jobname.mmz.log" -w
+ %<latex>"\string\PackageWarning{memoize (python-based extraction)}{\string\warningtext}"
+ %<plain>"\string\warning{memoize (python-based extraction): \string\warningtext}"
+ %<context>"\string\warning{memoize (python-based extraction): \string\warningtext}"
+ "\mmzOutputDirectory\mmzUnquote\jobname.mmz"
+ },
+}
+\def\mmz@preamble@only@warning{%
+ \PackageWarning{memoize}{%
+ Ignoring the invocation of "\pgfkeyscurrentkey".
+ This key may only be executed in the preamble}%
+}
+% \end{key}
+%
+% \paragraph*{The extraction log}
+% As we cannot access the exit status of a system command in \hologo{TeX}, we
+% communicate with the system command via the ``extraction log file,'' produced
+% by both \hologo{TeX}-based extraction and the Perl and Python extraction
+% script. This file signals whether the embedded extraction was successful ---
+% if it is, the file contains |\mmzExtractionSuccessful| --- and also contains
+% any size-mismatch warnings (these are currently only thrown by the
+% \hologo{TeX}-based extraction). As the log is really a \hologo{TeX} file,
+% the idea is to simply input it after extracting each extern (for
+% \hologo{TeX}-based extraction) or after the extraction of all externs (for
+% the external scripts).
+\def\mmz@clear@extraction@log{%
+ \begingroup
+ \immediate\openout0{\mmzUnquote\jobname.mmz.log"}%
+ \immediate\closeout0
+ \endgroup
+}
+% |#1| is the extraction method.
+\def\mmz@check@extraction@log#1{%
+ \begingroup \def\extractionmethod{#1}%
+ \mmz@tempfalse \let\mmz@orig@endinput\endinput
+ \def\endinput{\mmz@temptrue\mmz@orig@endinput}%
+ \@input{\jobname.mmz.log}%
+ \ifmmz@temp \else \mmz@extraction@error \fi \endgroup }
+\def\mmz@extraction@error{%
+ \PackageWarning{memoize}{Extraction of externs from document "\mmzUnquote\jobname.pdf"
+ using method "\extractionmethod" was unsuccessful. Have you set the
+ shell escape mode as suggested in chapter 1 of the manual?}{}}
+%
+% \subsection{The record files}
+% \label{sec:code:record}
+%
+% \begin{key}{record}
+% This key activates a record \meta{type}: the hooks defined by that record
+% \meta{type} will henceforth be executed at the appropriate places.
+%
+% A \meta{hook} of a particular \meta{type} resides in |pgfkeys| path
+% |/mmz/record/|\meta{type}|/|\meta{hook}, and is invoked via
+% |/mmz/record/|\meta{hook}. Record type activation thus appends a call of
+% the former to the latter. It does so using handler |.try|, so that
+% unneeded hooks may be left undefined.
+%
+\mmzset{
+ record/.style={%
+ record/begin/.append style={
+ /mmz/record/#1/begin/.try,
+ % The |begin| hook also executes the |prefix| hook, so that |\mmzPrefix|
+ % surely occurs at the top of the |.mmz| file. Listing each prefix type
+ % separately in this hook ensures that |prefix| of a certain type is
+ % executed after that type's |begin|.
+ /mmz/record/#1/prefix/.try/.expanded=\mmz@prefix@path,
+ },
+ record/prefix/.append style={/mmz/record/#1/prefix/.try={##1}},
+ record/new extern/.append style={/mmz/record/#1/new extern/.try={##1}},
+ record/used extern/.append style={/mmz/record/#1/used extern/.try={##1}},
+ record/new cmemo/.append style={/mmz/record/#1/new cmemo/.try={##1}},
+ record/new ccmemo/.append style={/mmz/record/#1/new ccmemo/.try={##1}},
+ record/used cmemo/.append style={/mmz/record/#1/used cmemo/.try={##1}},
+ record/used ccmemo/.append style={/mmz/record/#1/used ccmemo/.try={##1}},
+ record/end/.append style={/mmz/record/#1/end/.try},
+ },
+}
+% \end{key}
+%
+% \begin{key}{no record}
+% This key deactivates all record types. Below, we use it to initialize the
+% relevant keys; in the user code, it may be used to deactivate the
+% preactivated |mmz| record type.
+\mmzset{
+ no record/.style={%
+ % The |begin| hook clears itself after invocation, to prevent double
+ % execution. Consequently, |record/begin| may be executed by the user in
+ % the preamble, without any ill effects.
+ record/begin/.style={record/begin/.style={}},
+ % The |prefix| key invokes itself again when the group closes. This way,
+ % we can correctly track the path prefix changes in the |.mmz| even if
+ % |path| is executed in a group.
+ record/prefix/.code={\aftergroup\mmz@record@prefix},
+ record/new extern/.code={},
+ record/used extern/.code={},
+ record/new cmemo/.code={},
+ record/new ccmemo/.code={},
+ record/used cmemo/.code={},
+ record/used ccmemo/.code={},
+ % The |end| hook clears itself after invocation, to prevent double
+ % execution. Consequently, |record/end| may be executed by the user before
+ % the end of the document, without any ill effects.
+ record/end/.style={record/end/.code={}},
+ }
+}
+% \end{key}
+% We define this macro because |\aftergroup|, used in |record/prefix|, only
+% accepts a token.
+\def\mmz@record@prefix{%
+ \mmzset{/mmz/record/prefix/.expanded=\mmz@prefix@path}%
+}
+% \paragraph{Initialize} the hook keys, preactivate |mmz| record type, and
+% execute hooks |begin| and |end| at the edges of the document.
+\mmzset{
+ no record,
+ record=mmz,
+ begindocument/.append style={record/begin},
+ enddocument/afterlastpage/.append style={record/end},
+}
+%
+% \subsubsection{The \texttt{.mmz} file}
+% \label{sec:code:record:mmz}
+%
+% Think of the |.mmz| record file as a \hologo{TeX}-readable log file, which
+% lets the extraction procedure know what happened in the previous compilation.
+% The file is in \hologo{TeX} format, so that we can trigger internal
+% \hologo{TeX}-based extraction by simply inputting it. The commands it
+% contains are intentionally as simple as possible (just a macro plus braced
+% arguments), to facilitate parsing by the external scripts.
+%
+% These hooks simply put the calls of the corresponding macros into the file.
+% All but hooks but |begin| and |end| receive the full path to the relevant
+% file as the only argument (ok, |prefix| receives the full path prefix, as set
+% by key |path|).
+%
+% \begin{key}{record/mmz/...}
+\mmzset{
+ record/mmz/begin/.code={%
+ \newwrite\mmz@mmzout
+ % The record file has a fixed name (the jobname plus the |.mmz| suffix) and
+ % location (the current directory, i.e.\ the directory where \hologo{TeX}
+ % is executed from; usually, this will be the directory containing the
+ % \hologo{TeX} source).
+ \immediate\openout\mmz@mmzout{\jobname.mmz}%
+ },
+ % The |\mmzPrefix| is used by the clean-up script, which will remove all
+ % files with the given path prefix but (unless called with |--all|) those
+ % mentioned in the |.mmz|. Now this script could in principle figure out
+ % what to remove by inspecting the paths to utilized\slash created
+ % memos\slash externs in the |.mmz| file, but this method could lead to
+ % problems in case of an incomplete (perhaps empty) |.mmz| file created by a
+ % failed compilation. Recording the path prefix in the |.mmz| radically
+ % increases the chances of a successful clean-up, which is doubly important,
+ % because a clean-up is sometimes precisely what we need to do to recover
+ % after a failed compilation.
+ record/mmz/prefix/.code={%
+ \immediate\write\mmz@mmzout{\noexpand\mmzPrefix{#1}}%
+ },
+ record/mmz/new extern/.code={%
+ % While this key receives a single formal argument, Memoize also prepares
+ % macros |\externbasepath| (|#1| without the |.pdf| suffix), |\pagenumber|
+ % (of the extern page in the document PDF), and |\expectedwidth| and
+ % |\expectedheight| (of the extern page).
+ \immediate\write\mmz@mmzout{%
+ \noexpand\mmzNewExtern{#1}{\pagenumber}{\expectedwidth}{\expectedheight}%
+ }%
+ },
+ record/mmz/new cmemo/.code={%
+ \immediate\write\mmz@mmzout{\noexpand\mmzNewCMemo{#1}}%
+ },
+ record/mmz/new ccmemo/.code={%
+ \immediate\write\mmz@mmzout{\noexpand\mmzNewCCMemo{#1}}%
+ },
+ record/mmz/used extern/.code={%
+ \immediate\write\mmz@mmzout{\noexpand\mmzUsedExtern{#1}}%
+ },
+ record/mmz/used cmemo/.code={%
+ \immediate\write\mmz@mmzout{\noexpand\mmzUsedCMemo{#1}}%
+ },
+ record/mmz/used ccmemo/.code={%
+ \immediate\write\mmz@mmzout{\noexpand\mmzUsedCCMemo{#1}}%
+ },
+ record/mmz/end/.code={%
+ % Add the |\endinput| marker to signal that the file is complete.
+ \immediate\write\mmz@mmzout{\noexpand\endinput}%
+ \immediate\closeout\mmz@mmzout
+ },
+ %
+ % \end{key}
+ % \subsubsection{The shell scripts}
+%
+% We define two shell script record types: |sh| for Linux, and |bat| for
+% Windows.
+%
+% \begin{key}{sh, bat}
+% These keys set the shell script filenames.
+% \bigskip
+ sh/.store in=\mmz@shname,
+ sh=memoize-extract.\jobname.sh,
+ bat/.store in=\mmz@batname,
+ bat=memoize-extract.\jobname.bat,
+% \end{key}
+%
+% \begin{key}{record/sh/...} Define the Linux shell script record type.
+ record/sh/begin/.code={%
+ \newwrite\mmz@shout
+ \immediate\openout\mmz@shout{\mmz@shname}%
+ },
+ record/sh/new extern/.code={%
+ \begingroup
+ % Macro |\mmz@tex@extraction@systemcall| is customizable through |tex
+ % extraction command|, |tex extraction options| and |tex extraction
+ % script|.
+ \immediate\write\mmz@shout{\mmz@tex@extraction@systemcall}%
+ \endgroup
+ },
+ record/sh/end/.code={%
+ \immediate\closeout\mmz@shout
+ },
+% \end{key}
+%
+% \begin{key}{record/bat/...}
+% Rinse and repeat for Windows.
+ record/bat/begin/.code={%
+ \newwrite\mmz@batout
+ \immediate\openout\mmz@batout{\mmz@batname}%
+ },
+ record/bat/new extern/.code={%
+ \begingroup
+ \immediate\write\mmz@batout{\mmz@tex@extraction@systemcall}%
+ \endgroup
+ },
+ record/bat/end/.code={%
+ \immediate\closeout\mmz@batout
+ },
+% \end{key}
+%
+% \subsubsection{The Makefile}
+%
+% The implementation of the Makefile record type is the most complex so far, as
+% we need to keep track of the targets.
+%
+% \begin{key}{makefile}
+% This key sets the makefile filename.
+ makefile/.store in=\mmz@makefilename,
+ makefile=memoize-extract.\jobname.makefile,
+}
+% \end{key}
+%
+% We need to define a macro which expands to the tab character of catcode
+% ``other'', to use as the recipe prefix.
+\begingroup
+\catcode`\^^I=12
+\gdef\mmz@makefile@recipe@prefix{^^I}%
+\endgroup
+% \begin{key}{record/makefile/...}
+% Define the Makefile record type.
+\mmzset{
+ record/makefile/begin/.code={%
+ % We initialize the record type by opening the file and setting makefile
+ % variables |.DEFAULT_GOAL| and |.PHONY|.
+ \newwrite\mmz@makefileout
+ \newtoks\mmz@makefile@externs
+ \immediate\openout\mmz@makefileout{\mmz@makefilename}%
+ \immediate\write\mmz@makefileout{.DEFAULT_GOAL = externs}%
+ \immediate\write\mmz@makefileout{.PHONY: externs}%
+ },
+ % The crucial part, writing out the extraction rule. The target comes first,
+ % then the recipe, which is whatever the user has set by |tex extraction
+ % command|, |tex extraction options| and |tex extraction script|.
+ record/makefile/new extern/.code={%
+ % The target extern file:
+ \immediate\write\mmz@makefileout{#1:}%
+ \begingroup
+ % The recipe is whatever the user set by |tex extraction
+ % command|, |tex extraction options| and |tex extraction script|.
+ \immediate\write\mmz@makefileout{%
+ \mmz@makefile@recipe@prefix\mmz@tex@extraction@systemcall}%
+ \endgroup
+ % Append the extern file to list of targets.
+ \xtoksapp\mmz@makefile@externs{#1\space}%
+ },
+ record/makefile/end/.code={%
+ % Before closing the file, we list the extern files as the prerequisites of
+ % our phony default target, |externs|.
+ \immediate\write\mmz@makefileout{externs: \the\mmz@makefile@externs}%
+ \immediate\closeout\mmz@makefileout
+ },
+}
+% \end{key}
+%
+%
+% \subsection{\hologo{TeX}-based extraction}
+% \label{sec:code:extract:tex}
+%
+% \begin{key}{extract/tex}
+% We trigger the \hologo{TeX}-based extraction by inputting the |.mmz| record
+% file.
+\mmzset{
+ extract/tex/.code={%
+ \begingroup
+ \@input{\jobname.mmz}%
+ \endgroup
+ },
+}
+% \end{key}
+%
+% \begingroup
+% \setlength\MacroIndent{2em}
+% \begin{macro}{\mmzUsedCMemo,\mmzUsedCCMemo,\mmzUsedExtern,\mmzNewCMemo,\mmzNewCCMemo,\mmzPrefix}
+% We can ignore everything but |\mmzNewExtern|s. All these macros receive a
+% single argument.
+\def\mmzUsedCMemo#1{}
+\def\mmzUsedCCMemo#1{}
+\def\mmzUsedExtern#1{}
+\def\mmzNewCMemo#1{}
+\def\mmzNewCCMemo#1{}
+\def\mmzPrefix#1{}
+% \end{macro}
+% \endgroup
+%
+% \begin{macro}{\mmzNewExtern}
+% Command |\mmzNewExtern| takes four arguments. It instructs us to extract
+% page |#2| of document |\jobname.pdf| to file |#1|. During the extraction,
+% we will check whether the size of the extern matches the given expected
+% width (|#3|) and total height (|#4|).
+%
+% We perform the extraction by an embedded \hologo{TeX} call. The system
+% command that gets executed is stored in |\mmz@tex@extraction@systemcall|,
+% which is set by |tex extraction command| and friends; by default, we
+% execute |pdftex|.
+%
+\def\mmzNewExtern#1{%
+ % The \hologo{TeX} executable expects the basename as the argument, so we
+ % strip away the |.pdf| suffix.
+ \mmz@new@extern@i#1\mmz@temp
+}
+\def\mmz@new@extern@i#1.pdf\mmz@temp#2#3#4{%
+ \begingroup
+ % Define the macros used in |\mmz@tex@extraction@systemcall|.
+ \def\externbasepath{#1}%
+ \def\pagenumber{#2}%
+ \def\expectedwidth{#3}%
+ \def\expectedheight{#4}%
+ % Empty out the extraction log.
+ \mmz@clear@extraction@log
+ % Extract.
+ \pdf@system{\mmz@tex@extraction@systemcall}%
+ % Was the extraction successful? We temporarily redefine the extraction
+ % error message macro (suited for the external extraction scripts, which
+ % extract all externs in one go) to report the exact problematic extern page.
+ \let\mmz@extraction@error\mmz@pageextraction@error
+ \mmz@check@extraction@log{tex}%
+ \endgroup
+}
+% \end{macro}
+\def\mmz@pageextraction@error{%
+ \PackageError{memoize}{Extraction of extern page \pagenumber\space from
+ document "\mmzUnquote\jobname.pdf" using method "\extractionmethod" was unsuccessful.
+ Have you set the shell escape mode as suggested in chapter 1 of the
+ manual?}{If "\mmzvalueof{tex extraction command}" was executed,
+ shell escape mode is not the problem, and inspecting "\externbasepath.log"
+ might give you a clue what's wrong}}
+%
+% \begin{key}{tex extraction command, tex extraction options, tex extraction script}
+% Using these keys, we set the system call
+% which will be invoked for each extern page. The value of this key is
+% expanded when executing the system command. The user may deploy the
+% following macros in the value of these keys:
+% \begin{itemize}
+% \item |\externbasepath|: the extern PDF that should be produced, minus the
+% |.pdf| suffix;
+% \item |\pagenumber|: the page number to be extracted;
+% \item |\expectedwidth|: the expected width of the extracted page;
+% \item |\expectedheight|: the expected total height of the extracted page;
+% \end{itemize}
+\def\mmz@tex@extraction@systemcall{%
+ \mmzvalueof{tex extraction command}\space
+ \mmzvalueof{tex extraction options}\space
+ "\mmzvalueof{tex extraction script}"%
+}
+% \end{key}
+%
+% \paragraph{The default} system call for \hologo{TeX}-based extern extraction.
+% As this method, despite being \hologo{TeX}-based, shares no code with the
+% document, we're free to implement it with any engine and format we want. For
+% reasons of speed, we clearly go for the plain \hologo{pdfTeX}.\footnote{I
+% implemented the first version of \hologo{TeX}-based extraction using
+% \hologo{LaTeX} and package \texttt{graphicx}, and it was (running with
+% \hologo{pdfTeX} engine) almost four times slower than the current plain
+% \hologo{TeX} implementation.} We perform the extraction by a little
+% \hologo{TeX} script, |memoize-extract-one|, inputted at the end of the value
+% given to |tex extraction script|.
+\mmzset{
+ tex extraction command/.initial=pdftex,
+ tex extraction options/.initial={%
+% \begin{listingregion}{tex-extraction-options.tex}
+ -halt-on-error
+ -interaction=batchmode
+ -jobname "\externbasepath"
+ \ifdefempty\mmzOutputDirectory{}{-output-directory "\mmzOutputDirectory"}
+% \end{listingregion}
+ },
+ tex extraction script/.initial={%
+% \begin{listingregion}{tex-extraction-script.tex} ^^A todo: context
+ \def\noexpand\fromdocument{"\mmzOutputDirectory"\jobname.pdf}%
+ \def\noexpand\pagenumber{\pagenumber}%
+ \def\noexpand\expectedwidth{\expectedwidth}%
+ \def\noexpand\expectedheight{\expectedheight}%
+ \def\noexpand\logfile{\jobname.mmz.log}%
+ \unexpanded{%
+ \def\warningtemplate{%
+ %<latex>\noexpand\PackageWarning{memoize}{\warningtext}%
+ %<plain>\warning{memoize: \warningtext}%
+ %<context>\warning{memoize: \warningtext}%
+ }}%
+ \ifdef\XeTeXversion{}{%
+ \def\noexpand\mmzpdfmajorversion{\the\pdfmajorversion}%
+ \def\noexpand\mmzpdfminorversion{\the\pdfminorversion}%
+ }%
+ \noexpand\input memoize-extract-one
+% \end{listingregion}
+ },
+}
+%</mmz>
+%
+% \subsubsection{\texttt{memoize-extract-one.tex}}
+%
+% The rest of the code of this section resides in file
+% |memoize-extract-one.tex|. It is used to extract a single extern page from
+% the document; it also checks whether the extern page dimensions are as
+% expected, and passes a warning to the main job if that is not the case. For
+% the reason of speed, the extraction script is in \hologo{plainTeX} format.
+% For the same reason, it is compiled by \hologo{pdfTeX} engine by default, but
+% we nevertheless take care that it will work with other (supported) engines as
+% well.
+%
+%<*extract-one>
+\catcode`\@11\relax
+\def\@firstoftwo#1#2{#1}
+\def\@secondoftwo#1#2{#2}
+%
+% Set the PDF version (maybe) passed to the script via |\mmzpdfmajorversion|
+% and |\mmzpdfminorversion|.
+\ifdefined\XeTeXversion
+\else
+ \ifdefined\luatexversion
+ \def\pdfmajorversion{\pdfvariable majorversion}%
+ \def\pdfminorversion{\pdfvariable minorversion}%
+ \fi
+ \ifdefined\mmzpdfmajorversion
+ \pdfmajorversion\mmzpdfmajorversion\relax
+ \fi
+ \ifdefined\mmzpdfminorversion
+ \pdfminorversion\mmzpdfminorversion\relax
+ \fi
+\fi
+% Allocate a new output stream, always --- |\newwrite| is |\outer| and thus
+% cannot appear in a conditional.
+\newwrite\extractionlog
+% Are we requested to produce a log file?
+\ifdefined\logfile
+ \immediate\openout\extractionlog{\logfile}%
+ % Define a macro which both outputs the warning message and writes it to the
+ % extraction log.
+ \def\doublewarning#1{%
+ \message{#1}%
+ \def\warningtext{#1}%
+ % This script will be called from different formats, so it is up to the
+ % main job to tell us, by defining macro |\warningtemplate|, how to throw a
+ % warning in the log file.
+ \immediate\write\extractionlog{%
+ \ifdefined\warningtemplate\warningtemplate\else\warningtext\fi
+ }%
+ }%
+\else
+ \let\doublewarning\message
+\fi
+\newif\ifforce
+\ifdefined\force
+ \csname force\force\endcsname
+\fi
+% \begin{macro}{\mmz@if@roughly@equal}
+% This macro checks whether the given dimensions (|#2| and |#3|) are equal
+% within the tolerance given by |#1|. We use the macro both in the
+% extraction script and in the main package. (We don't use |\ifpdfabsdim|,
+% because it is unavailable in \hologo{XeTeX}.)
+%</extract-one>
+%<*mmz,extract-one>
+\def\mmz@tolerance{0.01pt}
+\def\mmz@if@roughly@equal#1#2#3{%
+ \dimen0=\dimexpr#2-#3\relax
+ \ifdim\dimen0<0pt
+ \dimen0=-\dimen0\relax
+ \fi
+ \ifdim\dimen0>#1\relax
+ \expandafter\@secondoftwo
+ \else
+ % The exact tolerated difference is, well, tolerated. This is a must to
+ % support |tolerance=0pt|.
+ \expandafter\@firstoftwo
+ \fi
+}%
+%</mmz,extract-one>
+%<*extract-one>
+% Grab the extern page from the document and put it in a box.
+\ifdefined\XeTeXversion
+ \setbox0=\hbox{\XeTeXpdffile \fromdocument\space page \pagenumber media}%
+\else
+ \ifdefined\luatexversion
+ \saveimageresource page \pagenumber mediabox {\fromdocument}%
+ \setbox0=\hbox{\useimageresource\lastsavedimageresourceindex}%
+ \else
+ \pdfximage page \pagenumber mediabox {\fromdocument}%
+ \setbox0=\hbox{\pdfrefximage\pdflastximage}%
+ \fi
+\fi
+% Check whether the extern page is of the expected size.
+\newif\ifbaddimensions
+\ifdefined\expectedwidth
+ \ifdefined\expectedheight
+ \mmz@if@roughly@equal{\mmz@tolerance}{\wd0}{\expectedwidth}{%
+ \mmz@if@roughly@equal{\mmz@tolerance}{\ht0}{\expectedheight}%
+ {}%
+ {\baddimensionstrue}%
+ }{\baddimensionstrue}%
+ \fi
+\fi
+% We'll setup the page geometry of the extern file and shipout the extern ---
+% if all is well, or we're forced to do it.
+\ifdefined\luatexversion
+ \let\pdfpagewidth\pagewidth
+ \let\pdfpageheight\pageheight
+ \def\pdfhorigin{\pdfvariable horigin}%
+ \def\pdfvorigin{\pdfvariable vorigin}%
+\fi
+\def\do@shipout{%
+ \pdfpagewidth=\wd0
+ \pdfpageheight=\ht0
+ \ifdefined\XeTeXversion
+ \hoffset -1 true in
+ \voffset -1 true in
+ \else
+ \pdfhorigin=0pt
+ \pdfvorigin=0pt
+ \fi
+ \shipout\box0
+}
+\ifbaddimensions
+ \doublewarning{I refuse to extract page \pagenumber\space from
+ "\fromdocument", because its size (\the\wd0 \space x \the\ht0) is not
+ what I expected (\expectedwidth\space x \expectedheight)}%
+ \ifforce\do@shipout\fi
+\else
+ \do@shipout
+\fi
+% If logging is in effect and the extern dimensions were not what we expected,
+% write a warning into the log.
+\ifdefined\logfile
+ \immediate\write\extractionlog{\noexpand\endinput}%
+ \immediate\closeout\extractionlog
+\fi
+\bye
+%</extract-one>
+% \end{macro}
+%
+% \section{Automemoization}
+% \label{sec:code:automemoization}
+%
+% \paragraph{Install} the advising framework implemented by our auxiliary
+% package Advice, which automemoization depends on. This will define keys
+% |auto|, |activate| etc.\ in our keypath.
+%<*mmz>
+\mmzset{
+ .install advice={setup key=auto, activation=deferred},
+ % We switch to the immediate activation at the end of the preamble.
+ begindocument/before/.append style={activation=immediate},
+}
+%
+% \begin{key}{manual}
+% Unless the user switched on |manual|, we perform the deferred
+% (de)activations at the beginning of the document (and then clear the style,
+% so that any further deferred activations will start with a clean slate).
+% In \hologo{LaTeX}, we will use the latest possible hook,
+% |begindocument/end|, as we want to hack into commands defined by other
+% packages. (The \hologo{TeX} conditional needs to be defined before using
+% it in |.append code| below.
+\newif\ifmmz@manual
+\mmzset{
+ manual/.is if=mmz@manual,
+ begindocument/end/.append code={%
+ \ifmmz@manual
+ \else
+ \pgfkeysalso{activate deferred,activate deferred/.code={}}%
+ \fi
+ },
+% \end{key}
+%
+% \paragraph{Announce} Memoize's run conditions and handlers.
+ auto/.cd,
+ run if memoization is possible/.style={
+ run conditions=\mmz@auto@rc@if@memoization@possible
+ },
+ run if memoizing/.style={run conditions=\mmz@auto@rc@if@memoizing},
+ apply options/.style={
+ bailout handler=\mmz@auto@bailout,
+ outer handler=\mmz@auto@outer,
+ },
+ memoize/.style={
+ run if memoization is possible,
+ apply options,
+ inner handler=\mmz@auto@memoize
+ },
+ %<*latex>
+ noop/.style={run if memoization is possible, noop \AdviceType},
+ noop command/.style={apply options, inner handler=\mmz@auto@noop},
+ noop environment/.style={
+ outer handler=\mmz@auto@noop@env, bailout handler=\mmz@auto@bailout},
+ %</latex>
+ %<plain,context>noop/.style={inner handler=\mmz@auto@noop},
+ nomemoize/.style={noop, options=disable},
+ replicate/.style={run if memoizing, inner handler=\mmz@auto@replicate},
+}
+%
+% \paragraph{Abortion}
+% We cheat and let the |run conditions| do the work --- it is cheaper to just
+% always abort than to invoke the outer handler. (As we don't set
+% |\AdviceRuntrue|, the run conditions will never be satisfied.)
+% \begin{listingregion}{_auto-abort.tex}
+\mmzset{
+ auto/abort/.style={run conditions=\mmzAbort},
+}
+% \end{listingregion}
+% And the same for |unmemoizable|:
+\mmzset{
+ auto/unmemoizable/.style={run conditions=\mmzUnmemoizable},
+}
+% For one, we abort upon |\pdfsavepos| (called |\savepos| in \hologo{LuaTeX}).
+% Second, unless in \hologo{LuaTeX}, we submit |\errmessage|, which allows us
+% to detect at least some errors --- in \hologo{LuaTeX}, we have a more
+% bullet-proof system of detecting errors, see |\mmz@memoize| in
+% \S\ref{sec:code:memoization-process}.
+\ifdef\luatexversion{%
+ \mmzset{auto=\savepos{abort}}
+}{%
+ \mmzset{
+ auto=\pdfsavepos{abort},
+ auto=\errmessage{abort},
+ }
+}
+%
+% \begin{mmzautokey}{run if memoization is possible}
+% \begin{macro}{\mmz@auto@rc@if@memoization@possible}
+% These run conditions are used by |memoize| and |noop|: Memoize should be
+% enabled, but we should not be already within Memoize, i.e.\ memoizing or
+% normally compiling some code submitted to memoization.
+% \begin{listingregion}{_auto-run-if-memoization-is-possible.tex}
+\def\mmz@auto@rc@if@memoization@possible{%
+ \ifmemoize
+ \ifinmemoize
+ \else
+ \AdviceRuntrue
+ \fi
+ \fi
+}
+% \end{listingregion}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{mmzautokey}{run if memoizing}
+% \begin{macro}{\mmz@auto@rc@if@memoizing}
+% These run conditions are used by |\label| and |\ref|: they should
+% be handled only during memoization (which implies that Memoize is enabled).
+\def\mmz@auto@rc@if@memoizing{%
+ \ifmemoizing\AdviceRuntrue\fi
+}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{macro}{\mmznext}
+% The next-options, set by this macro, will be applied to the next, and only
+% next instance of automemoization. We set the next-options globally, so
+% that only the linear order of the invocation matters. Note that |\mmznext|,
+% being a user command, must also be defined in package |nomemoize|.
+%</mmz>
+%<nommz>\def\mmznext#1{\ignorespaces}
+%<*mmz>
+\def\mmznext#1{\gdef\mmz@next{#1}\ignorespaces}
+\mmznext{}%
+% \end{macro}
+%
+% \begin{mmzautokey}{apply options}
+% \begin{macro}{\mmz@auto@outer,\mmz@auto@bailout}
+% The outer and the bailout handler defined here work as a team. The outer
+% handler's job is to apply the auto- and the next-options; therefore, the
+% bailout handler must consume the next-options as well. To keep the
+% option application local, the outer handler opens a group, which is
+% expected to be closed by the inner handler. This key is used by
+% |memoize| and |noop command|.
+% \begin{listingregion}{_auto-memoize-outer.tex}
+\def\mmz@auto@outer{%
+ \begingroup
+ \mmzAutoInit
+ \AdviceCollector
+}
+% \end{listingregion}
+% \begin{listingregion}{_auto-memoize-bailout.tex}
+\def\mmz@auto@bailout{%
+ \mmznext{}%
+}
+% \end{listingregion}
+% \bigskip
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{macro}{\mmzAutoInit}
+% Apply first the auto-options, and then the next-options (and clear the
+% latter). Finally, if we have any extra collector options (set by the
+% |verbatim| keys), append them to Advice's (raw) collector options.
+\def\mmzAutoInit{%
+ \ifdefempty\AdviceOptions{}{\expandafter\mmzset\expandafter{\AdviceOptions}}%
+ \ifdefempty\mmz@next{}{\expandafter\mmzset\expandafter{\mmz@next}\mmznext{}}%
+ \eappto\AdviceRawCollectorOptions{\expandonce\mmzRawCollectorOptions}%
+}
+% \end{macro}
+%
+% \begin{mmzautokey}{memoize}
+% \begin{macro}{\mmz@auto@memoize}
+% This key installs the inner handler for memoization. If you compare this
+% handler to the definition of |\mmz| in
+% section~\ref{sec:code:memoization:manual}, you will see that the only
+% thing left to do here is to start memoization with |\Memoize|, everything
+% else is already done by the advising framework, as customized by Memoize.
+%
+% The first argument to |\Memoize| is the memoization key (which the code
+% md5sum is computed off of); it consists of the handled code (the contents
+% of |\AdviceReplaced|) and its arguments, which were collected into |##1|.
+% The second argument is the code which the memoization driver will
+% execute. |\AdviceOriginal|, if invoked right away, would execute the
+% original command; but as this macro is only guaranteed to refer to this
+% command within the advice handlers, we expand it before calling |\Memoize|.
+% that command.
+%
+% Note that we don't have to define different handlers for commands and
+% environments, and for different \hologo{TeX} formats. When memoizing
+% command |\foo|, |\AdviceReplaced| contains |\foo|. When memoizing
+% environment |foo|, |\AdviceReplaced| contains |\begin{foo}|, |\foo| or
+% |\startfoo|, depending on the format, while the closing tag
+% (|\end{foo}|, |\endfoo| or |\stopfoo|) occurs at the end of the
+% collected arguments, because |apply options| appended
+% |\collargsEndTagtrue| to |raw collector options|.
+%
+% This macro has no formal parameters, because the collected arguments will
+% be grabbed by |\mmz@marshal|, which we have to go through because
+% executing |\Memoize| closes the memoization group and we lose the current
+% value of |\ifmmz@ignorespaces|. (We also can't use |\aftergroup|,
+% because closing the group is not the final thing |\Memoize| does.)
+% \begin{listingregion}{_auto-memoize-inner.tex}
+\long\def\mmz@auto@memoize#1{%
+ \expanded{%
+ \noexpand\Memoize
+ {\expandonce\AdviceReplaced\unexpanded{#1}}%
+ {\expandonce\AdviceOriginal\unexpanded{#1}}%
+ \ifmmz@ignorespaces\ignorespaces\fi
+ }%
+}
+% \end{listingregion}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{mmzautokey}{noop}
+% \begin{macro}{\mmz@auto@noop,\mmz@auto@noop@env}
+% The no-operation handler can be used to apply certain options for the
+% span of the execution of the handled command or environment. This is
+% exploited by |auto/nomemoize|, which sets |disable| as an auto-option.
+%
+% The handler for commands and non-\hologo{LaTeX} environments is
+% implemented as an inner handler. On its own, it does nothing except
+% honor |verbatim| and |ignore spaces| (only takes care of |verbatim| and
+% |ignore spaces| (in the same way as the memoization handler above), but
+% it is intended to be used alongside the default outer handler, which
+% applies the auto- and the next-options. As that handler opens a group
+% (and this handler closes it), we have effectively delimited the effect of
+% those options to this invocation of the handled command or environment.
+\long\def\mmz@auto@noop#1{%
+ \expandafter\mmz@maybe@scantokens\expandafter{\AdviceOriginal#1}%
+ \expandafter\endgroup
+ \ifmmz@ignorespaces\ignorespaces\fi
+}
+% In \hologo{LaTeX}, and only there, commands and environments need separate
+% treatment. As \hologo{LaTeX} environments introduce a group of their own, we
+% can simply hook our initialization into the beginning of the environment (as
+% a one-time hook). Consequently, we don't need to collect the environment
+% body, so this can be an outer handler.
+%<*latex>
+\def\mmz@auto@noop@env{%
+ \AddToHookNext{env/\AdviceName/begin}{%
+ \mmzAutoInit
+ \ifmmz@ignorespaces\ignorespacesafterend\fi
+ }%
+ \AdviceOriginal
+}
+%</latex>
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{mmzautokey}{replicate}
+% \begin{macro}{\mmz@auto@replicate}
+% This inner handler writes a copy of the handled command or environment's
+% invocation into the cc-memo (and then executes it). As it is used
+% alongside |run if memoizing|, the replicated command in the cc-memo will
+% always execute the original command. The system works even if
+% replication is off when the cc-memo is input; in that case, the control
+% sequence in the cc-memo directly executes the original command.
+%
+% This handler takes an option, |expanded| --- if given, the collected
+% arguments will be expanded (under protection) before being written into
+% the cc-memo.
+\def\mmz@auto@replicate#1{%
+ \begingroup
+ \let\mmz@auto@replicate@expansion\unexpanded
+ \expandafter\pgfqkeys\expanded{{/mmz/auto/replicate}{\AdviceOptions}}%
+ %<latex>\let\protect\noexpand
+ \expanded{%
+ \endgroup
+ \noexpand\gtoksapp\noexpand\mmzCCMemo{%
+ \expandonce\AdviceReplaced\mmz@auto@replicate@expansion{#1}}%
+ \expandonce\AdviceOriginal\unexpanded{#1}%
+ }%
+}
+\pgfqkeys{/mmz/auto/replicate}{
+ expanded/.code={\let\mmz@auto@replicate@expansion\@firstofone},
+}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \subsection{\hologo{LaTeX}-specific handlers}
+%
+% We handle cross-referencing (both the |\label| and the |\ref| side) and
+% indexing. Note that the latter is a straightforward instance of replication.
+%
+%<*latex>
+% \begin{listingregion}{_auto-memoize-ref.tex}
+\mmzset{
+ auto/.cd,
+ ref/.style={outer handler=\mmz@auto@ref\mmzNoRef, run if memoizing},
+ force ref/.style={outer handler=\mmz@auto@ref\mmzForceNoRef, run if memoizing},
+}
+% \end{listingregion}
+\mmzset{
+ auto=\ref{ref},
+ auto=\pageref{ref},
+ auto=\label{run if memoizing, outer handler=\mmz@auto@label},
+ auto=\index{replicate, args=m, expanded},
+}
+%
+% \begin{mmzautokey}{ref, force ref}
+% \begin{macro}{\mmz@auto@ref}
+% These keys install an outer handler which appends a cross-reference to the
+% context. |force ref| does this even if the reference key is undefined,
+% while |ref| aborts memoization in such a case --- the idea is that it makes
+% no sense to memoize when we expect the context to change in the next
+% compilation anyway.
+%
+% Any command taking a mandatory braced reference key argument potentially
+% preceded by optional arguments of (almost) any kind may be submitted to
+% these keys. This follows from the parameter list of |\mmz@auto@ref@i|,
+% where |#2| grabs everything up to the first opening brace. The downside of
+% the flexibility regarding the optional arguments is that unbraced
+% single-token reference keys will cause an error, but as such usages of
+% |\ref| and friends should be virtually inexistent, we let the bug stay.
+%
+% |#1| should be either |\mmzNoRef| or |\mmzForceNoRef|. |#2| will receive
+% any optional arguments of |\ref| (or |\pageref|, or whatever), and |#3| in
+% |\mmz@auto@ref@i| is the cross-reference key.
+% \begin{listingregion}{_auto-memoize-ref.tex}
+\def\mmz@auto@ref#1#2#{\mmz@auto@ref@i#1{#2}}
+\def\mmz@auto@ref@i#1#2#3{%
+ #1{#3}%
+ \AdviceOriginal#2{#3}%
+}
+% \end{listingregion}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{macro}{\mmzForceNoRef,\mmzNoRef}
+% These macros do the real job in the outer handlers for cross-referencing,
+% but it might be useful to have them publicly available. |\mmzForceNoRef|
+% appends the reference key to the context. |\mmzNoRef| only does that if
+% the reference is defined, otherwise it aborts the memoization.
+\def\mmzForceNoRef#1{%
+ \ifmemoizing
+ \expandafter\gtoksapp\expandafter\mmzContextExtra
+ \else
+ \expandafter\toksapp\expandafter\mmzContext
+ \fi
+ {r@#1={\csname r@#1\endcsname}}%
+ \ignorespaces
+}
+\def\mmzNoRef#1{%
+ \ifcsundef{r@#1}{\mmzAbort}{\mmzForceNoRef{#1}}%
+ \ignorespaces
+}
+% \end{macro}
+%
+% \begin{mmzautokey}{refrange, force refrange}
+% \begin{macro}{\mmz@auto@refrange}
+% Let's rinse and repeat for reference ranges. The code is virtually the
+% same as above, but we grab two reference key arguments (|#3| and |#4|) in
+% the final macro.\indentmacrocode
+\mmzset{
+ auto/.cd,
+ refrange/.style={outer handler=\mmz@auto@refrange\mmzNoRef,
+ bailout handler=\relax, run if memoizing},
+ force refrange/.style={outer handler=\mmz@auto@refrange\mmzForceNoRef,
+ bailout handler=\relax, run if memoizing},
+}
+% \noindentmacrocode
+\def\mmz@auto@refrange#1#2#{\mmz@auto@refrange@i#1{#2}}
+\def\mmz@auto@refrange@i#1#2#3#4{%
+ #1{#3}%
+ #1{#4}%
+ \AdviceOriginal#2{#3}{#4}%
+}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{mmzautokey}{multiref, force multiref}
+% \begin{macro}{\mmz@auto@multiref}
+% And one final time, for ``multi-references'', such as |cleveref|'s
+% |\cref|, which can take a comma-separated list of reference keys in the
+% sole argument. Again, only the final macro is any different, this time
+% distributing |#1| (|\mmzNoRef| or |\mmzForceNoRef|) over |#3| by
+% |\forcsvlist|.
+\mmzset{
+ auto/.cd,
+ multiref/.style={outer handler=\mmz@auto@multiref\mmzNoRef,
+ bailout handler=\relax, run if memoizing},
+ force multiref/.style={outer handler=\mmz@auto@multiref\mmzForceNoRef,
+ bailout handler=\relax, run if memoizing},
+}
+\def\mmz@auto@multiref#1#2#{\mmz@auto@multiref@i#1{#2}}
+\def\mmz@auto@multiref@i#1#2#3{%
+ \forcsvlist{#1}{#3}%
+ \AdviceOriginal#2{#3}%
+}
+% \end{macro}
+% \end{mmzautokey}
+%
+% \begin{macro}{\mmz@auto@label}
+% The outer handler for \cs{label} must be defined specifically for this
+% command. The generic replicating handler is not enough here, as we need to
+% replicate both the invocation of |\label| and the definition of
+% |\@currentlabel|.
+\def\mmz@auto@label#1{%
+ \xtoksapp\mmzCCMemo{%
+ \noexpand\mmzLabel{#1}{\expandonce\@currentlabel}%
+ }%
+ \AdviceOriginal{#1}%
+}
+% \end{macro}
+%
+% \begin{macro}{\mmzLabel}
+% This is the macro that |\label|'s handler writes into the cc-memo. The
+% first argument is the reference key; the second argument is the value of
+% |\@currentlabel| at the time of invocation |\label| during memoization,
+% which this macro temporarily restores.
+\def\mmzLabel#1#2{%
+ \begingroup
+ \def\@currentlabel{#2}%
+ \label{#1}%
+ \endgroup
+}
+%</latex>
+%</mmz>
+%
+% \end{macro}
+%
+% \section{Support for various classes and packages}
+%
+% \subsection{\TikZ;}
+% \label{sec:code:mmz:tikz}
+%
+% In this section, we activate \TikZ; support (the collector is defined by
+% Advice). All the action happens at the end of the preamble, so that we can
+% detect whether \TikZ; was loaded (regardless of whether Memoize was loaded
+% before \TikZ;, or vice versa), but still input the definitions.
+%<*mmz>
+\mmzset{
+ begindocument/before/.append code={%
+ %<latex>\@ifpackageloaded{tikz}{%
+ %<plain,context>\ifdefined\tikz
+ \input advice-tikz.code.tex
+ %<latex>}{}%
+ %<plain,context>\fi
+ % We define and activate the automemoization handlers for the \TikZ; command
+ % and environment.
+ \mmzset{%
+ % \begin{listingregion}{_auto-tikz-collector.tex}
+ auto=\tikz{memoize, collector=\AdviceCollectTikZArguments},
+ % \end{listingregion}
+ %/utils/exec={\tracingall},
+ auto={tikzpicture}{memoize},
+ % A hack to prevent memoizing pictures which are accidentally marked as
+ % remembered --- accidentally in the sense that because the document
+ % changed, the |.aux| file contains a |\pgfsyspdfmark| command which
+ % erroneously refers to the picture being memoized. We know that
+ % memoizing a remembered picture can't be right, as we always abort on
+ % |\pdfsavepos|. This is implemented by hacking into PGF's
+ % |\pgfsys@getposition|, and aborting memoization if the mark does not
+ % equal |\relax|. (We have to duplicate |#| because of |.append code|.)
+ auto=\pgfsys@getposition{
+ run if memoizing, outer handler=\mmz@pgfsys@getposition},
+ }%
+ \def\mmz@pgfsys@getposition##1{%
+ \expandafter\ifx\csname pgf@sys@pdf@mark@pos@##1\endcsname\relax
+ \else
+ \mmzAbort
+ \fi
+ \AdviceOriginal{##1}%
+ }%
+ },
+}
+%</mmz>
+%
+%
+% \subsection{Forest}
+% \label{sec:code:forest}
+%
+% Forest will soon feature extensive memoization support, but for now, let's
+% just enable the basic, single extern externalization.
+%<*mmz>
+%<*latex>
+\mmzset{
+ begindocument/before/.append code={%
+ \@ifpackageloaded{forest}{%
+ \mmzset{
+ auto={forest}{memoize},
+% Yes, |\Forest| is defined using |xparse|.
+ auto=\Forest{memoize},
+ }%
+ }{}%
+ },
+}
+%</latex>
+%
+% \subsection{Beamer}
+% \label{sec:code:beamer}
+%
+% The Beamer code is explained in \MS\ref{sec:per-overlay}.
+%
+%<*latex>
+\AddToHook{begindocument/before}{\@ifclassloaded{beamer}{%
+ % \begin{listingregion}{per-overlay.tex}
+ \mmzset{per overlay/.style={
+ /mmz/context={%
+ overlay=\csname beamer@overlaynumber\endcsname,
+ pauses=\ifmemoizing
+ \mmzBeamerPauses
+ \else
+ \expandafter\the\csname c@beamerpauses\endcsname
+ \fi
+ },
+ /mmz/at begin memoization={%
+ \xdef\mmzBeamerPauses{\the\c@beamerpauses}%
+ \xtoksapp\mmzCMemo{%
+ \noexpand\mmzSetBeamerOverlays{\mmzBeamerPauses}{\beamer@overlaynumber}}%
+ \gtoksapp\mmzCCMemo{%
+ \only<\mmzBeamerOverlays>{}}%
+ },
+ /mmz/at end memoization={%
+ \xtoksapp\mmzCCMemo{%
+ \noexpand\setcounter{beamerpauses}{\the\c@beamerpauses}}%
+ },
+ /mmz/per overlay/.code={},
+ }}
+ \def\mmzSetBeamerOverlays#1#2{%
+ \ifnum\c@beamerpauses=#1\relax
+ \gdef\mmzBeamerOverlays{#2}%
+ \ifnum\beamer@overlaynumber<#2\relax \mmz@temptrue \else \mmz@tempfalse \fi
+ \else
+ \mmz@temptrue
+ \fi
+ \ifmmz@temp
+ \appto\mmzAtBeginMemoization{%
+ \gtoksapp\mmzCMemo{\mmzSetBeamerOverlays{#1}{#2}}}%
+ \fi
+ }%
+ % \end{listingregion}
+}{}}
+%</latex>
+%
+%
+% \section{Initialization}
+% \label{sec:code:initialization}
+%
+% \begin{key}{begindocument/before, begindocument, begindocument/end,
+% enddocument/afterlastpage}
+% These styles contain the initialization
+% and the finalization code. They were populated throughout the source.
+% Hook |begindocument/before| contains the package support code, which must
+% be loaded while still in the preamble. Hook |begindocument| contains the
+% initialization code whose execution doesn't require any particular timing,
+% as long as it happens at the beginning of the document. Hook
+% |begindocument/end| is where the commands are activated; this must
+% crucially happen as late as possible, so that we successfully override
+% foreign commands (like |hyperref|'s definitions). In \hologo{LaTeX}, we
+% can automatically execute these hooks at appropriate places:
+%<*latex>
+\AddToHook{begindocument/before}{\mmzset{begindocument/before}}
+\AddToHook{begindocument}{\mmzset{begindocument}}
+\AddToHook{begindocument/end}{\mmzset{begindocument/end}}
+\AddToHook{enddocument/afterlastpage}{\mmzset{enddocument/afterlastpage}}
+%</latex>
+% In \hologo{plainTeX}, the user must execute these hooks manually; but at
+% least we can group them together and given them nice names. Provisionally,
+% manual execution is required in \hologo{ConTeXt} as well, as I'm not sure
+% where to execute them --- please help!
+%<*plain,context>
+\mmzset{
+ begin document/.style={begindocument/before, begindocument, begindocument/end},
+ end document/.style={enddocument/afterlastpage},
+}
+%</plain,context>
+% \end{key}
+%
+% \paragraph{\texttt{memoize.cfg}} Load the configuration file. Note that
+% |nomemoize| must input this file as well, because any special
+% memoization-related macros defined by the user should be available; for
+% example, my |memoize.cfg| defines |\ifregion| (see
+% \MS\ref{sec:tut:multifile}).
+%</mmz>
+%<mmz,nommz>\InputIfFileExists{memoize.cfg}{}{}
+%<*mmz>
+%
+% Formats other than \hologo{plainTeX} need a way to prevent extraction during
+% package-loading.
+\mmzset{
+ %<!plain>extract/no/.code={},
+% \begin{key}{output directory}
+% \begin{macro}{mmzOutputDirectory}
+% Set the |-output-directory| --- manually, as there is no other way.
+% \indentmacrocode
+ output-directory/.store in=\mmzOutputDirectory,
+}
+% \end{macro}
+% \end{key}
+%
+% \paragraph{Process} the package options (except in \hologo{plainTeX}).
+%<latex>\ProcessPgfPackageOptions{/mmz}
+%<context>\expandafter\mmzset\expandafter{\currentmoduleparameters}
+%
+% Define |\mmzOutputDirectory| if |output-directory| was not given.
+\ifdefined\mmzOutputDirectory
+\else
+ \def\mmzOutputDirectory{}%
+\fi
+\mmzset{output directory/.code={\PackageError{memoize}{Key "output-directory"
+ may only be used as a package option}{}}}
+\mmzset{
+ % \paragraph{Extract} the externs using the method given by |memoize.cfg| or
+ % the package options --- unless we're running \hologo{plainTeX}.
+ %<*!plain>
+ extract/\mmz@extraction@method,
+ % In non-\hologo{plainTeX} formats, also disable |extract| in the preamble.
+ extract/.code={\PackageError{memoize}{Key "extract" is only allowed as a
+ package option.}{If you really want to extract in the preamble, execute
+ "extract/<method>".}},
+ %</!plain>
+ %<*plain>
+ % In \hologo{plainTeX}, where extraction must be invoked after
+ % loading the package, we now have to redefine |extract|, so that it will
+ % immediately trigger extraction.
+ extract/.is choice,
+ extract/.default=\mmz@extraction@method,
+ % But only once:
+ extract/.append style={
+ extract/.code={\PackageError{memoize}{Key "extract" is only allowed to
+ be used once.}{If you really want to extract again, execute
+ "extract/<method>".}},
+ },
+ %</plain>
+}
+%
+% Memoize was not really born for the draft mode, as it cannot produce new
+% externs there. But we don't want to disable the package, as utilization is
+% still perfectly valid in this mode, so let's just warn the user.
+\ifnum\pdf@draftmode=1
+ \PackageWarning{memoize}{No memoization will be performed in the draft mode}%
+\fi
+%</mmz>
+%
+% \paragraph{The end} of |memoize|, |nomemoize| and |memoizable|.
+%<*mmz,nommz,mmzable>
+%<plain>\resetatcatcode
+%<context>\stopmodule
+%<context>\protect
+%</mmz,nommz,mmzable>
+% That's all, folks!
+%
+% \end{macrocode}
+%
+% \endinput
+%
+% Local Variables:
+% TeX-engine: luatex
+% TeX-master: "doc/memoize-code.tex"
+% TeX-auto-save: nil
+% End: \ No newline at end of file
diff --git a/macros/generic/memoize/memoize.ins b/macros/generic/memoize/memoize.ins
new file mode 100644
index 0000000000..f288e8e555
--- /dev/null
+++ b/macros/generic/memoize/memoize.ins
@@ -0,0 +1,39 @@
+%% memoize.ins
+%%
+%% This file is a part of Memoize, a TeX package for externalization of
+%% graphics and memoization of compilation results in general, available at
+%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize.
+%%
+%% Copyright (c) 2020- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+%% (Sa\v{s}o \v{Z}ivanovi\'{c})
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3c of this license or (at
+%% your option) any later version. The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of
+%% all distributions of LaTeX version 2008 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%% The Current Maintainer of this work is Saso Zivanovic.
+%%
+%% The files belonging to this work and covered by LPPL are listed in
+%% (<texmf>/doc/generic/memoize/)FILES.
+%%
+\input docstrip.tex
+\keepsilent
+\preamble
+\endpreamble
+\askforoverwritefalse
+\generate{%
+ \file{memoize.sty}{\from{memoize.dtx}{mmz,latex}}%
+ \file{memoize.tex}{\from{memoize.dtx}{mmz,plain}}%
+ \file{t-memoize.tex}{\from{memoize.dtx}{mmz,context}}%
+ \file{nomemoize.sty}{\from{memoize.dtx}{nommz,latex}}%
+ \file{nomemoize.tex}{\from{memoize.dtx}{nommz,plain}}%
+ \file{t-nomemoize.tex}{\from{memoize.dtx}{nommz,context}}%
+ \file{memoizable.sty}{\from{memoize.dtx}{mmzable,latex}}%
+ \file{memoizable.tex}{\from{memoize.dtx}{mmzable,plain}}%
+ \file{t-memoizable.tex}{\from{memoize.dtx}{mmzable,context}}%
+ \file{memoize-extract-one.tex}{\from{memoize.dtx}{extract-one}}%
+}
+\endbatchfile
diff --git a/support/easydtx/LICENCE b/support/easydtx/LICENCE
new file mode 100644
index 0000000000..f288702d2f
--- /dev/null
+++ b/support/easydtx/LICENCE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/support/easydtx/README.md b/support/easydtx/README.md
new file mode 100644
index 0000000000..8f0030b03b
--- /dev/null
+++ b/support/easydtx/README.md
@@ -0,0 +1,10 @@
+EasyDTX is a variant of the DTX format which eliminates the need for all those
+pesky `macrocode` environments. Any line introduced by a single comment counts
+as documentation, and documentation lines may be indented.
+
+An `.edtx` file is converted to a `.dtx` by a little Perl script called
+`edtx2dtx`; there is also a rudimentary Emacs mode, implemented in
+`easydoctex-mode.el`, which takes care of fontification, indentation, and
+forward and inverse search. (The script does what it should, and would really
+deserve version 1.0.0. The Emacs mode, however, is just something that works
+well enough for me.)
diff --git a/support/easydtx/easydoctex-mode.el b/support/easydtx/easydoctex-mode.el
new file mode 100644
index 0000000000..3226414e3c
--- /dev/null
+++ b/support/easydtx/easydoctex-mode.el
@@ -0,0 +1,149 @@
+;; easydoctex-mode.el 0.1.0
+;;
+;; This file is a part of TeX package EasyDTX, available at
+;; https://ctan.org/pkg/easydtx and https://github.com/sasozivanovic/easydtx.
+;;
+;; Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+;;
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;;
+;; The files belonging to this work and covered by GPL are listed in
+;; <texmf>/doc/support/easydtx/FILES.
+
+;; Add this to .emacs to (auto)load EasyDocTeX mode and associate it with .edtx files:
+;; (autoload 'easydoctex-mode "easydoctex-mode" "Add DocTeX fontification (and only fontification) to LaTeX mode." t)
+;; (add-to-list 'auto-mode-alist '("\\.edtx\\'" . easydoctex-mode))
+
+(define-derived-mode easydoctex-mode TeX-latex-mode "EasyDocTeX"
+ "Add DocTeX fontification (and only fontification) to LaTeX mode."
+ (setq major-mode 'easydoctex-mode)
+ (set (make-local-variable 'LaTeX-insert-into-comments) t)
+ (set (make-local-variable 'LaTeX-syntactic-comments) t)
+ (setq paragraph-start (concat paragraph-start "\\| *%<")
+ paragraph-separate (concat paragraph-separate "\\|%<")
+ font-latex-doctex-keywords (append (butlast font-latex-doctex-keywords) '(("^ *%<[^>]*>" (0 font-latex-doctex-preprocessor-face t))))
+ )
+ (let ((major-mode 'doctex-mode))
+ (funcall TeX-install-font-lock)))
+
+(defun easydoctex-wrapper (ORIG-FUNC &rest args)
+ (if (eq major-mode 'easydoctex-mode)
+ (let ((major-mode 'doctex-mode))
+ (apply ORIG-FUNC args))
+ (apply ORIG-FUNC args)))
+
+(advice-add 'font-latex-find-matching-close :around #'easydoctex-wrapper)
+(advice-add 'font-latex-commented-outp :around #'easydoctex-wrapper)
+(advice-add 'font-latex-forward-comment :around #'easydoctex-wrapper)
+(advice-add 'font-latex-match-simple-command :around #'easydoctex-wrapper)
+
+(defun easydoctex-no-comment-padding (ORIG-FUNC &rest args)
+ (if (and
+ (eq major-mode 'easydoctex-mode)
+ (save-excursion
+ (beginning-of-line)
+ (looking-at " *%<")
+ ))
+ ""
+ (apply ORIG-FUNC args)))
+(advice-add 'TeX-comment-padding-string :around #'easydoctex-no-comment-padding)
+
+(defun easydoctex-guard-is-code (ORIG-FUNC &rest args)
+ (if (and
+ (eq major-mode 'easydoctex-mode)
+ (save-excursion
+ (beginning-of-line)
+ (looking-at " *%<")))
+ nil
+ (apply ORIG-FUNC args)))
+(advice-add 'TeX-in-commented-line :around #'easydoctex-guard-is-code)
+
+(defun font-latex-easydoctex-syntactic-face-function (ORIG-FUNC state &rest args)
+ "In EasyDTC (.edtx), % can start after any blanks, but it should not be followed by another % or a guard."
+ (if (eq major-mode 'easydoctex-mode)
+ (if (or
+ (nth 3 state)
+ (nth 7 state)
+ (save-excursion
+ (goto-char (nth 8 state))
+ (skip-chars-backward " \t")
+ (not (bolp)))
+ (char-equal (char-after (1+ (nth 8 state))) ?%))
+ (apply ORIG-FUNC state args)
+ font-latex-doctex-documentation-face)
+ (apply ORIG-FUNC state args)))
+(advice-add
+ 'font-latex-doctex-syntactic-face-function :around
+ #'font-latex-easydoctex-syntactic-face-function)
+
+(defun LaTeX-current-environment-no-macrocode (env)
+ "The only (and obligatory) macrocode environment does not count as an environment."
+ (if (member env '("macrocode" "macrocode*")) "document" env))
+(advice-add 'LaTeX-current-environment :filter-return #'LaTeX-current-environment-no-macrocode)
+;; (advice-remove 'LaTeX-current-environment#'LaTeX-current-environment-no-macrocode)
+
+(defun server-visit-files-forward-to-edtx (args)
+ "When inverse search points to a .dtx generated from .edtx, visit
+the original .edtx file instead."
+ (dolist (file-pos (nth 0 args))
+ (let* ((file (car file-pos))
+ (pos (cdr file-pos))
+ (edtx (concat (file-name-sans-extension file) ".edtx"))
+ )
+ (when (and pos
+ (string-match "dtx" (file-name-extension file))
+ (file-readable-p edtx))
+ (setcar file-pos edtx)
+ (let* ((line (car pos))
+ (col (cdr pos))
+ (dtx-buffer (find-file-noselect file nil t))
+ (line-offset
+ (with-current-buffer dtx-buffer
+ (widen)
+ (goto-char 1)
+ (forward-line (1- line))
+ (move-to-column col)
+ (count-matches "^% \\\\\\(begin\\|end\\){macrocode}" 0 (point)))))
+ (when (> line-offset 1)
+ (set 'line-offset (1- line-offset)))
+ (setcdr file-pos (cons (- line line-offset) col))
+ ))))
+ args)
+(advice-add 'server-visit-files :filter-args #'server-visit-files-forward-to-edtx)
+;; (advice-remove 'server-visit-files #'server-visit-files-forward-to-edtx)
+
+
+
+;; Forward search for .edtx
+(defun TeX-current-file-name-master-relative--edtx (r)
+ (if (equal (file-name-extension r) "edtx")
+ (concat (file-name-sans-extension r) ".dtx")
+ r))
+(advice-add 'TeX-current-file-name-master-relative :filter-return
+ #'TeX-current-file-name-master-relative--edtx)
+(defun TeX-current-line--edtx (line)
+ (when (equal (file-name-extension (buffer-file-name)) "edtx")
+ (let ((remaining (string-to-number line))
+ (dtx-buffer (find-file-noselect (concat (file-name-sans-extension (buffer-file-name)) ".dtx") nil t)))
+ (with-current-buffer dtx-buffer
+ (widen)
+ (goto-char 1)
+ (setq line 0)
+ (while (> (setq remaining (1- remaining)) 0)
+ (while (progn (forward-line 1)
+ (setq line (1+ line))
+ (looking-at "% \\\\\\(begin\\|end\\){macrocode}")))))
+ (setq line (format "%d" line))))
+ line)
+(advice-add 'TeX-current-line :filter-return #'TeX-current-line--edtx)
diff --git a/support/easydtx/edtx2dtx.1 b/support/easydtx/edtx2dtx.1
new file mode 100644
index 0000000000..34c0fe7f82
--- /dev/null
+++ b/support/easydtx/edtx2dtx.1
@@ -0,0 +1,54 @@
+.\" Automatically generated by Pandoc 3.0.1
+.\"
+.\" Define V font for inline verbatim, using C font in formats
+.\" that render this, and otherwise B font.
+.ie "\f[CB]x\f[]"x" \{\
+. ftr V B
+. ftr VI BI
+. ftr VB B
+. ftr VBI BI
+.\}
+.el \{\
+. ftr V CR
+. ftr VI CI
+. ftr VB CB
+. ftr VBI CBI
+.\}
+.TH "edtx2dtx" "1" "October 10, 2023" "edtx2dtx 0.1.0" "User Manual"
+.nh
+.SH NAME
+.PP
+edtx2dtx - Convert .edtx into .dtx
+.SH SYNOPSIS
+.PP
+\f[B]edtx2dtx\f[R] \f[I]filename.edtx\f[R] > \f[I]filename.dtx\f[R]
+.SH DESCRIPTION
+This utility wraps code chunks by a (commented and properly indented)
+.PP
+pair.
+A code chunk is any sequence of lines not introduced by a single
+(possibly indented) comment character (%); i.e.\ both non-commented
+lines and lines introduced by multiple comment characters count as code,
+and documentation lines may be indented.
+The part(s) of the file which should undergo conversion should be marked
+by a
+.PP
+pair (unlike in a .dtx, these lines need not immediately precede and
+follow the code, respectively).
+This convention allows for the driver to remain as is, and also makes it
+easy to paste a .dtx file into an .edtx, as using this utility on a .dtx
+does not change the file.
+.PP
+The utility furthermore replaces the first occurrence of
+\[lq].edtx\[rq], followed by an optional parenthesized note, with
+\[lq].dtx\[rq], plus the note on how the file was generated.
+.SH OPTIONS
+.TP
+\f[B]-h, --help\f[R]
+Show help and exit.
+.TP
+\f[B]-V, --version\f[R]
+Show the version number and exit.
+.SH SEE ALSO
+.PP
+easydoctex.el
diff --git a/support/easydtx/edtx2dtx.pl b/support/easydtx/edtx2dtx.pl
new file mode 100755
index 0000000000..f3965b1a48
--- /dev/null
+++ b/support/easydtx/edtx2dtx.pl
@@ -0,0 +1,99 @@
+#!/usr/bin/env perl
+
+# This file is a part of TeX package EasyDTX, available at
+# https://ctan.org/pkg/easydtx and https://github.com/sasozivanovic/easydtx.
+#
+# Copyright (c) 2023- Saso Zivanovic <saso.zivanovic@guest.arnes.si>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# The files belonging to this work and covered by LPPL are listed in
+# <texmf>/doc/support/easydtx/FILES.
+
+use strict;
+use Getopt::Long;
+
+my $usage = <<END;
+EasyDTX: convert .edtx into .dtx
+Usage: edtx2dtx filename.edtx > filename.dtx
+END
+
+my $VERSION = '0.1.0';
+my ($help, $print_version);
+GetOptions(
+ "help|h|?" => \$help,
+ "version|V" => \$print_version,
+ ) or die $usage;
+if ($help) {print($usage); exit 0}
+if ($print_version) { print("edtx2dtx $VERSION\n"); exit 0 }
+die $usage unless @ARGV == 1;
+
+sub begin_macrocode { print("% \\begin{macrocode}\n"); }
+sub end_macrocode { print("% \\end{macrocode}\n"); }
+
+sub process_edtx {
+ my $indoc = 1;
+ while (<>) {
+ if (/^% \\end{macrocode}/) { # trailer starts here
+ end_macrocode unless ($indoc);
+ last;
+ } elsif (/^% \\begin{macrocode}/) {
+ die "Nested \\begin{macrocode}";
+ } elsif (/^ *(%%+)/) { # code: multiple comments
+ begin_macrocode if ($indoc);
+ print;
+ $indoc = 0;
+ } elsif (/^%(<[^>]*>)(.*)$/) { # code: unindented guard
+ begin_macrocode if ($indoc);
+ print;
+ $indoc = 0;
+ } elsif (/^( *)%(<[^>]*>) *(.*)$/) { # code: indented guard
+ begin_macrocode if ($indoc);
+ print("%$2$1$3\n");
+ $indoc = 0;
+ } elsif (/^% *(.*)$/) { # doc: unindented comment
+ end_macrocode unless ($indoc);
+ print;
+ $indoc = 1;
+ } elsif (/^( ?)( *)% *(.*)$/) { # doc: indented comment
+ end_macrocode unless ($indoc);
+ print "%$2$3\n";
+ $indoc = 1;
+ } else { # code
+ begin_macrocode if ($indoc);
+ print;
+ $indoc = 0;
+ }
+ }
+}
+
+my $edtx = @ARGV[0];
+my $dtx = $edtx;
+$dtx =~ s/\.edtx$/.dtx/;
+
+my $first = 1;
+while (<>) {
+ if ($first and s/$edtx +(.*)/$dtx (generated from $edtx by edtx2dtx)/) {
+ print;
+ $first = 0;
+ } elsif (/^% \\begin{macrocode}/) {
+ process_edtx;
+ } elsif (/^% \\end{macrocode}/) {
+ die "\\end{macrocode} without the opening \\begin{macrocode}!";
+ } else {
+ print;
+ }
+}
+
+
diff --git a/support/texshop/README.txt b/support/texshop/README.txt
index f54b08d35d..cd08ec751f 100644
--- a/support/texshop/README.txt
+++ b/support/texshop/README.txt
@@ -7,4 +7,4 @@ The main author is Richard Koch, koch@uoregon.edu, with supporting contributions
Consult the program web site, https://pages.uoregon.edu/koch/texshop/texshop.html,
for full source code, an extensive Changes document, and other information.
-The current version, 5.18, was released on September 21, 2023. \ No newline at end of file
+The current version, 5.20, was released on October 10, 2023. \ No newline at end of file
diff --git a/support/texshop/texshop518.html b/support/texshop/texshop518.html
deleted file mode 100644
index a5dddd5d06..0000000000
--- a/support/texshop/texshop518.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
- <title>TeXShop</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <style type="text/css" media="screen">@import "v1.css";</style>
-</head>
-
-<body>
-
-Modern versions of
-Ghostscript do not process transparency operators in ps files unless the flag -dALLOWSPSTRANSPARENCY is added to the function call. In TeXShop 5.18, a preference item titled "Ghostscript Options" under the Typesetting tab can be checked to activate the flag.
-This activation only applies in two circumstances:
-<p><ul>
-<li> When TeXShop opens a postscript file, it calls ps2pdf to convert the postscript to pdf and opens the pdf file.
-Without the flag, transparency will be ignored in the ps file. With the flag, it will be respected.
-<p><li> When TeXShop typesets files in DVI mode, it runs TeX or LaTeX to create a dvi file, runs
-dvips to create a postscript file, converts the postscript file to pdf using ps2pdf, and displays the pdf file.
-Projects typeset in this way can use the package pstricks for extra typesetting effects, and pstricks can add transparency to illustrations. Typesetting
-will only preserve transparency if the flag is set.
-</ul>
-<p>The flag requires Ghostscript 9.51 or higher. It has no effect when used with earlier versions of Ghostscript.
-<p> The flag is added (in DVI mode) only if the user has not added "--distillerops" to the simpdftex preference settings.
-TeXShop does not want to interfere with users who are carefully controlling the Ghostscript flags themselves.
-<p> This preference item should still work when users supply their own Ghostscript, possibly from macports or homebrew, but that has not been tested.
-<p> Two sample files are provided for experimentation with the new setting. Select the TeXShop menu "Open ~/Library/TeXShop" and navigate to
-the folder New/Version-5.18. This folder contains two files which can be copied to your home directory:
-Transparency.ps and Transparency.tex. Open Transparency.ps in TeXShop. If the new item is not selected, the ruler in the illustration will cover the material underneath. If the new item is selected, the ruler will be partially transparent and show items underneath. Typeset the source file Transparency.tex to see the same change of behavior when typesetting in DVI mode. These samples were provided by Antonis Tsolomitis, with email address <a href="atsol@aegean.gr">atsol@aegean.gr</a> and web url
-<a href="https://myria.math.aegean.gr/~atsol/newpage-en/">https://myria.math.aegean.gr/~atsol/newpage-en/</a>.
-<p> When new typesetting methods become available or older methods require new flags to operate properly, the changes are generally handled in TeXShop by creating new engine files. Herbert Schulz created such engines for transparency, available in ~/Library/TeXShop/Engines/Inactive/GhostscriptTransparencyEngines. The new preference
-item does not affect these engines, and the engines are more flexible than the preference setting, handling for instance versions of Ghostscript earlier than 9.51. Use Herbert's engines for full control. The new preference is for users who run into a problem and want to click a box for a quick solution.
-
-<p> The following changes were also made:
-<p><ul>
-<li> In Single Window mode, after typesetting a project with a root file the root source was brought forward even if the "Continue Editing" preference was selected. This behavior has been fixed by Matthias Schmidt.
-<p><li>Uwe Schmock improved the formatting of the TeXShop Manual.
-</ul>
-
-</body>
-</html>
diff --git a/support/texshop/texshop520.html b/support/texshop/texshop520.html
new file mode 100644
index 0000000000..c083d0d097
--- /dev/null
+++ b/support/texshop/texshop520.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>TeXShop</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <style type="text/css" media="screen">@import "v1.css";</style>
+</head>
+
+<body>
+
+Version 5.19 was never released. The following changes were made in 5.20:
+<p><ul>
+<li> Some people complained that line numbers in the source file are too small to read. A new preference under the "Source" tab allows users to choose between small and large line numbers.
+
+<p><li> The Typst project by Martin Haug and Laurenz Mädje is a complete rewrite of both the input language and the typesetting abilities of TeX and LaTeX. See <a href="https://typst.app">https://typst.app</a> for details. A TeXShop user, Jeroen Scheerder, recently created an engine file that allows TeXShop to typeset Typst sources. Version 5.20 of TeXShop contains that engine in ~/Library/TeXShop/Engines/Inactive/Typst. This folder also contains simple typst source files, called templates, and instructions explaining how to download and install typst. Thus users can
+easily experiment with Typst using TeXShop.
+
+<p><li> Typst source files have extension ".typ". This file extension was added to the list of extensions that TeXShop is willing to create and open, and to the list of file types that TeXShop can typeset. Moreover, source files with extension ".typ"
+can be added to ~/Library/TeXShop/Templates and then will appear in the Templates pulldown menu in the source window.
+
+<p><li> Version 5.18 of TeXShop contains a preference which adds a flag whenever Ghostscript is called telling the program to process transparency operators. This flag is understood by Ghostscript 9.51 and later, so TeXShop has code which checks the version of Ghostscript running, and does not add the flag when the version is earlier than 9.51.
+But very shortly after the release of TeXShop 5.18, Matthias Schmidt read that code and discovered that it did nothing because it was deactivated by a line of debugging code I forgot to remove. I silently fixed the bug and most people updating to version 5.18 received a version without this bug. Since the bug was minor, I decided not to release a new version just to fix it. It is fixed for everyone in version 5.20.
+
+<p><li> The TeXShop manual was updated slightly to describe the changes in version 5.20. Uwe Schmock has also improved the manual and some of his changes are in the latest version.
+
+<p><li> Max Horn runs an important web site which may be unknown to most TeXShop users. The site is
+<a href="https://github.com/TeXShop/TeXShop">https://github.com/TeXShop/TeXShop</a> and contains
+the source code for most versions of TeXShop since the program began. While the Horn site was under construction,
+I sent him old sources obtained by turned on computers that had last run twenty years ago; they started right up! That is how I found the original sources for the earliest TeXShop, which are linked from the the main TeXShop page,
+<a href="https://pages.uoregon.edu/koch/texshop/texshop.html">https://pages.uoregon.edu/koch/texshop/texshop.html</a>.
+
+<p> I am ashamed to admit that git remains a mystery to me. So Horn has access to valuable information I know nothing about. Here's an example. Horn recently reported that the 5.18 sources suddenly contained a complete copy of the final program. That was 90 megs of useless information. Sure enough, a copy had accidentally been saved in the wrong spot.
+This problem was immediately fixed on the web, but I'm gradually digesting a list from Horn of other elements in the current sources that are probably no longer relevant.
+
+
+</ul>
+
+</body>
+</html>
diff --git a/systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl b/systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
index 8e86a80cd6..f776baef92 100644
--- a/systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
+++ b/systems/texlive/tlnet/tlpkg/installer/ctan-mirrors.pl
@@ -55,9 +55,6 @@ $mirrors = {
'Taiwan' => {
'https://ctan.mirror.twds.com.tw/tex-archive/' => 1,
},
- 'Thailand' => {
- 'https://mirror.kku.ac.th/CTAN/' => 1,
- },
},
'Europe' => {
'Austria' => {
@@ -176,10 +173,8 @@ $mirrors = {
'https://mirror.quantum5.ca/CTAN/' => 1,
'https://muug.ca/mirror/ctan/' => 1,
},
- 'Costa Rica' => {
- 'https://mirrors.ucr.ac.cr/CTAN/' => 1,
- },
'USA' => {
+ 'http://mirrors.ibiblio.org/pub/mirrors/CTAN/' => 1,
'https://ctan.math.illinois.edu/' => 1,
'https://ctan.math.utah.edu/ctan/tex-archive/' => 1,
'https://ctan.math.washington.edu/tex-archive/' => 1,
diff --git a/systems/texlive/tlnet/tlpkg/texlive.tlpdb b/systems/texlive/tlnet/tlpkg/texlive.tlpdb
index f62b971ddd..c950084c40 100644
--- a/systems/texlive/tlnet/tlpkg/texlive.tlpdb
+++ b/systems/texlive/tlnet/tlpkg/texlive.tlpdb
@@ -26,11 +26,11 @@ depend container_split_src_files/1
depend frozen/0
depend minrelease/2016
depend release/2023
-depend revision/68508
+depend revision/68516
name 00texlive.image
category TLCore
-revision 68496
+revision 68515
shortdesc TeX Live files only in the source repository
longdesc The files here are not copied by the installer and containers
longdesc are not built for them; they exist only in the source
@@ -40,7 +40,7 @@ longdesc IgnorePatterns in the check_files routine in tlmgr.pl augment
longdesc this list. Those are not included in the source/ tarball. For
longdesc information on the 00texlive prefix see
longdesc 00texlive.installation(.tlpsrc)
-runfiles size=13155
+runfiles size=13157
.mkisofsrc
autorun.inf
texmf-dist/README
@@ -420,6 +420,7 @@ runfiles size=13155
tlpkg/tlpsrc/adrconv.tlpsrc
tlpkg/tlpsrc/adtrees.tlpsrc
tlpkg/tlpsrc/advdate.tlpsrc
+ tlpkg/tlpsrc/advice.tlpsrc
tlpkg/tlpsrc/ae.tlpsrc
tlpkg/tlpsrc/aeguill.tlpsrc
tlpkg/tlpsrc/aesupp.tlpsrc
@@ -1137,6 +1138,7 @@ runfiles size=13155
tlpkg/tlpsrc/codicefiscaleitaliano.tlpsrc
tlpkg/tlpsrc/coelacanth.tlpsrc
tlpkg/tlpsrc/coffeestains.tlpsrc
+ tlpkg/tlpsrc/collargs.tlpsrc
tlpkg/tlpsrc/collcell.tlpsrc
tlpkg/tlpsrc/collectbox.tlpsrc
tlpkg/tlpsrc/collection-basic.tlpsrc
@@ -1561,6 +1563,7 @@ runfiles size=13155
tlpkg/tlpsrc/easy-todo.tlpsrc
tlpkg/tlpsrc/easy.tlpsrc
tlpkg/tlpsrc/easybook.tlpsrc
+ tlpkg/tlpsrc/easydtx.tlpsrc
tlpkg/tlpsrc/easyfig.tlpsrc
tlpkg/tlpsrc/easyfloats.tlpsrc
tlpkg/tlpsrc/easyformat.tlpsrc
@@ -1712,6 +1715,7 @@ runfiles size=13155
tlpkg/tlpsrc/etl.tlpsrc
tlpkg/tlpsrc/etoc.tlpsrc
tlpkg/tlpsrc/etoolbox-de.tlpsrc
+ tlpkg/tlpsrc/etoolbox-generic.tlpsrc
tlpkg/tlpsrc/etoolbox.tlpsrc
tlpkg/tlpsrc/etsvthor.tlpsrc
tlpkg/tlpsrc/euclideangeometry.tlpsrc
@@ -2893,6 +2897,7 @@ runfiles size=13155
tlpkg/tlpsrc/memexsupp.tlpsrc
tlpkg/tlpsrc/memoir.tlpsrc
tlpkg/tlpsrc/memoirchapterstyles.tlpsrc
+ tlpkg/tlpsrc/memoize.tlpsrc
tlpkg/tlpsrc/memory.tlpsrc
tlpkg/tlpsrc/memorygraphs.tlpsrc
tlpkg/tlpsrc/mendex-doc.tlpsrc
@@ -4807,7 +4812,7 @@ depend setting_available_architectures:aarch64-linux amd64-freebsd amd64-netbsd
name 00texlive.installer
category TLCore
-revision 68498
+revision 68510
shortdesc TeX Live standalone installer package
longdesc This package defines the files to go into the installer
longdesc archives (install-tl-unx.tar.gz, install-tl.zip) built by the
@@ -10143,6 +10148,44 @@ catalogue-ctan /macros/latex/contrib/advdate
catalogue-license lppl1.3
catalogue-topics date-time
+name advice
+category Package
+revision 68511
+shortdesc Extend commands and environments
+relocated 1
+longdesc Like its namesake from the Emacs world, this cross-format
+longdesc package implements a generic framework for extending the
+longdesc functionality of selected commands and environments. It was
+longdesc developed as an auxiliary package of Memoize. This is why it
+longdesc is, somewhat unconventionally, documented alongside that
+longdesc package. This applies to both the manual and the documented
+longdesc code listing.
+containersize 4632
+containerchecksum 48d59b89dfd721f4383bb0c34c746e4ca745f82348d0e213ebc91163ddac3b78f64af28b716aca9170c639db4d4f16bad83f8d5e5944454bd3137dcc6898f6e5
+doccontainersize 7584
+doccontainerchecksum fd691b94d7497a0f226063d226a6f890a9719de2711cd41ffe9503a5f69126aab7965e8d32d3256d7300b315269af95cf8564506949ce693ed65a068ccfd95e8
+docfiles size=8
+ RELOC/doc/generic/advice/FILES
+ RELOC/doc/generic/advice/INSTALL.md
+ RELOC/doc/generic/advice/LICENCE
+ RELOC/doc/generic/advice/README.md details="Readme"
+srccontainersize 12808
+srccontainerchecksum e2e8588aa800ed7625fe45eef792a1471a4552b97dcce0821f2efe54b6e035b29f19c78956433b961a4931c02da5b818a82260aed7748aabf9594fac5b16cea1
+srcfiles size=14
+ RELOC/source/generic/advice/Makefile
+ RELOC/source/generic/advice/advice.edtx
+ RELOC/source/generic/advice/advice.ins
+runfiles size=13
+ RELOC/tex/context/advice/t-advice.tex
+ RELOC/tex/generic/advice/advice-tikz.code.tex
+ RELOC/tex/latex/advice/advice.sty
+ RELOC/tex/plain/advice/advice.tex
+catalogue-contact-repository https://github.com/sasozivanovic/memoize
+catalogue-ctan /macros/generic/advice
+catalogue-license lppl1.3c
+catalogue-topics macro-def macro-supp macro-gen
+catalogue-version 1.0.0
+
name ae
category Package
revision 15878
@@ -69194,6 +69237,44 @@ catalogue-license pd
catalogue-topics graphics pgf-tikz amusements
catalogue-version 0.5.1
+name collargs
+category Package
+revision 68512
+shortdesc Collect arguments of any command
+relocated 1
+longdesc This is a cross-format package providing a command which can
+longdesc determine the argument scope of any command whose argument
+longdesc structure conforms to xparse's argument specification. It was
+longdesc implemented as an auxiliary package of Advice ... which in turn
+longdesc was implemented as an auxiliary package of Memoize. This is why
+longdesc it is, somewhat unconventionally, documented alongside that
+longdesc package. This applies to both the manual and the documented
+longdesc code listing.
+containersize 8496
+containerchecksum 14de3dbea8268290c043444be98074b56a5bab11e5106bf8df15fef7384f06d49a68a5ab3eb5d6918886724513dc3fb229df1e0b94043f9111f956a63776a436
+doccontainersize 7528
+doccontainerchecksum 266a0132f273f05a0ec7b0a7a9dbccba223f27f923a521efe2cd4d79e82c314b88a9d5264a8ab6ba6168207f7e1d66fb0db6c980d0edcc1b6fe6b9f0827a43ce
+docfiles size=8
+ RELOC/doc/generic/collargs/FILES
+ RELOC/doc/generic/collargs/INSTALL.md
+ RELOC/doc/generic/collargs/LICENCE
+ RELOC/doc/generic/collargs/README.md details="Readme"
+srccontainersize 24988
+srccontainerchecksum 037100f82a93c880a45a90f911b086e86f4855d888c52d987df946011d41d70acc7d0929bc8f5fd513e52bed9f9b57006e218b35a9e50c90b28707bf60dd754b
+srcfiles size=29
+ RELOC/source/generic/collargs/Makefile
+ RELOC/source/generic/collargs/collargs.edtx
+ RELOC/source/generic/collargs/collargs.ins
+runfiles size=33
+ RELOC/tex/context/collargs/t-collargs.tex
+ RELOC/tex/latex/collargs/collargs.sty
+ RELOC/tex/plain/collargs/collargs.tex
+catalogue-contact-repository https://github.com/sasozivanovic/memoize
+catalogue-ctan /macros/generic/collargs
+catalogue-license lppl1.3c
+catalogue-topics macro-supp macro-gen
+catalogue-version 1.0.0
+
name collcell
category Package
revision 64967
@@ -69494,7 +69575,7 @@ containerchecksum 652554e2038407c987a3aaf73f206b228728ec7848c737de8c6267abb0b200
name collection-binextra
category Collection
-revision 68232
+revision 68514
shortdesc TeX auxiliary programs
relocated 1
longdesc Myriad additional TeX-related support programs. Includes
@@ -69535,6 +69616,7 @@ depend dviout-util
depend dvipng
depend dvipos
depend dvisvgm
+depend easydtx
depend findhyph
depend fragmaster
depend git-latexdiff
@@ -69607,8 +69689,8 @@ depend web
depend xindex
depend xindy
depend xpdfopen
-containersize 988
-containerchecksum e28d3abe47d6ce15bf31f0416f3ce61616e1f93638d394a211864a199e6570d76d5cf3e358c0dfa9c055f4772966d158799330f5c2f270d3c5b60f5c209afcfe
+containersize 996
+containerchecksum 849fd368e654d2eb9e17c7345a92586b9ad9675fc6ea498128d99284776e911562e21718ec545926ccd6af6bdd4d02701ee91faf08940dd60c97e042477aa605
name collection-context
category Collection
@@ -73187,7 +73269,7 @@ containerchecksum 951e172129275fa2cb7ccea6bf23f27484503533ebee4c3bef7d2f4ddda594
name collection-pictures
category Collection
-revision 68464
+revision 68515
shortdesc Graphics, pictures, diagrams
relocated 1
longdesc Including TikZ, pict, etc., but MetaPost and PStricks are
@@ -73283,6 +73365,7 @@ depend luasseq
depend maker
depend makeshape
depend mathspic
+depend memoize
depend mercatormap
depend milsymb
depend miniplot
@@ -73441,18 +73524,19 @@ depend worldflags
depend xistercian
depend xpicture
depend xypic
-containersize 1624
-containerchecksum a51a885c1f2600fa08da2a787e7093533d9fdd540c5d1dd4a1f19e20cdfb2795dd58f55a22ab3d82af6bbacb64fbd37a63e2d67b4e537a204d7ce10332859d08
+containersize 1628
+containerchecksum a8e03b8c6d4f00099f700ab7a04304baaf625ef7705816794fe86ccf69b83eb4e8e1a760ea7ac66868d5b8bd3579a4ef79de5a12310f8944487f43df7b7dab19
name collection-plaingeneric
category Collection
-revision 67486
+revision 68513
shortdesc Plain (La)TeX packages
relocated 1
longdesc Add-on packages and macros that work with plain TeX, often
longdesc LaTeX, and occasionally other formats.
depend abbr
depend abstyles
+depend advice
depend apnum
depend autoaligne
depend barr
@@ -73461,6 +73545,7 @@ depend borceux
depend c-pascal
depend catcodes
depend chronosys
+depend collargs
depend collection-basic
depend colorsep
depend compare
@@ -73475,6 +73560,7 @@ depend encxvlna
depend epigram
depend epsf
depend epsf-dvipdfmx
+depend etoolbox-generic
depend expex-acro
depend expkv-bundle
depend fenixpar
@@ -73562,8 +73648,8 @@ depend xintsession
depend xlop
depend yax
depend zztex
-containersize 984
-containerchecksum a8d3ee4032870cd570d5d786764a252b8020ea7ce95c0b3f6cebab65f8ec5e7fc7d852b8f825ac918ab3c8e7b530874854504d12caa87a56cccd881d80f43567
+containersize 1000
+containerchecksum 843b4a12c44b875cb79334b3bb7def0daafd033f27a1811421ed5bd50179a8013bceeaafad4a565027a3b434312eed913437ab346b22f281ee1592b186739718
name collection-pstricks
category Collection
@@ -76014,7 +76100,7 @@ catalogue-version 0.1.1
name context
category Package
-revision 67039
+revision 68515
shortdesc The ConTeXt macro package
longdesc A full featured, parameter driven macro package, which fully
longdesc supports advanced interactive documents. See the ConTeXt garden
@@ -76027,10 +76113,10 @@ depend luatex
depend manfnt-font
depend mflogo-font
depend stmaryrd
-containersize 8269444
-containerchecksum e547555be09dd2ffa82f7d1b11ff51960865d049beddf46fd04d1de9fcbd49ecd00d67022b392d110e9524189dacf863f7bdf3ab6108a70f8ac4d598038666ab
-doccontainersize 84865880
-doccontainerchecksum 183c488ad7be191a7571c83f3a48b8a1631c98fc8e833a1ea2615af96ea5dc2c02bc071847e2d51e46427271974e1405202e5da788a2ecad8186fb151dc34406
+containersize 8290160
+containerchecksum 9d1b17aab8c4094b3d98be37644d74458021bd67171ac0f2706e65ff9d453cd18fe86c5db6ae8b182d2e6f68939ed6a6906a0304634e70f355997152d59a9e10
+doccontainersize 84859828
+doccontainerchecksum 0ed8385b2db14162a17bf3e2d47881c5d00e5de394771aa948ae50efd6d4e019a6d3221f4014dcc8c2e923c4d964a9811f206d6e28bb46b391fd87f18d83820a
docfiles size=26897
texmf-dist/doc/context/README.adoc
texmf-dist/doc/context/documents/general/leaflets/leaflet-context.pdf
@@ -77407,7 +77493,7 @@ docfiles size=26897
texmf-dist/doc/man/man1/mtx-youless.man1.pdf
texmf-dist/doc/man/man1/mtxrun.1
texmf-dist/doc/man/man1/mtxrun.man1.pdf
-runfiles size=13919
+runfiles size=13947
texmf-dist/bibtex/bst/context/mkii/cont-ab.bst
texmf-dist/bibtex/bst/context/mkii/cont-au.bst
texmf-dist/bibtex/bst/context/mkii/cont-no.bst
@@ -77654,6 +77740,7 @@ runfiles size=13919
texmf-dist/scripts/context/perl/pdftrimwhite.pl
texmf-dist/scripts/context/perl/texfind.pl
texmf-dist/scripts/context/perl/texfont.pl
+ texmf-dist/tex/context/advice/t-advice.tex
texmf-dist/tex/context/base/context-version.pdf
texmf-dist/tex/context/base/context-version.png
texmf-dist/tex/context/base/context.rme
@@ -79441,6 +79528,7 @@ runfiles size=13919
texmf-dist/tex/context/base/mkxl/util-sac.lmt
texmf-dist/tex/context/base/mkxl/util-sbx.lmt
texmf-dist/tex/context/bib/common/sample.bib
+ texmf-dist/tex/context/collargs/t-collargs.tex
texmf-dist/tex/context/colors/icc/context/colorprofiles.lua
texmf-dist/tex/context/colors/icc/context/colorprofiles.xml
texmf-dist/tex/context/filenames.pdf
@@ -79818,6 +79906,9 @@ runfiles size=13919
texmf-dist/tex/context/interface/mkiv/i-whitespace.xml
texmf-dist/tex/context/interface/mkiv/i-xml.xml
texmf-dist/tex/context/interface/mkiv/i-xtable.xml
+ texmf-dist/tex/context/memoize/t-memoizable.tex
+ texmf-dist/tex/context/memoize/t-memoize.tex
+ texmf-dist/tex/context/memoize/t-nomemoize.tex
texmf-dist/tex/context/modules/common/s-cdr-01.tex
texmf-dist/tex/context/modules/common/s-faq-00.tex
texmf-dist/tex/context/modules/common/s-faq-01.tex
@@ -104372,6 +104463,173 @@ catalogue-license lppl1.3c
catalogue-topics book-pub dissertation class doc-templ chinese expl3
catalogue-version 1.71D
+name easydtx
+category Package
+revision 68514
+shortdesc A simplified DTX format
+longdesc EasyDTX is a variant of the DTX format which eliminates the
+longdesc need for all those pesky "macrocode" environments. Any line
+longdesc introduced by a single comment counts as documentation, and
+longdesc documentation lines may be indented. An .edtx file is converted
+longdesc to a .dtx by a little Perl script called edtx2dtx. There is
+longdesc also a rudimentary Emacs mode, implemented in
+longdesc easydoctex-mode.el, which takes care of fontification,
+longdesc indentation, and forward and inverse search.
+depend easydtx.ARCH
+containersize 1812
+containerchecksum f3297c900999197a5acbd73b931bffb21cc989296777b4884d62792d283490e46b06282ae5ce0cf3b0411690432dfa442a4f00c693f4d6677b9ced6037234914
+doccontainersize 27256
+doccontainerchecksum 2f9fe3dd6b2ee2d326a05de9f38966f26ea5baa154c3d7fdecea4af944dd041858b9e66f593b1a246bc6a3fe7d44d64fe1ddcb72e2495917bf8f4ad38b6531c5
+docfiles size=18
+ texmf-dist/doc/man/man1/edtx2dtx.1
+ texmf-dist/doc/man/man1/edtx2dtx.man1.pdf
+ texmf-dist/doc/support/easydtx/FILES
+ texmf-dist/doc/support/easydtx/LICENCE
+ texmf-dist/doc/support/easydtx/README.md details="Readme"
+ texmf-dist/doc/support/easydtx/easydoctex-mode.el
+runfiles size=1
+ texmf-dist/scripts/easydtx/edtx2dtx.pl
+catalogue-contact-repository https://github.com/sasozivanovic/easydtx
+catalogue-ctan /support/easydtx
+catalogue-license gpl3+
+catalogue-topics doc-supp
+catalogue-version 0.1.0
+
+name easydtx.aarch64-linux
+category Package
+revision 68514
+shortdesc aarch64-linux files of easydtx
+containersize 344
+containerchecksum e4534ea8e04ce573c62e54a4eb1a3f07dc8f42a071b36aa6f9adb8a2570a65661c73c817928c1d63397743f34b0deaa0ce1118f36341a48096d9778ab8de401c
+binfiles arch=aarch64-linux size=1
+ bin/aarch64-linux/edtx2dtx
+
+name easydtx.amd64-freebsd
+category Package
+revision 68514
+shortdesc amd64-freebsd files of easydtx
+containersize 344
+containerchecksum f3fd2c31946ad9f9cc48823b01f2ad24c9a40c69d0280c5b48b0db2a25d56ca8471ec8a1c24057ffbdb3c6c2188094e5e86fdd5a4e997f04c778257d730a0f3a
+binfiles arch=amd64-freebsd size=1
+ bin/amd64-freebsd/edtx2dtx
+
+name easydtx.amd64-netbsd
+category Package
+revision 68514
+shortdesc amd64-netbsd files of easydtx
+containersize 344
+containerchecksum ee592df9efab8dc712e2480547603c46d1f4e625dbad1109b88db04253a86febcdf57f785c938fdfa6d0866041a085bd75fe820a3e3ae090cbdcd658f646a676
+binfiles arch=amd64-netbsd size=1
+ bin/amd64-netbsd/edtx2dtx
+
+name easydtx.armhf-linux
+category Package
+revision 68514
+shortdesc armhf-linux files of easydtx
+containersize 344
+containerchecksum 2c541212888303b0d78fba47145fe3d72446a8e63551cf4af820e88a593ee8a5b13cdc3a07af9fb0477130e0b0d84c327b104d84149e422f1fa94c8543c142ce
+binfiles arch=armhf-linux size=1
+ bin/armhf-linux/edtx2dtx
+
+name easydtx.i386-freebsd
+category Package
+revision 68514
+shortdesc i386-freebsd files of easydtx
+containersize 344
+containerchecksum 36aed48666fbb4bcae5f127750a020bdfa98eadc7cebb0731d892e49d4605cdb142c84e7bf845dc840a484f0cebe7e4be32dba155891bc7d7a2d045ee952652f
+binfiles arch=i386-freebsd size=1
+ bin/i386-freebsd/edtx2dtx
+
+name easydtx.i386-linux
+category Package
+revision 68514
+shortdesc i386-linux files of easydtx
+containersize 344
+containerchecksum 80474040adebf765c6ece10b4a1b56bf121db3ad530b80138287b938d992c98dea3c3bddc94f19f938995aac2cf0c2bd45409a3bdb09e5465909fb180f217de4
+binfiles arch=i386-linux size=1
+ bin/i386-linux/edtx2dtx
+
+name easydtx.i386-netbsd
+category Package
+revision 68514
+shortdesc i386-netbsd files of easydtx
+containersize 344
+containerchecksum e3cca250499757618113cabbf20ba5ce6bfa73afb67db495e02b8f9197b262aff318868211f03b0625d57eab7dd205111944bf3d24ed712d8539e1515bbc7ebc
+binfiles arch=i386-netbsd size=1
+ bin/i386-netbsd/edtx2dtx
+
+name easydtx.i386-solaris
+category Package
+revision 68514
+shortdesc i386-solaris files of easydtx
+containersize 344
+containerchecksum 9e69ecb8ad05659cd650f261404849c368ded817d0785fb1737cf1a5bc916113260c9ab56a1767f35310c0791035d5c6803ea277359de7bc588b2389c589230e
+binfiles arch=i386-solaris size=1
+ bin/i386-solaris/edtx2dtx
+
+name easydtx.universal-darwin
+category Package
+revision 68514
+shortdesc universal-darwin files of easydtx
+containersize 348
+containerchecksum 944f3db6f93f2dfdf348d33299d03708093a187d22be8f4064c502ec6ffe833148e65fb4fae6023985acd8b92e22d6edaa74d913b887daba1cd84c0dcbd794b7
+binfiles arch=universal-darwin size=1
+ bin/universal-darwin/edtx2dtx
+
+name easydtx.windows
+category Package
+revision 68514
+shortdesc windows files of easydtx
+containersize 2304
+containerchecksum 6681ccb604c3528bb96fa4707ff03ce723a4bef5b26cd4ae5bb2d9b97e7ac8c5f2e9f3200a5ccc7efb775de6536137b1061b162fb0446abb325cd0edde128f57
+binfiles arch=windows size=2
+ bin/windows/edtx2dtx.exe
+
+name easydtx.x86_64-cygwin
+category Package
+revision 68514
+shortdesc x86_64-cygwin files of easydtx
+containersize 344
+containerchecksum 71cead576d6de0ba6c238e7693d44c8e3be09ddf6455b2faa210b15297b92911d116391a8d5a1d9305003503dbbe9cce3b3ca1825e7273589d7d64447916684b
+binfiles arch=x86_64-cygwin size=1
+ bin/x86_64-cygwin/edtx2dtx
+
+name easydtx.x86_64-darwinlegacy
+category Package
+revision 68514
+shortdesc x86_64-darwinlegacy files of easydtx
+containersize 352
+containerchecksum fb4ae9b583de339c5f6b5f9fdaf29b7a346f9d4e340f6c7f10481d530eae31538a46051aa285ea4e31499003d91c60330be9caed19e109ba33cf2c670c1cf383
+binfiles arch=x86_64-darwinlegacy size=1
+ bin/x86_64-darwinlegacy/edtx2dtx
+
+name easydtx.x86_64-linux
+category Package
+revision 68514
+shortdesc x86_64-linux files of easydtx
+containersize 344
+containerchecksum 264cfdeabd0ce6b3fbd45238e3bb9c5bdc7dfd0b6fe9e3b2aeb2b2ffd23f3e6cccfb396668494818bc73b01acd790ee193f91f57635e99e745d7b3340450fafd
+binfiles arch=x86_64-linux size=1
+ bin/x86_64-linux/edtx2dtx
+
+name easydtx.x86_64-linuxmusl
+category Package
+revision 68514
+shortdesc x86_64-linuxmusl files of easydtx
+containersize 348
+containerchecksum 75d1467a7d42409d50c7627adc144ddf391d5afb68628d80e632c9c3c522f1959d79420764f5e5bf41aaf335b0dfc15052744457e26c1199c1623a351983d40e
+binfiles arch=x86_64-linuxmusl size=1
+ bin/x86_64-linuxmusl/edtx2dtx
+
+name easydtx.x86_64-solaris
+category Package
+revision 68514
+shortdesc x86_64-solaris files of easydtx
+containersize 344
+containerchecksum 1744755c8efb9fd572d842187dff91c5e858497893fdb7b2fc7ab4e8333c9ecdcc50aa463b2f4302261142134df678c6e4f35649d801798986d091c8ca3ab6d8
+binfiles arch=x86_64-solaris size=1
+ bin/x86_64-solaris/edtx2dtx
+
name easyfig
category Package
revision 64967
@@ -116091,6 +116349,29 @@ catalogue-license lppl
catalogue-topics german-doc translation macro-supp
catalogue-version 1
+name etoolbox-generic
+category Package
+revision 68513
+shortdesc A loader for etoolbox.sty in non-LaTeX formats
+relocated 1
+longdesc This package implements a wrapper which allows the user to load
+longdesc the LaTeX-independent part of LaTeX package etoolbox in other
+longdesc formats. It was implemented as an auxiliary package of Memoize.
+containersize 1748
+containerchecksum 12bb7835b59a33026a0acff3c8f8204bf9b159fa84538332ebd7e4ce7116f3ab0dcdfda075555e595c050dcf96525a67f13ab33757df5e55e21b62c3d08488cf
+doccontainersize 6616
+doccontainerchecksum f877ad6a682abe82d84bbd1e9bd2870d80d5b79a63ef150f0eb4cc9abe0cf07c485b59d55281709027d705843bb7da33cff2eac6d382885ba806068a3a651c7a
+docfiles size=6
+ RELOC/doc/generic/etoolbox-generic/LICENCE
+ RELOC/doc/generic/etoolbox-generic/README.md details="Readme"
+runfiles size=1
+ RELOC/tex/generic/etoolbox-generic/etoolbox-generic.tex
+catalogue-contact-repository https://github.com/sasozivanovic/etoolbox-generic
+catalogue-ctan /macros/generic/etoolbox-generic
+catalogue-license lppl1.3c
+catalogue-topics macro-supp macro-gen etex
+catalogue-version 2.5k
+
name etsvthor
category Package
revision 48186
@@ -169480,7 +169761,7 @@ binfiles arch=x86_64-solaris size=3
name kpathsea
category TLCore
-revision 67318
+revision 68516
shortdesc Path searching library for TeX-related files
longdesc Kpathsea is a library and utility programs which provide path
longdesc searching facilities for TeX file types, including the
@@ -169489,10 +169770,10 @@ longdesc layered on top of a general search mechanism. It is not
longdesc distributed separately, but rather is released and maintained
longdesc as part of the TeX Live sources.
depend kpathsea.ARCH
-containersize 32576
-containerchecksum 99ca8cdfedd25acd2bf9459fc22aab9ec3fa6c94b18b1e11aa969680eebb49a11eab6694ce69158116fc8d30e9c80889f69a375316621083640b1786a9660229
-doccontainersize 1040296
-doccontainerchecksum af7af49856b5431ef87958807241398f1c0ed9da90d973b2021a8aa46e2518e259478800c44e4edbafe8e093153fcc89065b662f20b323606a687caefbf51adf
+containersize 32592
+containerchecksum 3a0e08fd9a7635e282e0fa010594358488e03db40faa305c309f28d307d475573696f3b6091b84eca96e9f25870ccab9ff549cdcc1412e610f6ca8474154b9f9
+doccontainersize 1040300
+doccontainerchecksum de1946896816d6ece6ac8632d8ca0d04212c34ef98009aaca5c7ec593f1c932e67c591d85b12406c7be6f142a59a03345d78279492857502ab2696af76bd35db
docfiles size=577
texmf-dist/doc/info/dir
texmf-dist/doc/info/kpathsea.info
@@ -205578,6 +205859,264 @@ catalogue-license lppl
catalogue-topics use-sample
catalogue-version 1.7e
+name memoize
+category Package
+revision 68515
+shortdesc Externalization of graphics and memoization of compilation results in general
+longdesc Memoize is a package for externalization of graphics and
+longdesc memoization of compilation results in general, allowing the
+longdesc author to reuse the results of compilation-intensive code.
+longdesc Memoize (i) induces very little overhead, as all externalized
+longdesc graphics is produced in a single compilation. It features (ii)
+longdesc automatic recompilation upon the change of code or
+longdesc user-adjustable context, and (iii) automatic externalization of
+longdesc TikZ pictures and Forest trees, easily extensible to other
+longdesc commands and environments. Furthermore, Memoize (iv) supports
+longdesc cross-referencing, TikZ overlays and Beamer, (v) works with all
+longdesc major engines and formats, and (vi) is adaptable to any
+longdesc workflow.
+depend memoize.ARCH
+containersize 19488
+containerchecksum 494badca4a4cc01c470404af8352eac3403b35098d109bb6aebc7f48cb3c8deedb55d97661338fe9d2390fcbd6aa440eded8915fe614c7dbee7cf741cff51c1c
+doccontainersize 2469760
+doccontainerchecksum 53cd5199e4d85c1322fc0d593317c94ff57804d128b0e033e8431f660aa7e4f041a8ab7ff7c59dc45de3de8a85ba4e27dd3c84e784d4833f43dd1926f92a987d
+docfiles size=856
+ texmf-dist/doc/generic/memoize/FILES
+ texmf-dist/doc/generic/memoize/INSTALL.md
+ texmf-dist/doc/generic/memoize/LICENCE
+ texmf-dist/doc/generic/memoize/README.md details="Readme"
+ texmf-dist/doc/generic/memoize/examples-src.zip
+ texmf-dist/doc/generic/memoize/examples.zip
+ texmf-dist/doc/generic/memoize/memoize-clean.1.md
+ texmf-dist/doc/generic/memoize/memoize-code.pdf
+ texmf-dist/doc/generic/memoize/memoize-code.sty
+ texmf-dist/doc/generic/memoize/memoize-code.tex
+ texmf-dist/doc/generic/memoize/memoize-doc-common.sty
+ texmf-dist/doc/generic/memoize/memoize-doc.sty
+ texmf-dist/doc/generic/memoize/memoize-extract.1.md
+ texmf-dist/doc/generic/memoize/memoize.mst
+ texmf-dist/doc/generic/memoize/memoize.pdf details="Package documentation"
+ texmf-dist/doc/generic/memoize/memoize.tex
+ texmf-dist/doc/generic/memoize/yadoc.sty
+ texmf-dist/doc/man/man1/memoize-clean.1
+ texmf-dist/doc/man/man1/memoize-clean.man1.pdf
+ texmf-dist/doc/man/man1/memoize-clean.pl.1
+ texmf-dist/doc/man/man1/memoize-clean.pl.man1.pdf
+ texmf-dist/doc/man/man1/memoize-clean.py.1
+ texmf-dist/doc/man/man1/memoize-clean.py.man1.pdf
+ texmf-dist/doc/man/man1/memoize-extract.1
+ texmf-dist/doc/man/man1/memoize-extract.man1.pdf
+ texmf-dist/doc/man/man1/memoize-extract.pl.1
+ texmf-dist/doc/man/man1/memoize-extract.pl.man1.pdf
+ texmf-dist/doc/man/man1/memoize-extract.py.1
+ texmf-dist/doc/man/man1/memoize-extract.py.man1.pdf
+srccontainersize 38092
+srccontainerchecksum 95e1a189046f2270b17a260e5ad98e4b9752a9a0fd17368fecf0c9b1ebdc752dff0a640f1010dddea482925d0ffe4b39fc34bdb790f8f23a6e2080f39aff01b6
+srcfiles size=38
+ texmf-dist/source/generic/memoize/Makefile
+ texmf-dist/source/generic/memoize/memoize.edtx
+ texmf-dist/source/generic/memoize/memoize.ins
+runfiles size=49
+ texmf-dist/scripts/memoize/memoize-clean.pl
+ texmf-dist/scripts/memoize/memoize-clean.py
+ texmf-dist/scripts/memoize/memoize-extract.pl
+ texmf-dist/scripts/memoize/memoize-extract.py
+ texmf-dist/tex/context/memoize/t-memoizable.tex
+ texmf-dist/tex/context/memoize/t-memoize.tex
+ texmf-dist/tex/context/memoize/t-nomemoize.tex
+ texmf-dist/tex/latex/memoize/memoizable.sty
+ texmf-dist/tex/latex/memoize/memoize.sty
+ texmf-dist/tex/latex/memoize/nomemoize.sty
+ texmf-dist/tex/plain/memoize/memoizable.tex
+ texmf-dist/tex/plain/memoize/memoize-extract-one.tex
+ texmf-dist/tex/plain/memoize/memoize.tex
+ texmf-dist/tex/plain/memoize/nomemoize.tex
+catalogue-contact-repository https://github.com/sasozivanovic/memoize
+catalogue-ctan /macros/generic/memoize
+catalogue-license lppl1.3c
+catalogue-topics compilation ext-code cond-comp macro-gen graphics
+catalogue-version 1.0.0
+
+name memoize.aarch64-linux
+category Package
+revision 68515
+shortdesc aarch64-linux files of memoize
+containersize 396
+containerchecksum cbfee06031e22a73fac55b9d86bf991d0744de7f914a98579a386c8c2dd9575e1cca3e062ff206b521abafb21273c3ae707a60a795f0166fba06727b02e2c49a
+binfiles arch=aarch64-linux size=4
+ bin/aarch64-linux/memoize-clean.pl
+ bin/aarch64-linux/memoize-clean.py
+ bin/aarch64-linux/memoize-extract.pl
+ bin/aarch64-linux/memoize-extract.py
+
+name memoize.amd64-freebsd
+category Package
+revision 68515
+shortdesc amd64-freebsd files of memoize
+containersize 396
+containerchecksum 3dd01c7aad77f1e27d006323d613dd26bd42be222564b6662e83ef726ddc25919699b547c1d967750a7c627167c053363fbddea46f5570c02763f38a89a73a3d
+binfiles arch=amd64-freebsd size=4
+ bin/amd64-freebsd/memoize-clean.pl
+ bin/amd64-freebsd/memoize-clean.py
+ bin/amd64-freebsd/memoize-extract.pl
+ bin/amd64-freebsd/memoize-extract.py
+
+name memoize.amd64-netbsd
+category Package
+revision 68515
+shortdesc amd64-netbsd files of memoize
+containersize 392
+containerchecksum 67eda4d1270e4128c48ee871c137bcbe2865901190e8d75504447183baf41dac58a06d0f1c7cb04e7efbc6c4b849f03c2e7c60d75d5c3e3031aa756f72165c10
+binfiles arch=amd64-netbsd size=4
+ bin/amd64-netbsd/memoize-clean.pl
+ bin/amd64-netbsd/memoize-clean.py
+ bin/amd64-netbsd/memoize-extract.pl
+ bin/amd64-netbsd/memoize-extract.py
+
+name memoize.armhf-linux
+category Package
+revision 68515
+shortdesc armhf-linux files of memoize
+containersize 396
+containerchecksum d6257f711115df78a3376de7c524a8cb0b4a49fcb978ae5125fc04605e91e6e9bac939a388389f0b99490ff72d43415bfed630b9afc19f4cf0d1581ac2719ef3
+binfiles arch=armhf-linux size=4
+ bin/armhf-linux/memoize-clean.pl
+ bin/armhf-linux/memoize-clean.py
+ bin/armhf-linux/memoize-extract.pl
+ bin/armhf-linux/memoize-extract.py
+
+name memoize.i386-freebsd
+category Package
+revision 68515
+shortdesc i386-freebsd files of memoize
+containersize 396
+containerchecksum 6cfc4c9e605bf75b190a4252a93218b2adaab7d5b082b0101bb0b148226da540e119084047ce76d130485e8dda8c20205e76c9af2b69f28d3b82a509072fba8a
+binfiles arch=i386-freebsd size=4
+ bin/i386-freebsd/memoize-clean.pl
+ bin/i386-freebsd/memoize-clean.py
+ bin/i386-freebsd/memoize-extract.pl
+ bin/i386-freebsd/memoize-extract.py
+
+name memoize.i386-linux
+category Package
+revision 68515
+shortdesc i386-linux files of memoize
+containersize 396
+containerchecksum 0d1359ba2459b80503f9714fe2c4f256328b463088f53d714898324f3f524c59060f9500bd991edec0cb3d390c32ee37ca95d09bc95d9339a8c077a4b4cb8e15
+binfiles arch=i386-linux size=4
+ bin/i386-linux/memoize-clean.pl
+ bin/i386-linux/memoize-clean.py
+ bin/i386-linux/memoize-extract.pl
+ bin/i386-linux/memoize-extract.py
+
+name memoize.i386-netbsd
+category Package
+revision 68515
+shortdesc i386-netbsd files of memoize
+containersize 396
+containerchecksum 44d708f2f6b4a80865e404c90f989f555dfd40e4cfbb317b713d8c9fc31ea275ce61a08eaaa30ecc391dc11401e2db69bd90774729318d530d054a8b3f57142f
+binfiles arch=i386-netbsd size=4
+ bin/i386-netbsd/memoize-clean.pl
+ bin/i386-netbsd/memoize-clean.py
+ bin/i386-netbsd/memoize-extract.pl
+ bin/i386-netbsd/memoize-extract.py
+
+name memoize.i386-solaris
+category Package
+revision 68515
+shortdesc i386-solaris files of memoize
+containersize 392
+containerchecksum e22a54f183dde7bb1031c31c3322d3d93568067d1f6f1ef8e51baaa3ca7b416afb052bbd51e5d61130a914741e2f823770e09911abd5188981639b9e2437dc71
+binfiles arch=i386-solaris size=4
+ bin/i386-solaris/memoize-clean.pl
+ bin/i386-solaris/memoize-clean.py
+ bin/i386-solaris/memoize-extract.pl
+ bin/i386-solaris/memoize-extract.py
+
+name memoize.universal-darwin
+category Package
+revision 68515
+shortdesc universal-darwin files of memoize
+containersize 396
+containerchecksum 901dc79c9ec5df8475b28a0be0e9a3011f7ee8ed747491370fd0f2d08002ec6a046bab18ad2c3609ac81f754a043111b28993e8877c013fec8b0c144ec92c7cd
+binfiles arch=universal-darwin size=4
+ bin/universal-darwin/memoize-clean.pl
+ bin/universal-darwin/memoize-clean.py
+ bin/universal-darwin/memoize-extract.pl
+ bin/universal-darwin/memoize-extract.py
+
+name memoize.windows
+category Package
+revision 68515
+shortdesc windows files of memoize
+containersize 2404
+containerchecksum e47ec2bed88abd00c36854f31b9004d7c679a462ebf6517b03196b6644b9a93fac08cc9b20cfb74e9e8a1590b393851b6f05fdc2ad36cc5f485363d102cd4780
+binfiles arch=windows size=8
+ bin/windows/memoize-clean.pl.exe
+ bin/windows/memoize-clean.py.exe
+ bin/windows/memoize-extract.pl.exe
+ bin/windows/memoize-extract.py.exe
+
+name memoize.x86_64-cygwin
+category Package
+revision 68515
+shortdesc x86_64-cygwin files of memoize
+containersize 400
+containerchecksum ac2a9e851788fcf7084cb0f08efda00e616b9f9efbf872aae1c2ea933420e37b718b79331a0bb267f5d9da0dc1c68083fb8992f6892fed4fa49a4af2a6e0b057
+binfiles arch=x86_64-cygwin size=4
+ bin/x86_64-cygwin/memoize-clean.pl
+ bin/x86_64-cygwin/memoize-clean.py
+ bin/x86_64-cygwin/memoize-extract.pl
+ bin/x86_64-cygwin/memoize-extract.py
+
+name memoize.x86_64-darwinlegacy
+category Package
+revision 68515
+shortdesc x86_64-darwinlegacy files of memoize
+containersize 404
+containerchecksum 8730937433bf7ed62a07f483a5e7354c9acee30ec4beaaa510ba5cae3e714bb51e7cacd59489407a318b920079357f52259a91f29336902d6c626efe8da80e52
+binfiles arch=x86_64-darwinlegacy size=4
+ bin/x86_64-darwinlegacy/memoize-clean.pl
+ bin/x86_64-darwinlegacy/memoize-clean.py
+ bin/x86_64-darwinlegacy/memoize-extract.pl
+ bin/x86_64-darwinlegacy/memoize-extract.py
+
+name memoize.x86_64-linux
+category Package
+revision 68515
+shortdesc x86_64-linux files of memoize
+containersize 396
+containerchecksum a1c8e996cc00bc1623a604f5a7ae5f09e8829ba63b8eb113ad74cfcde2c6f9298547e5b25796ccfa7476e59b02917bc2cf426206a76071e0086eb521978c8fd7
+binfiles arch=x86_64-linux size=4
+ bin/x86_64-linux/memoize-clean.pl
+ bin/x86_64-linux/memoize-clean.py
+ bin/x86_64-linux/memoize-extract.pl
+ bin/x86_64-linux/memoize-extract.py
+
+name memoize.x86_64-linuxmusl
+category Package
+revision 68515
+shortdesc x86_64-linuxmusl files of memoize
+containersize 396
+containerchecksum d647707495850c19f2e5227995f0cd9ccea1286b1c14eb73c8ca037dc2e88844463e6b481b9bbedac8f3161f84d5e57bfb972abfaf802d977dee4c80b82e8138
+binfiles arch=x86_64-linuxmusl size=4
+ bin/x86_64-linuxmusl/memoize-clean.pl
+ bin/x86_64-linuxmusl/memoize-clean.py
+ bin/x86_64-linuxmusl/memoize-extract.pl
+ bin/x86_64-linuxmusl/memoize-extract.py
+
+name memoize.x86_64-solaris
+category Package
+revision 68515
+shortdesc x86_64-solaris files of memoize
+containersize 396
+containerchecksum bd76465c19ad24147f69c9a345046150ae7d360db42c778a06a9f8156315a4f40dc6aa45d6614a50d5f56bfae37825f15c730ce29d90f9326cca3b91e6af69aa
+binfiles arch=x86_64-solaris size=4
+ bin/x86_64-solaris/memoize-clean.pl
+ bin/x86_64-solaris/memoize-clean.py
+ bin/x86_64-solaris/memoize-extract.pl
+ bin/x86_64-solaris/memoize-extract.py
+
name memory
category Package
revision 30452
@@ -315601,14 +316140,14 @@ catalogue-version 6.8
name texlive-common
category TLCore
-revision 67094
+revision 68510
shortdesc TeX Live documentation (common elements)
relocated 1
postaction shortcut type=menu name="TeX Live documentation" cmd=TEXDIR/texmf-dist/doc/texlive/index.html
-containersize 344
-containerchecksum 8f68ecc02967fb7a2d6437ddd068276b0450f6febefd1c21b97d69c325cc943c4eb3c9327ba579a5773cb790e71102b6aa738b0154c483a1afabb1d056ef1051
-doccontainersize 708120
-doccontainerchecksum fbb5cd62dce713c7c5507dfd944a296f21599ab08561968043f569ae3c7b3e1943b82ad984e6b030173d85dacfd01f163cecc19a64a1eb47ec1b1b0af1a898b4
+containersize 348
+containerchecksum 1d56101ace5038cd3b8d36c90e026a1c26363535fffbe1ffab64dfbd01408e7cdfb66045e11b13e22491f238e2d3a7015fdeb9bf75fa56f581d2ca5da8f1a01a
+doccontainersize 708156
+doccontainerchecksum c9832e8249440656334db12b6ee54b467fdebe1194b6adbb8d28ee375250bc6458e8c1b48b5684eab0ff2f0b55db4f4ab6e77679df447a01070a15c1243e5d83
docfiles size=224
RELOC/doc/texlive/index.html
RELOC/doc/texlive/install-tl.html
@@ -315917,7 +316456,7 @@ docfiles size=376
name texlive-scripts
category TLCore
-revision 68498
+revision 68510
shortdesc TeX Live infrastructure programs
longdesc Includes install-tl, tl-portable, rungs, etc.; not needed for
longdesc tlmgr to run but still ours. Not included in tlcritical.
@@ -315925,11 +316464,11 @@ depend texlive-scripts.ARCH
depend texlive.infra
execute addMap mathpple.map
postaction shortcut type=menu name="TeX Live command-line" cmd=TEXDIR/tlpkg/installer/tl-cmd.bat
-containersize 114076
-containerchecksum 5f2a9546153ee53545c0a132a1fd4d48232ba487abe5fec94d5fd33fd390a579b242453b0f239e4c1848c44cdcdca6fb26a61354c8fe00f41be07319394a369b
-doccontainersize 430052
-doccontainerchecksum 03715a94905aa6115cd73dce03d50d37ad853cda07b84d1b99e0d056b63cdb48d3fb77f62b190a3c2198e32b6efb8b1cc7dce9111a25d1f6b8bddaa5cecd8d9a
-docfiles size=551
+containersize 114064
+containerchecksum afbd59b86e5b0abefc98cb1e3fa4139432a3f24d13d360107181e742b4f88460ffb4abb494ac4314ef4d1a500a5f9d09a70c0d241a11c0f0fff4f4411f5375cb
+doccontainersize 428524
+doccontainerchecksum e8f19fbc2c5c1c3b29fec8350199ba305975db8cf4b2526a8051194bfb3d44dd46e34212c7f163481a869de17ba03ea02e1708ef9b91440c22d17be680f25315
+docfiles size=550
doc.html
texmf-dist/doc/man/man1/fmtutil-sys.1
texmf-dist/doc/man/man1/fmtutil-sys.man1.pdf
diff --git a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5 b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
index 8eabc076c9..a09343a2ac 100644
--- a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
+++ b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.md5
@@ -1 +1 @@
-fd707ea3695d01b2ebbad5723afa0518 texlive.tlpdb
+71d8f5ab6453405c055e24bc3dbd065d texlive.tlpdb
diff --git a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512 b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
index c737bf4e3d..910245da4f 100644
--- a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
+++ b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512
@@ -1 +1 @@
-35e769fefe735d623899dccd397a0d8811899912e211e35c841ebc4c5848ea7d28208b4bc9988b88127007c4a1849feb4a3578d39060ac371c30921933e1d26c texlive.tlpdb
+cfc866dfcf4d4400de6b9c87116ba3fdb4ee1081fa342ef33d3432855e37af2a484fd1743c328730f7e8ecfc44462241dac02147c048d958ada9e0526248b35b texlive.tlpdb
diff --git a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
index 892f5c1e75..593592d6f8 100644
--- a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
+++ b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.sha512.asc
@@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE-----
-iQEzBAEBCgAdFiEE2PL4YFeoV+QqiBBqTOGHfhlDjHAFAmUl4gIACgkQTOGHfhlD
-jHATYwf/ZXZzREFrxv3BHVctTaXlA6gfG8OdSVkMq2VbOAvDBg8pdP3JVhyVIO+4
-naaF98V9MeuOh2D5k7KRaGyLclr8ONgm+tWXMXfrxo32Kqz7NKTEKqv2HGFyJpyM
-LwA7RUR+TtsuSLDxqjagLjHNajf+slbG88PlCbMCYqYV4IslI5YmZ3h8KJOoYvS4
-MEmgXVdjicOLQrQG+jr6SMAc70UMCwPdtqymuLEyWFZZUV35P4jtZitaN+ELY6Ur
-uOP9ge7H+x2gP4wyY4uHIFA/aXO3BJOEL3fCrg1jsOANNRKJ+7LTrIKf8dVo2zJU
-JMuZOt+oWm56JltYSaFIwYfUwWoS0w==
-=2Bs3
+iQEzBAEBCgAdFiEE2PL4YFeoV+QqiBBqTOGHfhlDjHAFAmUnM7QACgkQTOGHfhlD
+jHDmzQgAgohc3RXOTxnFRNuvVavURvQQQyj7pvOCnwfNxuMoPkpBMZYq9YayUbel
+T2SQ8AB9hQAZlVEB1jnnaEJwl/eqp2TEeP2hwFO+FrmqjvsbLm7qTXCKSRSbuQDG
+D4UhJ8F6rTVeFffEzgfQgi9aR6XWjH2LxWtj2/3Hzjrjz59zoAdkInmR3o5HWf5z
+l+DFO8hQe30lxpraK7J5S6w5kaXnR+KSWoq0MNgNuQKkhJLR5GyprhdnYPCxfRPi
+u0gv7xcquI/lMKfmMsGId1nEy6Xve2ybE3SgXW7akbGhd03ynH0O2380+S8VvskH
+6XhlHAcP+lDh9FzEyiDb8vwVOJrwJw==
+=VtK1
-----END PGP SIGNATURE-----
diff --git a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
index 0a92c5d024..8506d6e664 100644
--- a/systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
+++ b/systems/texlive/tlnet/tlpkg/texlive.tlpdb.xz
Binary files differ
diff --git a/systems/win32/miktex/tm/packages/files.csv.lzma b/systems/win32/miktex/tm/packages/files.csv.lzma
index 1cd952d3d8..12d81877d5 100644
--- a/systems/win32/miktex/tm/packages/files.csv.lzma
+++ b/systems/win32/miktex/tm/packages/files.csv.lzma
Binary files differ
diff --git a/systems/win32/miktex/tm/packages/next/files.csv.lzma b/systems/win32/miktex/tm/packages/next/files.csv.lzma
index d013d9174f..3a226f105b 100644
--- a/systems/win32/miktex/tm/packages/next/files.csv.lzma
+++ b/systems/win32/miktex/tm/packages/next/files.csv.lzma
Binary files differ
diff --git a/systems/win32/miktex/tm/packages/next/pr.ini b/systems/win32/miktex/tm/packages/next/pr.ini
index 8b07516188..15570a8fed 100644
--- a/systems/win32/miktex/tm/packages/next/pr.ini
+++ b/systems/win32/miktex/tm/packages/next/pr.ini
@@ -1,13 +1,13 @@
[repository]
-date=1696929419
+date=1697032708
lastupd=miktex-zzip-bin-x64-2.9 miktex-zlib-bin-x64-2.9 miktex-yap-bin-x64-2.9 miktex-xml2pmx-bin-x64 miktex-xetex-bin-x64-2.9 miktex-web-bin-x64-2.9 miktex-uriparser-bin-x64-2.9 miktex-upmendex-bin-x64 miktex-ttf2pk2-bin-x64-2.9 miktex-texworks-bin-x64-2.9 miktex-texware-bin-x64-2.9 miktex-texify-bin-x64-2.9 miktex-tex4ht-bin-x64-2.9 miktex-tex2xindy-bin-x64-2.9 miktex-tex-bin-x64-2.9 miktex-teckit-bin-x64-2.9 miktex-tdsutil-bin-x64 miktex-synctex-bin-x64-2.9 miktex-runtime-bin-x64-2.9 miktex-ptex-bin-x64
-lstdigest=9c2c945853df7f8d3a35af02dbcb3744
-numpkg=6876
+lstdigest=bc0eb6d2bb66dc147c13bd9de1c27137
+numpkg=6878
relstate=next
-version=8683
+version=8684
;;;;This configuration file is signed by a MiKTeX maintainer. The signature follows.
;;;;-----BEGIN MIKTEX SIGNATURE-----
-;;;; signature/miktex: QwPb5iteCCyO+Pr9rlfvVrGFYVfijkf6seP10MDcm2KZPBdFx5M1lq1LY4iXQqy53nCQ9DsmVHg1FhTAg3vGHRWtCaNGa6I7z1jkcTMnJd2OSEshH7Yd7wrM6r5eZgMNgIoxV5/RtD5H6Ibqa/UpwyBXrQ1mtx/UpjQvcXfU5E+MklVzXs90sXi2obNqa7RDdOcSLPuW3zAOy++F9VBEtO4EA4fuHMHupT5Z+KkrSIOWTp7EfK9IF8D8HTRN9lJKNmtgw+ZNumtzLWqBFPWMbvTk/4L6t1nbQkYSCX8o6gAs7n4ED6Mjuf1FokKuPe0+R4ikKxvp2SzqhE4H6wG4CA==
+;;;; signature/miktex: cJa90wq2bho9Ou5PH9meQR8xQtfa/F32s1n0vTlAC9PFkPx6YQt2+S9GkDXC0Gbs7Z7hwKxxKAL29J97LWvVBX4GCkHLwYdlX/Au+JtXbfC1w1TBM9eevjZ0vYbHdGIdvcOPkm9cXTDKnfkwjea9Imxrbutgnoj9MlVR1wdnTzj+saeqOXzh6QuUqQPiKjUjqJu2KJoH/YbNPrYDwX9cX9fP4uO3WcHMg0xtPCA5gErMnii+HR8CffRiwnZ+GSmrkZpAq7+tdC6QABqfOFHTjAnDBCOmfMInPOvPoQWjtu4qpWNMpSwNeHKjan6tycNb9pdfWr02/4VYJpEvXugOEg==
;;;;-----END MIKTEX SIGNATURE-----
diff --git a/systems/win32/miktex/tm/packages/pr.ini b/systems/win32/miktex/tm/packages/pr.ini
index acb547c75b..4d070b0fae 100644
--- a/systems/win32/miktex/tm/packages/pr.ini
+++ b/systems/win32/miktex/tm/packages/pr.ini
@@ -1,13 +1,13 @@
[repository]
-date=1696929382
-lastupd=tikz-osci__source tikz-osci__doc tikz-osci setspaceenhanced__source setspaceenhanced__doc setspaceenhanced schule__source schule__doc schule proflycee__source proflycee__doc proflycee profcollege__source profcollege__doc profcollege musixtex__doc musixtex msu-thesis__source msu-thesis__doc msu-thesis
-lstdigest=c17fd8e7b84c350a2b6c87ed37078257
-numpkg=6876
+date=1697032598
+lastupd=tkz-bernoulli__source tkz-bernoulli__doc tkz-bernoulli pdfmanagement-testphase__source pdfmanagement-testphase__doc pdfmanagement-testphase non-decimal-units__source non-decimal-units__doc non-decimal-units luatexja__source luatexja__doc luatexja l3packages__source l3packages__doc l3packages l3kernel__source l3kernel__doc l3kernel l3experimental__source l3experimental__doc
+lstdigest=5f77a1d63ed4fa150edfb0a1f3d752c8
+numpkg=6878
relstate=stable
-version=8683
+version=8684
;;;;This configuration file is signed by a MiKTeX maintainer. The signature follows.
;;;;-----BEGIN MIKTEX SIGNATURE-----
-;;;; signature/miktex: M5YkP/zt8uOmk0BzpqyT4ud2BI8234W3L0kFKl7VQRKzOq6QDO5UOHzNcZyMfJOg9ZvyfWNWtZgnQubM0/yNPQmRLhjsWJg2iInVsJg25BLWaMPFKdt5nzNLdPWSoPV2hpME33bQSH5w8hJexa03fzuPvkxNMAHza809Y6zYOxxmqumPHeQy148AyUyHfhOFViQbFlycvbqYZ1JWaj+U/HSkf6hZ20zxzmXeAiSVVIvJYXzD0YY9OzcxOFqYTuU+USRpdNZriHoBIRo8DdNi9l6sEErZ/4/QqKjJMZhzy7B7NGbTEDlRvb6e9pcYD8gXn53oUDg/TuC2Ijnb0sWPlw==
+;;;; signature/miktex: S7TaildV9ugMo2X/1yWJ0VgIt6RbftSLwG6zPD68rJCyhfHQfQpoDt7PMHO/JNNRJwBNWMev/CA47h9CTI2sTNQcpICYhMKjVi84JNR6Ajlwe0IZgX2yZ/d8oMeKmLl0Z99/nxBxZkO3eMqGDnSnxhnxWRh2qLke82TZQcbLh9/4u7WRJDFvJ/WXXwoB9dc0roVVHa5SmS3Vaf6dqv+HltOpNpApvzhp3w6ATiiOwRFOtHzUxzXSGuBnOmIiZfy+XKDoTDGz4CAWUObP72FqkqqLCMLnj/wyBnMB0vR0wyS4WkjU89lA8GHEXDjHPdLUwMGejcay1WPLZ8tylEFKsg==
;;;;-----END MIKTEX SIGNATURE-----
diff --git a/timestamp b/timestamp
index 6b60908a54..0377a21c6c 100644
--- a/timestamp
+++ b/timestamp
@@ -2,4 +2,4 @@
# The source CTAN of this site's material:
dante.ctan.org
# The year-month-day-hour-minute of this site's material:
-2023-10-11-02-02
+2023-10-12-02-02