From 43cbf51d3ee54f8d34fef3921e97937133db01f3 Mon Sep 17 00:00:00 2001 From: George Lambert Date: Tue, 15 Sep 2026 23:10:15 -0400 Subject: [PATCH] S17/S18: send success and failure routes; Sphinx HTML/PDF Python router + Go sm-leaf reject missing to, empty ct, plaintext body. Summary logs never include ciphertext. MODULE.md. --- MODULE.md | 40 + Makefile | 9 + build/html/.buildinfo | 4 + build/html/.doctrees/environment.pickle | Bin 0 -> 14288 bytes build/html/.doctrees/index.doctree | Bin 0 -> 12622 bytes build/html/_sources/index.rst.txt | 40 + build/html/_static/alabaster.css | 663 +++++++++ build/html/_static/base-stemmer.js | 476 +++++++ build/html/_static/basic.css | 906 ++++++++++++ build/html/_static/custom.css | 1 + build/html/_static/doctools.js | 150 ++ build/html/_static/documentation_options.js | 13 + build/html/_static/english-stemmer.js | 1066 +++++++++++++++ build/html/_static/file.png | Bin 0 -> 286 bytes build/html/_static/github-banner.svg | 5 + build/html/_static/language_data.js | 13 + build/html/_static/minus.png | Bin 0 -> 90 bytes build/html/_static/plus.png | Bin 0 -> 90 bytes build/html/_static/pygments.css | 84 ++ build/html/_static/searchtools.js | 693 ++++++++++ build/html/_static/sphinx_highlight.js | 159 +++ build/html/genindex.html | 99 ++ build/html/index.html | 135 ++ build/html/objects.inv | Bin 0 -> 244 bytes build/html/search.html | 117 ++ build/html/searchindex.js | 1 + build/latex/.doctrees/environment.pickle | Bin 0 -> 14289 bytes build/latex/.doctrees/index.doctree | Bin 0 -> 12622 bytes build/latex/LICRcyr2utf8.xdy | 101 ++ build/latex/LICRlatin2utf8.xdy | 239 ++++ build/latex/LatinRules.xdy | 611 +++++++++ build/latex/Makefile | 65 + build/latex/latexmkjarc | 22 + build/latex/latexmkrc | 9 + build/latex/make.bat | 31 + build/latex/python.ist | 16 + build/latex/secure-messaging.aux | 21 + build/latex/secure-messaging.idx | 0 build/latex/secure-messaging.log | 927 +++++++++++++ build/latex/secure-messaging.out | 3 + build/latex/secure-messaging.pdf | Bin 0 -> 99138 bytes build/latex/secure-messaging.tex | 170 +++ build/latex/secure-messaging.toc | 4 + build/latex/sphinx.sty | 1263 +++++++++++++++++ build/latex/sphinx.xdy | 230 ++++ build/latex/sphinxhighlight.sty | 130 ++ build/latex/sphinxhowto.cls | 102 ++ build/latex/sphinxlatexadmonitions.sty | 408 ++++++ build/latex/sphinxlatexcontainers.sty | 22 + build/latex/sphinxlatexgraphics.sty | 123 ++ build/latex/sphinxlatexindbibtoc.sty | 69 + build/latex/sphinxlatexlists.sty | 131 ++ build/latex/sphinxlatexliterals.sty | 1229 +++++++++++++++++ build/latex/sphinxlatexnumfig.sty | 135 ++ build/latex/sphinxlatexobjects.sty | 386 ++++++ build/latex/sphinxlatexshadowbox.sty | 178 +++ build/latex/sphinxlatexstyleheadings.sty | 91 ++ build/latex/sphinxlatexstylepage.sty | 73 + build/latex/sphinxlatexstyletext.sty | 149 ++ build/latex/sphinxlatextables.sty | 1365 +++++++++++++++++++ build/latex/sphinxmanual.cls | 128 ++ build/latex/sphinxmessages.sty | 21 + build/latex/sphinxoptionsgeometry.sty | 54 + build/latex/sphinxoptionshyperref.sty | 35 + build/latex/sphinxpackageboxes.sty | 827 +++++++++++ build/latex/sphinxpackagecyrillic.sty | 55 + build/latex/sphinxpackagefootnote.sty | 439 ++++++ build/latex/sphinxpackagesubstitutefont.sty | 21 + go/internal/leaf/leaf.go | 60 +- go/internal/leaf/leaf_test.go | 73 +- python/secure_messaging/__init__.py | 3 + python/secure_messaging/router.py | 106 ++ source/conf.py | 10 + source/index.rst | 40 + tests/test_sm.py | 38 + 75 files changed, 14878 insertions(+), 9 deletions(-) create mode 100644 MODULE.md create mode 100644 Makefile create mode 100644 build/html/.buildinfo create mode 100644 build/html/.doctrees/environment.pickle create mode 100644 build/html/.doctrees/index.doctree create mode 100644 build/html/_sources/index.rst.txt create mode 100644 build/html/_static/alabaster.css create mode 100644 build/html/_static/base-stemmer.js create mode 100644 build/html/_static/basic.css create mode 100644 build/html/_static/custom.css create mode 100644 build/html/_static/doctools.js create mode 100644 build/html/_static/documentation_options.js create mode 100644 build/html/_static/english-stemmer.js create mode 100644 build/html/_static/file.png create mode 100644 build/html/_static/github-banner.svg create mode 100644 build/html/_static/language_data.js create mode 100644 build/html/_static/minus.png create mode 100644 build/html/_static/plus.png create mode 100644 build/html/_static/pygments.css create mode 100644 build/html/_static/searchtools.js create mode 100644 build/html/_static/sphinx_highlight.js create mode 100644 build/html/genindex.html create mode 100644 build/html/index.html create mode 100644 build/html/objects.inv create mode 100644 build/html/search.html create mode 100644 build/html/searchindex.js create mode 100644 build/latex/.doctrees/environment.pickle create mode 100644 build/latex/.doctrees/index.doctree create mode 100644 build/latex/LICRcyr2utf8.xdy create mode 100644 build/latex/LICRlatin2utf8.xdy create mode 100644 build/latex/LatinRules.xdy create mode 100644 build/latex/Makefile create mode 100644 build/latex/latexmkjarc create mode 100644 build/latex/latexmkrc create mode 100644 build/latex/make.bat create mode 100644 build/latex/python.ist create mode 100644 build/latex/secure-messaging.aux create mode 100644 build/latex/secure-messaging.idx create mode 100644 build/latex/secure-messaging.log create mode 100644 build/latex/secure-messaging.out create mode 100644 build/latex/secure-messaging.pdf create mode 100644 build/latex/secure-messaging.tex create mode 100644 build/latex/secure-messaging.toc create mode 100644 build/latex/sphinx.sty create mode 100644 build/latex/sphinx.xdy create mode 100644 build/latex/sphinxhighlight.sty create mode 100644 build/latex/sphinxhowto.cls create mode 100644 build/latex/sphinxlatexadmonitions.sty create mode 100644 build/latex/sphinxlatexcontainers.sty create mode 100644 build/latex/sphinxlatexgraphics.sty create mode 100644 build/latex/sphinxlatexindbibtoc.sty create mode 100644 build/latex/sphinxlatexlists.sty create mode 100644 build/latex/sphinxlatexliterals.sty create mode 100644 build/latex/sphinxlatexnumfig.sty create mode 100644 build/latex/sphinxlatexobjects.sty create mode 100644 build/latex/sphinxlatexshadowbox.sty create mode 100644 build/latex/sphinxlatexstyleheadings.sty create mode 100644 build/latex/sphinxlatexstylepage.sty create mode 100644 build/latex/sphinxlatexstyletext.sty create mode 100644 build/latex/sphinxlatextables.sty create mode 100644 build/latex/sphinxmanual.cls create mode 100644 build/latex/sphinxmessages.sty create mode 100644 build/latex/sphinxoptionsgeometry.sty create mode 100644 build/latex/sphinxoptionshyperref.sty create mode 100644 build/latex/sphinxpackageboxes.sty create mode 100644 build/latex/sphinxpackagecyrillic.sty create mode 100644 build/latex/sphinxpackagefootnote.sty create mode 100644 build/latex/sphinxpackagesubstitutefont.sty create mode 100644 python/secure_messaging/router.py create mode 100644 source/conf.py create mode 100644 source/index.rst diff --git a/MODULE.md b/MODULE.md new file mode 100644 index 0000000..67585c8 --- /dev/null +++ b/MODULE.md @@ -0,0 +1,40 @@ +# MODULE — secure-messaging + +Git: https://git.georgelambert.org/marchon/secure-messaging + + +This is **not** a HIPAA/SOC 2/ISO certificate. +Vocabulary: see `https://git.georgelambert.org/marchon/system-git-sync` `docs/thesaurus.md`. +Catalog: `https://git.georgelambert.org/marchon/nats-service-endpoints`. + + +## What this module is + +Runtime or documentation unit in the Peergos-for-compliance / secure-messaging +set. See this repo `README.md` for the short intro. + +## Who calls this module and why + +sm-leaf (Go) and pfc-py-admin (Python sign/history). + +**Callers:** Console send, tests, systemd `pfc-sm-leaf`. + +## Messages — from / to + +- **From:** `verae.sm.send` envelopes (`to`, `from_lookup_id`, `alg`, `ct`). +- **To:** Mailbox dest (clear); ack `lookup_id`. Failures → `verae.sm.error`, `verae.sm.dead`, `verae.sm.log.summary`. + +## Filters / security + +Missing `to`, empty `ct` (unless plain-lab), plaintext `body`, bad alg, summary `ct` field. + +## Errors and timeouts + +- **Errors:** Network Error Bundle: `ct_sender` (sender only) + `ct_system` (ops). Never log mail body. +- **Timeouts:** NATS 5s; NPE seal 15s. + +## Where data is stored and how others use it + +Signed wrapper path; admin-history JSONL cube. + +Walkthroughs and screenshots: `https://git.georgelambert.org/marchon/peergos-compliance-docs` (`source/walkthrough.rst`). diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a144086 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.PHONY: html pdf test +html: + sphinx-build -b html source build/html +pdf: + sphinx-build -b latex source build/latex + $(MAKE) -C build/latex || pdflatex -output-directory build/latex build/latex/secure-messaging.tex +test: + PYTHONPATH=python python3 -m unittest discover -s tests -v + cd go && go test ./... diff --git a/build/html/.buildinfo b/build/html/.buildinfo new file mode 100644 index 0000000..331e078 --- /dev/null +++ b/build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file records the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 99feb519dacc1b2aed6961d763dc4e5a +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/build/html/.doctrees/environment.pickle b/build/html/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..8929a97b769bcf49a55944cae465c4293aebfcc7 GIT binary patch literal 14288 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 X-K!K7%)7M8E*9E{P6ZM)uaEr?)o03$ literal 0 HcmV?d00001 diff --git a/build/html/.doctrees/index.doctree b/build/html/.doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9cb143083ddcad61a9ff179f221ee29e8a75a911 GIT binary patch literal 12622 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 U{Z9h3xYzO1!h7t@qPVy6UnnP1NdN!< literal 0 HcmV?d00001 diff --git a/build/html/_sources/index.rst.txt b/build/html/_sources/index.rst.txt new file mode 100644 index 0000000..9350471 --- /dev/null +++ b/build/html/_sources/index.rst.txt @@ -0,0 +1,40 @@ +Secure messaging +================ + +Passthrough NATS envelopes, Ed25519 signed configuration, DataCube +admin-history, and Network Error Bundles. + +This is **not** a HIPAA/SOC 2/ISO certificate. + +* Python spec: ``python/secure_messaging/`` +* Go leaf: ``go/cmd/sm-leaf`` (in-process NATS + optional hub) +* Loopback health: ``127.0.0.1:18783/health`` +* Catalog: https://git.georgelambert.org/marchon/nats-service-endpoints +* Hub: https://git.georgelambert.org/marchon/system-git-sync + +Who calls this module +--------------------- + +``pfc-py-admin`` (sign config, append history) and systemd ``pfc-sm-leaf``. +Tests send targeted good and bad messages on ``verae.sm.send``. + +Messages +-------- + +* **From:** console / tests / connectors +* **To:** mailbox dest in the clear; body ciphertext +* **Success:** ack ``accepted`` + ``lookup_id`` (sender cannot reopen ``ct``) +* **Failure:** ``SM-MISSING-TO``, ``SM-EMPTY-CT``, ``SM-BAD-ALG``, + ``SM-PLAINTEXT-BODY``, ``SM-BAD-JSON`` → ``verae.sm.error`` + + ``verae.sm.dead`` + ``verae.sm.log.summary`` +* **Filter:** no plaintext ``body`` field; summary must not contain ``ct`` +* **Timeout:** 5s NATS; 15s NPE sidecar + +Errors +------ + +Network Error Bundle: ``ct_sender`` (sender-only status) and ``ct_system`` +(ops bounce, no mail body). ``logging.mode=summary``. + +Variables: ``crypto.mode``, ``routing.mode=passthrough``, ``SM_LEAF_HUB``, +``SM_HTTP``. See system-git-sync ``docs/VARIABLES.md``. diff --git a/build/html/_static/alabaster.css b/build/html/_static/alabaster.css new file mode 100644 index 0000000..7e75bf8 --- /dev/null +++ b/build/html/_static/alabaster.css @@ -0,0 +1,663 @@ +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar { + max-height: 100%; + overflow-y: auto; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox { + margin: 1em 0; +} + +div.sphinxsidebar .search > div { + display: table-cell; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: unset; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + +@media screen and (max-width: 940px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.sphinxsidebar { + display: block; + float: none; + width: unset; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + min-width: auto; /* fixes width on small screens, breaks .hll */ + padding: 0; + } + + .hll { + /* "fixes" the breakage */ + width: max-content; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Hide ugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} + +img.github { + position: absolute; + top: 0; + border: 0; + right: 0; +} \ No newline at end of file diff --git a/build/html/_static/base-stemmer.js b/build/html/_static/base-stemmer.js new file mode 100644 index 0000000..e6fa0c4 --- /dev/null +++ b/build/html/_static/base-stemmer.js @@ -0,0 +1,476 @@ +// @ts-check + +/**@constructor*/ +BaseStemmer = function() { + /** @protected */ + this.current = ''; + this.cursor = 0; + this.limit = 0; + this.limit_backward = 0; + this.bra = 0; + this.ket = 0; + + /** + * @param {string} value + */ + this.setCurrent = function(value) { + this.current = value; + this.cursor = 0; + this.limit = this.current.length; + this.limit_backward = 0; + this.bra = this.cursor; + this.ket = this.limit; + }; + + /** + * @return {string} + */ + this.getCurrent = function() { + return this.current; + }; + + /** + * @param {BaseStemmer} other + */ + this.copy_from = function(other) { + /** @protected */ + this.current = other.current; + this.cursor = other.cursor; + this.limit = other.limit; + this.limit_backward = other.limit_backward; + this.bra = other.bra; + this.ket = other.ket; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.in_grouping = function(s, min, max) { + /** @protected */ + if (this.cursor >= this.limit) return false; + var ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) return false; + ch -= min; + if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false; + this.cursor++; + return true; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.go_in_grouping = function(s, min, max) { + /** @protected */ + while (this.cursor < this.limit) { + var ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) + return true; + ch -= min; + if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) + return true; + this.cursor++; + } + return false; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.in_grouping_b = function(s, min, max) { + /** @protected */ + if (this.cursor <= this.limit_backward) return false; + var ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) return false; + ch -= min; + if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false; + this.cursor--; + return true; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.go_in_grouping_b = function(s, min, max) { + /** @protected */ + while (this.cursor > this.limit_backward) { + var ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) return true; + ch -= min; + if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return true; + this.cursor--; + } + return false; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.out_grouping = function(s, min, max) { + /** @protected */ + if (this.cursor >= this.limit) return false; + var ch = this.current.charCodeAt(this.cursor); + if (ch > max || ch < min) { + this.cursor++; + return true; + } + ch -= min; + if ((s[ch >>> 3] & (0X1 << (ch & 0x7))) == 0) { + this.cursor++; + return true; + } + return false; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.go_out_grouping = function(s, min, max) { + /** @protected */ + while (this.cursor < this.limit) { + var ch = this.current.charCodeAt(this.cursor); + if (ch <= max && ch >= min) { + ch -= min; + if ((s[ch >>> 3] & (0X1 << (ch & 0x7))) != 0) { + return true; + } + } + this.cursor++; + } + return false; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.out_grouping_b = function(s, min, max) { + /** @protected */ + if (this.cursor <= this.limit_backward) return false; + var ch = this.current.charCodeAt(this.cursor - 1); + if (ch > max || ch < min) { + this.cursor--; + return true; + } + ch -= min; + if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) { + this.cursor--; + return true; + } + return false; + }; + + /** + * @param {number[]} s + * @param {number} min + * @param {number} max + * @return {boolean} + */ + this.go_out_grouping_b = function(s, min, max) { + /** @protected */ + while (this.cursor > this.limit_backward) { + var ch = this.current.charCodeAt(this.cursor - 1); + if (ch <= max && ch >= min) { + ch -= min; + if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) != 0) { + return true; + } + } + this.cursor--; + } + return false; + }; + + /** + * @param {string} s + * @return {boolean} + */ + this.eq_s = function(s) + { + /** @protected */ + if (this.limit - this.cursor < s.length) return false; + if (this.current.slice(this.cursor, this.cursor + s.length) != s) + { + return false; + } + this.cursor += s.length; + return true; + }; + + /** + * @param {string} s + * @return {boolean} + */ + this.eq_s_b = function(s) + { + /** @protected */ + if (this.cursor - this.limit_backward < s.length) return false; + if (this.current.slice(this.cursor - s.length, this.cursor) != s) + { + return false; + } + this.cursor -= s.length; + return true; + }; + + /** + * @param {Among[]} v + * @return {number} + */ + this.find_among = function(v) + { + /** @protected */ + var i = 0; + var j = v.length; + + var c = this.cursor; + var l = this.limit; + + var common_i = 0; + var common_j = 0; + + var first_key_inspected = false; + + while (true) + { + var k = i + ((j - i) >>> 1); + var diff = 0; + var common = common_i < common_j ? common_i : common_j; // smaller + // w[0]: string, w[1]: substring_i, w[2]: result, w[3]: function (optional) + var w = v[k]; + var i2; + for (i2 = common; i2 < w[0].length; i2++) + { + if (c + common == l) + { + diff = -1; + break; + } + diff = this.current.charCodeAt(c + common) - w[0].charCodeAt(i2); + if (diff != 0) break; + common++; + } + if (diff < 0) + { + j = k; + common_j = common; + } + else + { + i = k; + common_i = common; + } + if (j - i <= 1) + { + if (i > 0) break; // v->s has been inspected + if (j == i) break; // only one item in v + + // - but now we need to go round once more to get + // v->s inspected. This looks messy, but is actually + // the optimal approach. + + if (first_key_inspected) break; + first_key_inspected = true; + } + } + do { + var w = v[i]; + if (common_i >= w[0].length) + { + this.cursor = c + w[0].length; + if (w.length < 4) return w[2]; + var res = w[3](this); + this.cursor = c + w[0].length; + if (res) return w[2]; + } + i = w[1]; + } while (i >= 0); + return 0; + }; + + // find_among_b is for backwards processing. Same comments apply + /** + * @param {Among[]} v + * @return {number} + */ + this.find_among_b = function(v) + { + /** @protected */ + var i = 0; + var j = v.length + + var c = this.cursor; + var lb = this.limit_backward; + + var common_i = 0; + var common_j = 0; + + var first_key_inspected = false; + + while (true) + { + var k = i + ((j - i) >> 1); + var diff = 0; + var common = common_i < common_j ? common_i : common_j; + var w = v[k]; + var i2; + for (i2 = w[0].length - 1 - common; i2 >= 0; i2--) + { + if (c - common == lb) + { + diff = -1; + break; + } + diff = this.current.charCodeAt(c - 1 - common) - w[0].charCodeAt(i2); + if (diff != 0) break; + common++; + } + if (diff < 0) + { + j = k; + common_j = common; + } + else + { + i = k; + common_i = common; + } + if (j - i <= 1) + { + if (i > 0) break; + if (j == i) break; + if (first_key_inspected) break; + first_key_inspected = true; + } + } + do { + var w = v[i]; + if (common_i >= w[0].length) + { + this.cursor = c - w[0].length; + if (w.length < 4) return w[2]; + var res = w[3](this); + this.cursor = c - w[0].length; + if (res) return w[2]; + } + i = w[1]; + } while (i >= 0); + return 0; + }; + + /* to replace chars between c_bra and c_ket in this.current by the + * chars in s. + */ + /** + * @param {number} c_bra + * @param {number} c_ket + * @param {string} s + * @return {number} + */ + this.replace_s = function(c_bra, c_ket, s) + { + /** @protected */ + var adjustment = s.length - (c_ket - c_bra); + this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket); + this.limit += adjustment; + if (this.cursor >= c_ket) this.cursor += adjustment; + else if (this.cursor > c_bra) this.cursor = c_bra; + return adjustment; + }; + + /** + * @return {boolean} + */ + this.slice_check = function() + { + /** @protected */ + if (this.bra < 0 || + this.bra > this.ket || + this.ket > this.limit || + this.limit > this.current.length) + { + return false; + } + return true; + }; + + /** + * @param {number} c_bra + * @return {boolean} + */ + this.slice_from = function(s) + { + /** @protected */ + var result = false; + if (this.slice_check()) + { + this.replace_s(this.bra, this.ket, s); + result = true; + } + return result; + }; + + /** + * @return {boolean} + */ + this.slice_del = function() + { + /** @protected */ + return this.slice_from(""); + }; + + /** + * @param {number} c_bra + * @param {number} c_ket + * @param {string} s + */ + this.insert = function(c_bra, c_ket, s) + { + /** @protected */ + var adjustment = this.replace_s(c_bra, c_ket, s); + if (c_bra <= this.bra) this.bra += adjustment; + if (c_bra <= this.ket) this.ket += adjustment; + }; + + /** + * @return {string} + */ + this.slice_to = function() + { + /** @protected */ + var result = ''; + if (this.slice_check()) + { + result = this.current.slice(this.bra, this.ket); + } + return result; + }; + + /** + * @return {string} + */ + this.assign_to = function() + { + /** @protected */ + return this.current.slice(0, this.limit); + }; +}; diff --git a/build/html/_static/basic.css b/build/html/_static/basic.css new file mode 100644 index 0000000..0028826 --- /dev/null +++ b/build/html/_static/basic.css @@ -0,0 +1,906 @@ +/* + * Sphinx stylesheet -- basic theme. + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin-top: 10px; +} + +ul.search li { + padding: 5px 0; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: inherit; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/build/html/_static/custom.css b/build/html/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/build/html/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/build/html/_static/doctools.js b/build/html/_static/doctools.js new file mode 100644 index 0000000..807cdb1 --- /dev/null +++ b/build/html/_static/doctools.js @@ -0,0 +1,150 @@ +/* + * Base JavaScript utilities for all Sphinx HTML documentation. + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})`, + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)), + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS + && !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) + return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/build/html/_static/documentation_options.js b/build/html/_static/documentation_options.js new file mode 100644 index 0000000..7e4c114 --- /dev/null +++ b/build/html/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/build/html/_static/english-stemmer.js b/build/html/_static/english-stemmer.js new file mode 100644 index 0000000..056760e --- /dev/null +++ b/build/html/_static/english-stemmer.js @@ -0,0 +1,1066 @@ +// Generated from english.sbl by Snowball 3.0.1 - https://snowballstem.org/ + +/**@constructor*/ +var EnglishStemmer = function() { + var base = new BaseStemmer(); + + /** @const */ var a_0 = [ + ["arsen", -1, -1], + ["commun", -1, -1], + ["emerg", -1, -1], + ["gener", -1, -1], + ["later", -1, -1], + ["organ", -1, -1], + ["past", -1, -1], + ["univers", -1, -1] + ]; + + /** @const */ var a_1 = [ + ["'", -1, 1], + ["'s'", 0, 1], + ["'s", -1, 1] + ]; + + /** @const */ var a_2 = [ + ["ied", -1, 2], + ["s", -1, 3], + ["ies", 1, 2], + ["sses", 1, 1], + ["ss", 1, -1], + ["us", 1, -1] + ]; + + /** @const */ var a_3 = [ + ["succ", -1, 1], + ["proc", -1, 1], + ["exc", -1, 1] + ]; + + /** @const */ var a_4 = [ + ["even", -1, 2], + ["cann", -1, 2], + ["inn", -1, 2], + ["earr", -1, 2], + ["herr", -1, 2], + ["out", -1, 2], + ["y", -1, 1] + ]; + + /** @const */ var a_5 = [ + ["", -1, -1], + ["ed", 0, 2], + ["eed", 1, 1], + ["ing", 0, 3], + ["edly", 0, 2], + ["eedly", 4, 1], + ["ingly", 0, 2] + ]; + + /** @const */ var a_6 = [ + ["", -1, 3], + ["bb", 0, 2], + ["dd", 0, 2], + ["ff", 0, 2], + ["gg", 0, 2], + ["bl", 0, 1], + ["mm", 0, 2], + ["nn", 0, 2], + ["pp", 0, 2], + ["rr", 0, 2], + ["at", 0, 1], + ["tt", 0, 2], + ["iz", 0, 1] + ]; + + /** @const */ var a_7 = [ + ["anci", -1, 3], + ["enci", -1, 2], + ["ogi", -1, 14], + ["li", -1, 16], + ["bli", 3, 12], + ["abli", 4, 4], + ["alli", 3, 8], + ["fulli", 3, 9], + ["lessli", 3, 15], + ["ousli", 3, 10], + ["entli", 3, 5], + ["aliti", -1, 8], + ["biliti", -1, 12], + ["iviti", -1, 11], + ["tional", -1, 1], + ["ational", 14, 7], + ["alism", -1, 8], + ["ation", -1, 7], + ["ization", 17, 6], + ["izer", -1, 6], + ["ator", -1, 7], + ["iveness", -1, 11], + ["fulness", -1, 9], + ["ousness", -1, 10], + ["ogist", -1, 13] + ]; + + /** @const */ var a_8 = [ + ["icate", -1, 4], + ["ative", -1, 6], + ["alize", -1, 3], + ["iciti", -1, 4], + ["ical", -1, 4], + ["tional", -1, 1], + ["ational", 5, 2], + ["ful", -1, 5], + ["ness", -1, 5] + ]; + + /** @const */ var a_9 = [ + ["ic", -1, 1], + ["ance", -1, 1], + ["ence", -1, 1], + ["able", -1, 1], + ["ible", -1, 1], + ["ate", -1, 1], + ["ive", -1, 1], + ["ize", -1, 1], + ["iti", -1, 1], + ["al", -1, 1], + ["ism", -1, 1], + ["ion", -1, 2], + ["er", -1, 1], + ["ous", -1, 1], + ["ant", -1, 1], + ["ent", -1, 1], + ["ment", 15, 1], + ["ement", 16, 1] + ]; + + /** @const */ var a_10 = [ + ["e", -1, 1], + ["l", -1, 2] + ]; + + /** @const */ var a_11 = [ + ["andes", -1, -1], + ["atlas", -1, -1], + ["bias", -1, -1], + ["cosmos", -1, -1], + ["early", -1, 5], + ["gently", -1, 3], + ["howe", -1, -1], + ["idly", -1, 2], + ["news", -1, -1], + ["only", -1, 6], + ["singly", -1, 7], + ["skies", -1, 1], + ["sky", -1, -1], + ["ugly", -1, 4] + ]; + + /** @const */ var /** Array */ g_aeo = [17, 64]; + + /** @const */ var /** Array */ g_v = [17, 65, 16, 1]; + + /** @const */ var /** Array */ g_v_WXY = [1, 17, 65, 208, 1]; + + /** @const */ var /** Array */ g_valid_LI = [55, 141, 2]; + + var /** boolean */ B_Y_found = false; + var /** number */ I_p2 = 0; + var /** number */ I_p1 = 0; + + + /** @return {boolean} */ + function r_prelude() { + B_Y_found = false; + /** @const */ var /** number */ v_1 = base.cursor; + lab0: { + base.bra = base.cursor; + if (!(base.eq_s("'"))) + { + break lab0; + } + base.ket = base.cursor; + if (!base.slice_del()) + { + return false; + } + } + base.cursor = v_1; + /** @const */ var /** number */ v_2 = base.cursor; + lab1: { + base.bra = base.cursor; + if (!(base.eq_s("y"))) + { + break lab1; + } + base.ket = base.cursor; + if (!base.slice_from("Y")) + { + return false; + } + B_Y_found = true; + } + base.cursor = v_2; + /** @const */ var /** number */ v_3 = base.cursor; + lab2: { + while(true) + { + /** @const */ var /** number */ v_4 = base.cursor; + lab3: { + golab4: while(true) + { + /** @const */ var /** number */ v_5 = base.cursor; + lab5: { + if (!(base.in_grouping(g_v, 97, 121))) + { + break lab5; + } + base.bra = base.cursor; + if (!(base.eq_s("y"))) + { + break lab5; + } + base.ket = base.cursor; + base.cursor = v_5; + break golab4; + } + base.cursor = v_5; + if (base.cursor >= base.limit) + { + break lab3; + } + base.cursor++; + } + if (!base.slice_from("Y")) + { + return false; + } + B_Y_found = true; + continue; + } + base.cursor = v_4; + break; + } + } + base.cursor = v_3; + return true; + }; + + /** @return {boolean} */ + function r_mark_regions() { + I_p1 = base.limit; + I_p2 = base.limit; + /** @const */ var /** number */ v_1 = base.cursor; + lab0: { + lab1: { + /** @const */ var /** number */ v_2 = base.cursor; + lab2: { + if (base.find_among(a_0) == 0) + { + break lab2; + } + break lab1; + } + base.cursor = v_2; + if (!base.go_out_grouping(g_v, 97, 121)) + { + break lab0; + } + base.cursor++; + if (!base.go_in_grouping(g_v, 97, 121)) + { + break lab0; + } + base.cursor++; + } + I_p1 = base.cursor; + if (!base.go_out_grouping(g_v, 97, 121)) + { + break lab0; + } + base.cursor++; + if (!base.go_in_grouping(g_v, 97, 121)) + { + break lab0; + } + base.cursor++; + I_p2 = base.cursor; + } + base.cursor = v_1; + return true; + }; + + /** @return {boolean} */ + function r_shortv() { + lab0: { + /** @const */ var /** number */ v_1 = base.limit - base.cursor; + lab1: { + if (!(base.out_grouping_b(g_v_WXY, 89, 121))) + { + break lab1; + } + if (!(base.in_grouping_b(g_v, 97, 121))) + { + break lab1; + } + if (!(base.out_grouping_b(g_v, 97, 121))) + { + break lab1; + } + break lab0; + } + base.cursor = base.limit - v_1; + lab2: { + if (!(base.out_grouping_b(g_v, 97, 121))) + { + break lab2; + } + if (!(base.in_grouping_b(g_v, 97, 121))) + { + break lab2; + } + if (base.cursor > base.limit_backward) + { + break lab2; + } + break lab0; + } + base.cursor = base.limit - v_1; + if (!(base.eq_s_b("past"))) + { + return false; + } + } + return true; + }; + + /** @return {boolean} */ + function r_R1() { + return I_p1 <= base.cursor; + }; + + /** @return {boolean} */ + function r_R2() { + return I_p2 <= base.cursor; + }; + + /** @return {boolean} */ + function r_Step_1a() { + var /** number */ among_var; + /** @const */ var /** number */ v_1 = base.limit - base.cursor; + lab0: { + base.ket = base.cursor; + if (base.find_among_b(a_1) == 0) + { + base.cursor = base.limit - v_1; + break lab0; + } + base.bra = base.cursor; + if (!base.slice_del()) + { + return false; + } + } + base.ket = base.cursor; + among_var = base.find_among_b(a_2); + if (among_var == 0) + { + return false; + } + base.bra = base.cursor; + switch (among_var) { + case 1: + if (!base.slice_from("ss")) + { + return false; + } + break; + case 2: + lab1: { + /** @const */ var /** number */ v_2 = base.limit - base.cursor; + lab2: { + { + /** @const */ var /** number */ c1 = base.cursor - 2; + if (c1 < base.limit_backward) + { + break lab2; + } + base.cursor = c1; + } + if (!base.slice_from("i")) + { + return false; + } + break lab1; + } + base.cursor = base.limit - v_2; + if (!base.slice_from("ie")) + { + return false; + } + } + break; + case 3: + if (base.cursor <= base.limit_backward) + { + return false; + } + base.cursor--; + if (!base.go_out_grouping_b(g_v, 97, 121)) + { + return false; + } + base.cursor--; + if (!base.slice_del()) + { + return false; + } + break; + } + return true; + }; + + /** @return {boolean} */ + function r_Step_1b() { + var /** number */ among_var; + base.ket = base.cursor; + among_var = base.find_among_b(a_5); + base.bra = base.cursor; + lab0: { + /** @const */ var /** number */ v_1 = base.limit - base.cursor; + lab1: { + switch (among_var) { + case 1: + /** @const */ var /** number */ v_2 = base.limit - base.cursor; + lab2: { + lab3: { + /** @const */ var /** number */ v_3 = base.limit - base.cursor; + lab4: { + if (base.find_among_b(a_3) == 0) + { + break lab4; + } + if (base.cursor > base.limit_backward) + { + break lab4; + } + break lab3; + } + base.cursor = base.limit - v_3; + if (!r_R1()) + { + break lab2; + } + if (!base.slice_from("ee")) + { + return false; + } + } + } + base.cursor = base.limit - v_2; + break; + case 2: + break lab1; + case 3: + among_var = base.find_among_b(a_4); + if (among_var == 0) + { + break lab1; + } + switch (among_var) { + case 1: + /** @const */ var /** number */ v_4 = base.limit - base.cursor; + if (!(base.out_grouping_b(g_v, 97, 121))) + { + break lab1; + } + if (base.cursor > base.limit_backward) + { + break lab1; + } + base.cursor = base.limit - v_4; + base.bra = base.cursor; + if (!base.slice_from("ie")) + { + return false; + } + break; + case 2: + if (base.cursor > base.limit_backward) + { + break lab1; + } + break; + } + break; + } + break lab0; + } + base.cursor = base.limit - v_1; + /** @const */ var /** number */ v_5 = base.limit - base.cursor; + if (!base.go_out_grouping_b(g_v, 97, 121)) + { + return false; + } + base.cursor--; + base.cursor = base.limit - v_5; + if (!base.slice_del()) + { + return false; + } + base.ket = base.cursor; + base.bra = base.cursor; + /** @const */ var /** number */ v_6 = base.limit - base.cursor; + among_var = base.find_among_b(a_6); + switch (among_var) { + case 1: + if (!base.slice_from("e")) + { + return false; + } + return false; + case 2: + { + /** @const */ var /** number */ v_7 = base.limit - base.cursor; + lab5: { + if (!(base.in_grouping_b(g_aeo, 97, 111))) + { + break lab5; + } + if (base.cursor > base.limit_backward) + { + break lab5; + } + return false; + } + base.cursor = base.limit - v_7; + } + break; + case 3: + if (base.cursor != I_p1) + { + return false; + } + /** @const */ var /** number */ v_8 = base.limit - base.cursor; + if (!r_shortv()) + { + return false; + } + base.cursor = base.limit - v_8; + if (!base.slice_from("e")) + { + return false; + } + return false; + } + base.cursor = base.limit - v_6; + base.ket = base.cursor; + if (base.cursor <= base.limit_backward) + { + return false; + } + base.cursor--; + base.bra = base.cursor; + if (!base.slice_del()) + { + return false; + } + } + return true; + }; + + /** @return {boolean} */ + function r_Step_1c() { + base.ket = base.cursor; + lab0: { + /** @const */ var /** number */ v_1 = base.limit - base.cursor; + lab1: { + if (!(base.eq_s_b("y"))) + { + break lab1; + } + break lab0; + } + base.cursor = base.limit - v_1; + if (!(base.eq_s_b("Y"))) + { + return false; + } + } + base.bra = base.cursor; + if (!(base.out_grouping_b(g_v, 97, 121))) + { + return false; + } + lab2: { + if (base.cursor > base.limit_backward) + { + break lab2; + } + return false; + } + if (!base.slice_from("i")) + { + return false; + } + return true; + }; + + /** @return {boolean} */ + function r_Step_2() { + var /** number */ among_var; + base.ket = base.cursor; + among_var = base.find_among_b(a_7); + if (among_var == 0) + { + return false; + } + base.bra = base.cursor; + if (!r_R1()) + { + return false; + } + switch (among_var) { + case 1: + if (!base.slice_from("tion")) + { + return false; + } + break; + case 2: + if (!base.slice_from("ence")) + { + return false; + } + break; + case 3: + if (!base.slice_from("ance")) + { + return false; + } + break; + case 4: + if (!base.slice_from("able")) + { + return false; + } + break; + case 5: + if (!base.slice_from("ent")) + { + return false; + } + break; + case 6: + if (!base.slice_from("ize")) + { + return false; + } + break; + case 7: + if (!base.slice_from("ate")) + { + return false; + } + break; + case 8: + if (!base.slice_from("al")) + { + return false; + } + break; + case 9: + if (!base.slice_from("ful")) + { + return false; + } + break; + case 10: + if (!base.slice_from("ous")) + { + return false; + } + break; + case 11: + if (!base.slice_from("ive")) + { + return false; + } + break; + case 12: + if (!base.slice_from("ble")) + { + return false; + } + break; + case 13: + if (!base.slice_from("og")) + { + return false; + } + break; + case 14: + if (!(base.eq_s_b("l"))) + { + return false; + } + if (!base.slice_from("og")) + { + return false; + } + break; + case 15: + if (!base.slice_from("less")) + { + return false; + } + break; + case 16: + if (!(base.in_grouping_b(g_valid_LI, 99, 116))) + { + return false; + } + if (!base.slice_del()) + { + return false; + } + break; + } + return true; + }; + + /** @return {boolean} */ + function r_Step_3() { + var /** number */ among_var; + base.ket = base.cursor; + among_var = base.find_among_b(a_8); + if (among_var == 0) + { + return false; + } + base.bra = base.cursor; + if (!r_R1()) + { + return false; + } + switch (among_var) { + case 1: + if (!base.slice_from("tion")) + { + return false; + } + break; + case 2: + if (!base.slice_from("ate")) + { + return false; + } + break; + case 3: + if (!base.slice_from("al")) + { + return false; + } + break; + case 4: + if (!base.slice_from("ic")) + { + return false; + } + break; + case 5: + if (!base.slice_del()) + { + return false; + } + break; + case 6: + if (!r_R2()) + { + return false; + } + if (!base.slice_del()) + { + return false; + } + break; + } + return true; + }; + + /** @return {boolean} */ + function r_Step_4() { + var /** number */ among_var; + base.ket = base.cursor; + among_var = base.find_among_b(a_9); + if (among_var == 0) + { + return false; + } + base.bra = base.cursor; + if (!r_R2()) + { + return false; + } + switch (among_var) { + case 1: + if (!base.slice_del()) + { + return false; + } + break; + case 2: + lab0: { + /** @const */ var /** number */ v_1 = base.limit - base.cursor; + lab1: { + if (!(base.eq_s_b("s"))) + { + break lab1; + } + break lab0; + } + base.cursor = base.limit - v_1; + if (!(base.eq_s_b("t"))) + { + return false; + } + } + if (!base.slice_del()) + { + return false; + } + break; + } + return true; + }; + + /** @return {boolean} */ + function r_Step_5() { + var /** number */ among_var; + base.ket = base.cursor; + among_var = base.find_among_b(a_10); + if (among_var == 0) + { + return false; + } + base.bra = base.cursor; + switch (among_var) { + case 1: + lab0: { + lab1: { + if (!r_R2()) + { + break lab1; + } + break lab0; + } + if (!r_R1()) + { + return false; + } + { + /** @const */ var /** number */ v_1 = base.limit - base.cursor; + lab2: { + if (!r_shortv()) + { + break lab2; + } + return false; + } + base.cursor = base.limit - v_1; + } + } + if (!base.slice_del()) + { + return false; + } + break; + case 2: + if (!r_R2()) + { + return false; + } + if (!(base.eq_s_b("l"))) + { + return false; + } + if (!base.slice_del()) + { + return false; + } + break; + } + return true; + }; + + /** @return {boolean} */ + function r_exception1() { + var /** number */ among_var; + base.bra = base.cursor; + among_var = base.find_among(a_11); + if (among_var == 0) + { + return false; + } + base.ket = base.cursor; + if (base.cursor < base.limit) + { + return false; + } + switch (among_var) { + case 1: + if (!base.slice_from("sky")) + { + return false; + } + break; + case 2: + if (!base.slice_from("idl")) + { + return false; + } + break; + case 3: + if (!base.slice_from("gentl")) + { + return false; + } + break; + case 4: + if (!base.slice_from("ugli")) + { + return false; + } + break; + case 5: + if (!base.slice_from("earli")) + { + return false; + } + break; + case 6: + if (!base.slice_from("onli")) + { + return false; + } + break; + case 7: + if (!base.slice_from("singl")) + { + return false; + } + break; + } + return true; + }; + + /** @return {boolean} */ + function r_postlude() { + if (!B_Y_found) + { + return false; + } + while(true) + { + /** @const */ var /** number */ v_1 = base.cursor; + lab0: { + golab1: while(true) + { + /** @const */ var /** number */ v_2 = base.cursor; + lab2: { + base.bra = base.cursor; + if (!(base.eq_s("Y"))) + { + break lab2; + } + base.ket = base.cursor; + base.cursor = v_2; + break golab1; + } + base.cursor = v_2; + if (base.cursor >= base.limit) + { + break lab0; + } + base.cursor++; + } + if (!base.slice_from("y")) + { + return false; + } + continue; + } + base.cursor = v_1; + break; + } + return true; + }; + + this.stem = /** @return {boolean} */ function() { + lab0: { + /** @const */ var /** number */ v_1 = base.cursor; + lab1: { + if (!r_exception1()) + { + break lab1; + } + break lab0; + } + base.cursor = v_1; + lab2: { + { + /** @const */ var /** number */ v_2 = base.cursor; + lab3: { + { + /** @const */ var /** number */ c1 = base.cursor + 3; + if (c1 > base.limit) + { + break lab3; + } + base.cursor = c1; + } + break lab2; + } + base.cursor = v_2; + } + break lab0; + } + base.cursor = v_1; + r_prelude(); + r_mark_regions(); + base.limit_backward = base.cursor; base.cursor = base.limit; + /** @const */ var /** number */ v_3 = base.limit - base.cursor; + r_Step_1a(); + base.cursor = base.limit - v_3; + /** @const */ var /** number */ v_4 = base.limit - base.cursor; + r_Step_1b(); + base.cursor = base.limit - v_4; + /** @const */ var /** number */ v_5 = base.limit - base.cursor; + r_Step_1c(); + base.cursor = base.limit - v_5; + /** @const */ var /** number */ v_6 = base.limit - base.cursor; + r_Step_2(); + base.cursor = base.limit - v_6; + /** @const */ var /** number */ v_7 = base.limit - base.cursor; + r_Step_3(); + base.cursor = base.limit - v_7; + /** @const */ var /** number */ v_8 = base.limit - base.cursor; + r_Step_4(); + base.cursor = base.limit - v_8; + /** @const */ var /** number */ v_9 = base.limit - base.cursor; + r_Step_5(); + base.cursor = base.limit - v_9; + base.cursor = base.limit_backward; + /** @const */ var /** number */ v_10 = base.cursor; + r_postlude(); + base.cursor = v_10; + } + return true; + }; + + /**@return{string}*/ + this['stemWord'] = function(/**string*/word) { + base.setCurrent(word); + this.stem(); + return base.getCurrent(); + }; +}; diff --git a/build/html/_static/file.png b/build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/build/html/_static/github-banner.svg b/build/html/_static/github-banner.svg new file mode 100644 index 0000000..c47d9dc --- /dev/null +++ b/build/html/_static/github-banner.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/build/html/_static/language_data.js b/build/html/_static/language_data.js new file mode 100644 index 0000000..5776786 --- /dev/null +++ b/build/html/_static/language_data.js @@ -0,0 +1,13 @@ +/* + * This script contains the language-specific data used by searchtools.js, + * namely the set of stopwords, stemmer, scorer and splitter. + */ + +const stopwords = new Set(["a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", "aren't", "as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", "by", "can't", "cannot", "could", "couldn't", "did", "didn't", "do", "does", "doesn't", "doing", "don't", "down", "during", "each", "few", "for", "from", "further", "had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "he's", "her", "here", "here's", "hers", "herself", "him", "himself", "his", "how", "how's", "i", "i'd", "i'll", "i'm", "i've", "if", "in", "into", "is", "isn't", "it", "it's", "its", "itself", "let's", "me", "more", "most", "mustn't", "my", "myself", "no", "nor", "not", "of", "off", "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over", "own", "same", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "so", "some", "such", "than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "to", "too", "under", "until", "up", "very", "was", "wasn't", "we", "we'd", "we'll", "we're", "we've", "were", "weren't", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "who's", "whom", "why", "why's", "with", "won't", "would", "wouldn't", "you", "you'd", "you'll", "you're", "you've", "your", "yours", "yourself", "yourselves"]); +window.stopwords = stopwords; // Export to global scope + + +/* Non-minified versions are copied as separate JavaScript files, if available */ +BaseStemmer=function(){this.current="",this.cursor=0,this.limit=0,this.limit_backward=0,this.bra=0,this.ket=0,this.setCurrent=function(t){this.current=t,this.cursor=0,this.limit=this.current.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},this.getCurrent=function(){return this.current},this.copy_from=function(t){this.current=t.current,this.cursor=t.cursor,this.limit=t.limit,this.limit_backward=t.limit_backward,this.bra=t.bra,this.ket=t.ket},this.in_grouping=function(t,r,i){return!(this.cursor>=this.limit||i<(i=this.current.charCodeAt(this.cursor))||i>>3]&1<<(7&i))||(this.cursor++,0))},this.go_in_grouping=function(t,r,i){for(;this.cursor>>3]&1<<(7&s)))return!0;this.cursor++}return!1},this.in_grouping_b=function(t,r,i){return!(this.cursor<=this.limit_backward||i<(i=this.current.charCodeAt(this.cursor-1))||i>>3]&1<<(7&i))||(this.cursor--,0))},this.go_in_grouping_b=function(t,r,i){for(;this.cursor>this.limit_backward;){var s=this.current.charCodeAt(this.cursor-1);if(i>>3]&1<<(7&s)))return!0;this.cursor--}return!1},this.out_grouping=function(t,r,i){return!(this.cursor>=this.limit)&&(i<(i=this.current.charCodeAt(this.cursor))||i>>3]&1<<(7&i)))&&(this.cursor++,!0)},this.go_out_grouping=function(t,r,i){for(;this.cursor>>3]&1<<(7&s)))return!0;this.cursor++}return!1},this.out_grouping_b=function(t,r,i){return!(this.cursor<=this.limit_backward)&&(i<(i=this.current.charCodeAt(this.cursor-1))||i>>3]&1<<(7&i)))&&(this.cursor--,!0)},this.go_out_grouping_b=function(t,r,i){for(;this.cursor>this.limit_backward;){var s=this.current.charCodeAt(this.cursor-1);if(s<=i&&r<=s&&0!=(t[(s-=r)>>>3]&1<<(7&s)))return!0;this.cursor--}return!1},this.eq_s=function(t){return!(this.limit-this.cursor>>1),o=0,a=e=(l=t[r])[0].length){if(this.cursor=s+l[0].length,l.length<4)return l[2];var g=l[3](this);if(this.cursor=s+l[0].length,g)return l[2]}}while(0<=(r=l[1]));return 0},this.find_among_b=function(t){for(var r=0,i=t.length,s=this.cursor,h=this.limit_backward,e=0,n=0,c=!1;;){for(var u,o=r+(i-r>>1),a=0,l=e=(u=t[r])[0].length){if(this.cursor=s-u[0].length,u.length<4)return u[2];var g=u[3](this);if(this.cursor=s-u[0].length,g)return u[2]}}while(0<=(r=u[1]));return 0},this.replace_s=function(t,r,i){var s=i.length-(r-t);return this.current=this.current.slice(0,t)+i+this.current.slice(r),this.limit+=s,this.cursor>=r?this.cursor+=s:this.cursor>t&&(this.cursor=t),s},this.slice_check=function(){return!(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>this.current.length)},this.slice_from=function(t){var r=!1;return this.slice_check()&&(this.replace_s(this.bra,this.ket,t),r=!0),r},this.slice_del=function(){return this.slice_from("")},this.insert=function(t,r,i){r=this.replace_s(t,r,i);t<=this.bra&&(this.bra+=r),t<=this.ket&&(this.ket+=r)},this.slice_to=function(){var t="";return t=this.slice_check()?this.current.slice(this.bra,this.ket):t},this.assign_to=function(){return this.current.slice(0,this.limit)}}; +var EnglishStemmer=function(){var a=new BaseStemmer,c=[["arsen",-1,-1],["commun",-1,-1],["emerg",-1,-1],["gener",-1,-1],["later",-1,-1],["organ",-1,-1],["past",-1,-1],["univers",-1,-1]],o=[["'",-1,1],["'s'",0,1],["'s",-1,1]],u=[["ied",-1,2],["s",-1,3],["ies",1,2],["sses",1,1],["ss",1,-1],["us",1,-1]],t=[["succ",-1,1],["proc",-1,1],["exc",-1,1]],l=[["even",-1,2],["cann",-1,2],["inn",-1,2],["earr",-1,2],["herr",-1,2],["out",-1,2],["y",-1,1]],n=[["",-1,-1],["ed",0,2],["eed",1,1],["ing",0,3],["edly",0,2],["eedly",4,1],["ingly",0,2]],f=[["",-1,3],["bb",0,2],["dd",0,2],["ff",0,2],["gg",0,2],["bl",0,1],["mm",0,2],["nn",0,2],["pp",0,2],["rr",0,2],["at",0,1],["tt",0,2],["iz",0,1]],_=[["anci",-1,3],["enci",-1,2],["ogi",-1,14],["li",-1,16],["bli",3,12],["abli",4,4],["alli",3,8],["fulli",3,9],["lessli",3,15],["ousli",3,10],["entli",3,5],["aliti",-1,8],["biliti",-1,12],["iviti",-1,11],["tional",-1,1],["ational",14,7],["alism",-1,8],["ation",-1,7],["ization",17,6],["izer",-1,6],["ator",-1,7],["iveness",-1,11],["fulness",-1,9],["ousness",-1,10],["ogist",-1,13]],m=[["icate",-1,4],["ative",-1,6],["alize",-1,3],["iciti",-1,4],["ical",-1,4],["tional",-1,1],["ational",5,2],["ful",-1,5],["ness",-1,5]],b=[["ic",-1,1],["ance",-1,1],["ence",-1,1],["able",-1,1],["ible",-1,1],["ate",-1,1],["ive",-1,1],["ize",-1,1],["iti",-1,1],["al",-1,1],["ism",-1,1],["ion",-1,2],["er",-1,1],["ous",-1,1],["ant",-1,1],["ent",-1,1],["ment",15,1],["ement",16,1]],k=[["e",-1,1],["l",-1,2]],g=[["andes",-1,-1],["atlas",-1,-1],["bias",-1,-1],["cosmos",-1,-1],["early",-1,5],["gently",-1,3],["howe",-1,-1],["idly",-1,2],["news",-1,-1],["only",-1,6],["singly",-1,7],["skies",-1,1],["sky",-1,-1],["ugly",-1,4]],d=[17,64],v=[17,65,16,1],i=[1,17,65,208,1],w=[55,141,2],p=!1,y=0,h=0;function q(){var r=a.limit-a.cursor;return!!(a.out_grouping_b(i,89,121)&&a.in_grouping_b(v,97,121)&&a.out_grouping_b(v,97,121)||(a.cursor=a.limit-r,a.out_grouping_b(v,97,121)&&a.in_grouping_b(v,97,121)&&!(a.cursor>a.limit_backward))||(a.cursor=a.limit-r,a.eq_s_b("past")))}function z(){return h<=a.cursor}function Y(){return y<=a.cursor}this.stem=function(){var r=a.cursor;if(!(()=>{var r;if(a.bra=a.cursor,0!=(r=a.find_among(g))&&(a.ket=a.cursor,!(a.cursora.limit)a.cursor=i;else{a.cursor=e,a.cursor=r,(()=>{p=!1;var r=a.cursor;if(a.bra=a.cursor,!a.eq_s("'")||(a.ket=a.cursor,a.slice_del())){a.cursor=r;r=a.cursor;if(a.bra=a.cursor,a.eq_s("y")){if(a.ket=a.cursor,!a.slice_from("Y"))return;p=!0}a.cursor=r;for(r=a.cursor;;){var i=a.cursor;r:{for(;;){var e=a.cursor;if(a.in_grouping(v,97,121)&&(a.bra=a.cursor,a.eq_s("y"))){a.ket=a.cursor,a.cursor=e;break}if(a.cursor=e,a.cursor>=a.limit)break r;a.cursor++}if(!a.slice_from("Y"))return;p=!0;continue}a.cursor=i;break}a.cursor=r}})(),h=a.limit,y=a.limit;i=a.cursor;r:{var s=a.cursor;if(0==a.find_among(c)){if(a.cursor=s,!a.go_out_grouping(v,97,121))break r;if(a.cursor++,!a.go_in_grouping(v,97,121))break r;a.cursor++}h=a.cursor,a.go_out_grouping(v,97,121)&&(a.cursor++,a.go_in_grouping(v,97,121))&&(a.cursor++,y=a.cursor)}a.cursor=i,a.limit_backward=a.cursor,a.cursor=a.limit;var e=a.limit-a.cursor,r=((()=>{var r=a.limit-a.cursor;if(a.ket=a.cursor,0==a.find_among_b(o))a.cursor=a.limit-r;else if(a.bra=a.cursor,!a.slice_del())return;if(a.ket=a.cursor,0!=(r=a.find_among_b(u)))switch(a.bra=a.cursor,r){case 1:if(a.slice_from("ss"))break;return;case 2:r:{var i=a.limit-a.cursor,e=a.cursor-2;if(!(e{a.ket=a.cursor,o=a.find_among_b(n),a.bra=a.cursor;r:{var r=a.limit-a.cursor;i:{switch(o){case 1:var i=a.limit-a.cursor;e:{var e=a.limit-a.cursor;if(0==a.find_among_b(t)||a.cursor>a.limit_backward){if(a.cursor=a.limit-e,!z())break e;if(!a.slice_from("ee"))return}}a.cursor=a.limit-i;break;case 2:break i;case 3:if(0==(o=a.find_among_b(l)))break i;switch(o){case 1:var s=a.limit-a.cursor;if(!a.out_grouping_b(v,97,121))break i;if(a.cursor>a.limit_backward)break i;if(a.cursor=a.limit-s,a.bra=a.cursor,a.slice_from("ie"))break;return;case 2:if(a.cursor>a.limit_backward)break i}}break r}a.cursor=a.limit-r;var c=a.limit-a.cursor;if(!a.go_out_grouping_b(v,97,121))return;if(a.cursor--,a.cursor=a.limit-c,!a.slice_del())return;a.ket=a.cursor,a.bra=a.cursor;var o,c=a.limit-a.cursor;switch(o=a.find_among_b(f)){case 1:return a.slice_from("e");case 2:var u=a.limit-a.cursor;if(a.in_grouping_b(d,97,111)&&!(a.cursor>a.limit_backward))return;a.cursor=a.limit-u;break;case 3:return a.cursor!=h||(u=a.limit-a.cursor,q()&&(a.cursor=a.limit-u,a.slice_from("e")))}if(a.cursor=a.limit-c,a.ket=a.cursor,a.cursor<=a.limit_backward)return;if(a.cursor--,a.bra=a.cursor,!a.slice_del())return}})(),a.cursor=a.limit-r,a.limit-a.cursor),r=(a.ket=a.cursor,e=a.limit-a.cursor,(a.eq_s_b("y")||(a.cursor=a.limit-e,a.eq_s_b("Y")))&&(a.bra=a.cursor,a.out_grouping_b(v,97,121))&&a.cursor>a.limit_backward&&a.slice_from("i"),a.cursor=a.limit-i,a.limit-a.cursor),e=((()=>{var r;if(a.ket=a.cursor,0!=(r=a.find_among_b(_))&&(a.bra=a.cursor,z()))switch(r){case 1:if(a.slice_from("tion"))break;return;case 2:if(a.slice_from("ence"))break;return;case 3:if(a.slice_from("ance"))break;return;case 4:if(a.slice_from("able"))break;return;case 5:if(a.slice_from("ent"))break;return;case 6:if(a.slice_from("ize"))break;return;case 7:if(a.slice_from("ate"))break;return;case 8:if(a.slice_from("al"))break;return;case 9:if(a.slice_from("ful"))break;return;case 10:if(a.slice_from("ous"))break;return;case 11:if(a.slice_from("ive"))break;return;case 12:if(a.slice_from("ble"))break;return;case 13:if(a.slice_from("og"))break;return;case 14:if(!a.eq_s_b("l"))return;if(a.slice_from("og"))break;return;case 15:if(a.slice_from("less"))break;return;case 16:if(!a.in_grouping_b(w,99,116))return;if(a.slice_del())break}})(),a.cursor=a.limit-r,a.limit-a.cursor),i=((()=>{var r;if(a.ket=a.cursor,0!=(r=a.find_among_b(m))&&(a.bra=a.cursor,z()))switch(r){case 1:if(a.slice_from("tion"))break;return;case 2:if(a.slice_from("ate"))break;return;case 3:if(a.slice_from("al"))break;return;case 4:if(a.slice_from("ic"))break;return;case 5:if(a.slice_del())break;return;case 6:if(!Y())return;if(a.slice_del())break}})(),a.cursor=a.limit-e,a.limit-a.cursor),r=((()=>{var r;if(a.ket=a.cursor,0!=(r=a.find_among_b(b))&&(a.bra=a.cursor,Y()))switch(r){case 1:if(a.slice_del())break;return;case 2:var i=a.limit-a.cursor;if(!a.eq_s_b("s")&&(a.cursor=a.limit-i,!a.eq_s_b("t")))return;if(a.slice_del())break}})(),a.cursor=a.limit-i,a.limit-a.cursor),e=((()=>{var r;if(a.ket=a.cursor,0!=(r=a.find_among_b(k)))switch(a.bra=a.cursor,r){case 1:if(!Y()){if(!z())return;var i=a.limit-a.cursor;if(q())return;a.cursor=a.limit-i}if(a.slice_del())break;return;case 2:if(!Y())return;if(!a.eq_s_b("l"))return;if(a.slice_del())break}})(),a.cursor=a.limit-r,a.cursor=a.limit_backward,a.cursor);(()=>{if(p)for(;;){var r=a.cursor;r:{for(;;){var i=a.cursor;if(a.bra=a.cursor,a.eq_s("Y")){a.ket=a.cursor,a.cursor=i;break}if(a.cursor=i,a.cursor>=a.limit)break r;a.cursor++}if(a.slice_from("y"))continue;return}a.cursor=r;break}})(),a.cursor=e}}return!0},this.stemWord=function(r){return a.setCurrent(r),this.stem(),a.getCurrent()}}; +window.Stemmer = EnglishStemmer; diff --git a/build/html/_static/minus.png b/build/html/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/build/html/_static/plus.png b/build/html/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/build/html/_static/pygments.css b/build/html/_static/pygments.css new file mode 100644 index 0000000..9392ddc --- /dev/null +++ b/build/html/_static/pygments.css @@ -0,0 +1,84 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8F5902; font-style: italic } /* Comment */ +.highlight .err { color: #A40000; border: 1px solid #EF2929 } /* Error */ +.highlight .g { color: #000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000 } /* Literal */ +.highlight .n { color: #000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000 } /* Other */ +.highlight .p { color: #000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8F5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8F5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8F5902 } /* Comment.Preproc */ +.highlight .cpf { color: #8F5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8F5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8F5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A40000 } /* Generic.Deleted */ +.highlight .ge { color: #000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000 } /* Generic.EmphStrong */ +.highlight .gr { color: #EF2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #A40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000 } /* Literal.Date */ +.highlight .m { color: #900 } /* Literal.Number */ +.highlight .s { color: #4E9A06 } /* Literal.String */ +.highlight .na { color: #C4A000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000 } /* Name.Class */ +.highlight .no { color: #000 } /* Name.Constant */ +.highlight .nd { color: #888 } /* Name.Decorator */ +.highlight .ni { color: #CE5C00 } /* Name.Entity */ +.highlight .ne { color: #C00; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000 } /* Name.Function */ +.highlight .nl { color: #F57900 } /* Name.Label */ +.highlight .nn { color: #000 } /* Name.Namespace */ +.highlight .nx { color: #000 } /* Name.Other */ +.highlight .py { color: #000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #F8F8F8 } /* Text.Whitespace */ +.highlight .mb { color: #900 } /* Literal.Number.Bin */ +.highlight .mf { color: #900 } /* Literal.Number.Float */ +.highlight .mh { color: #900 } /* Literal.Number.Hex */ +.highlight .mi { color: #900 } /* Literal.Number.Integer */ +.highlight .mo { color: #900 } /* Literal.Number.Oct */ +.highlight .sa { color: #4E9A06 } /* Literal.String.Affix */ +.highlight .sb { color: #4E9A06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4E9A06 } /* Literal.String.Char */ +.highlight .dl { color: #4E9A06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8F5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4E9A06 } /* Literal.String.Double */ +.highlight .se { color: #4E9A06 } /* Literal.String.Escape */ +.highlight .sh { color: #4E9A06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4E9A06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4E9A06 } /* Literal.String.Other */ +.highlight .sr { color: #4E9A06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4E9A06 } /* Literal.String.Single */ +.highlight .ss { color: #4E9A06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465A4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000 } /* Name.Function.Magic */ +.highlight .vc { color: #000 } /* Name.Variable.Class */ +.highlight .vg { color: #000 } /* Name.Variable.Global */ +.highlight .vi { color: #000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000 } /* Name.Variable.Magic */ +.highlight .il { color: #900 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/build/html/_static/searchtools.js b/build/html/_static/searchtools.js new file mode 100644 index 0000000..e29b1c7 --- /dev/null +++ b/build/html/_static/searchtools.js @@ -0,0 +1,693 @@ +/* + * Sphinx JavaScript utilities for the full-text search. + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename, kind] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +// Global search result kind enum, used by themes to style search results. +// prettier-ignore +class SearchResultKind { + static get index() { return "index"; } + static get object() { return "object"; } + static get text() { return "text"; } + static get title() { return "title"; } +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _escapeHTML = (text) => { + return text + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); +}; + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename, kind] = item; + + let listItem = document.createElement("li"); + // Add a class representing the item's type: + // can be used by a theme's CSS selector for styling + // See SearchResultKind for the class names. + listItem.classList.add(`kind-${kind}`); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = _escapeHTML(title); + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + ` (${_escapeHTML(descr)})`; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) + // SPHINX_HIGHLIGHT_ENABLED is set in sphinx_highlight.js + highlightTerms.forEach((term) => + _highlightText(listItem, term, "highlighted"), + ); + } else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor), + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) + // SPHINX_HIGHLIGHT_ENABLED is set in sphinx_highlight.js + highlightTerms.forEach((term) => + _highlightText(listItem, term, "highlighted"), + ); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.", + ); + else + Search.status.innerText = Documentation.ngettext( + "Search finished, found one page matching the search query.", + "Search finished, found ${resultCount} pages matching the search query.", + resultCount, + ).replace("${resultCount}", resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5, + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename, kind]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => + query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter((term) => term); // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString( + htmlString, + "text/html", + ); + for (const removalQuery of [".headerlink", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { + el.remove(); + }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector( + `[role="main"] ${anchor}`, + ); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.`, + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template.", + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.setAttribute("role", "list"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords set is from language_data.js + if (stopwords.has(queryTermLower) || queryTerm.match(/^\d+$/)) return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { + // SPHINX_HIGHLIGHT_ENABLED is set in sphinx_highlight.js + localStorage.setItem( + "sphinx_highlight_terms", + [...highlightTerms].join(" "), + ); + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: ( + query, + searchTerms, + excludedTerms, + highlightTerms, + objectTerms, + ) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename, kind]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if ( + title.toLowerCase().trim().includes(queryLower) + && queryLower.length >= title.length / 2 + ) { + for (const [file, id] of foundTitles) { + const score = Math.round( + (Scorer.title * queryLower.length) / title.length, + ); + const boost = titles[file] === title ? 1 : 0; // add a boost for document titles + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score + boost, + filenames[file], + SearchResultKind.title, + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && queryLower.length >= entry.length / 2) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round((100 * queryLower.length) / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + SearchResultKind.index, + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)), + ); + + // lookup as search terms in fulltext + normalResults.push( + ...Search.performTermsSearch(searchTerms, excludedTerms), + ); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result + .slice(0, 4) + .concat([result[5]]) + .map((v) => String(v)) + .join(","); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [ + searchQuery, + searchTerms, + excludedTerms, + highlightTerms, + objectTerms, + ] = Search._parseQuery(query); + const results = Search._performSearch( + searchQuery, + searchTerms, + excludedTerms, + highlightTerms, + objectTerms, + ); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4]; + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + SearchResultKind.object, + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => objectSearchCallback(prefix, array)), + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + // find documents, if any, containing the query word in their text/title term indices + // use Object.hasOwnProperty to avoid mismatching against prototype properties + const arr = [ + { + files: terms.hasOwnProperty(word) ? terms[word] : undefined, + score: Scorer.term, + }, + { + files: titleTerms.hasOwnProperty(word) ? titleTerms[word] : undefined, + score: Scorer.title, + }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, new Map()); + const fileScores = scoreMap.get(file); + fileScores.set(word, record.score); + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2, + ).length; + if ( + wordList.length !== searchTerms.size + && wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file + || titleTerms[term] === file + || (terms[term] || []).includes(file) + || (titleTerms[term] || []).includes(file), + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file).get(w))); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + SearchResultKind.text, + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = + top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/build/html/_static/sphinx_highlight.js b/build/html/_static/sphinx_highlight.js new file mode 100644 index 0000000..a74e103 --- /dev/null +++ b/build/html/_static/sphinx_highlight.js @@ -0,0 +1,159 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true; + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 + && !parent.classList.contains(className) + && !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore(span, parent.insertBefore(rest, node.nextSibling)); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect", + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target), + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms"); + // Update history only if '?highlight' is present; otherwise it + // clears text fragments (not set in window.location by the browser) + if (url.searchParams.has("highlight")) { + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + } + + // get individual terms from highlight string + const terms = highlight + .toLowerCase() + .split(/\s+/) + .filter((x) => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '", + ), + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms"); + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) + return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) + return; + if ( + DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + && event.key === "Escape" + ) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/build/html/genindex.html b/build/html/genindex.html new file mode 100644 index 0000000..3c1bf09 --- /dev/null +++ b/build/html/genindex.html @@ -0,0 +1,99 @@ + + + + + + + Index — secure-messaging documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/build/html/index.html b/build/html/index.html new file mode 100644 index 0000000..c10c887 --- /dev/null +++ b/build/html/index.html @@ -0,0 +1,135 @@ + + + + + + + + Secure messaging — secure-messaging documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Secure messaging

+

Passthrough NATS envelopes, Ed25519 signed configuration, DataCube +admin-history, and Network Error Bundles.

+

This is not a HIPAA/SOC 2/ISO certificate.

+ +
+

Who calls this module

+

pfc-py-admin (sign config, append history) and systemd pfc-sm-leaf. +Tests send targeted good and bad messages on verae.sm.send.

+
+
+

Messages

+
    +
  • From: console / tests / connectors

  • +
  • To: mailbox dest in the clear; body ciphertext

  • +
  • Success: ack accepted + lookup_id (sender cannot reopen ct)

  • +
  • Failure: SM-MISSING-TO, SM-EMPTY-CT, SM-BAD-ALG, +SM-PLAINTEXT-BODY, SM-BAD-JSONverae.sm.error + +verae.sm.dead + verae.sm.log.summary

  • +
  • Filter: no plaintext body field; summary must not contain ct

  • +
  • Timeout: 5s NATS; 15s NPE sidecar

  • +
+
+
+

Errors

+

Network Error Bundle: ct_sender (sender-only status) and ct_system +(ops bounce, no mail body). logging.mode=summary.

+

Variables: crypto.mode, routing.mode=passthrough, SM_LEAF_HUB, +SM_HTTP. See system-git-sync docs/VARIABLES.md.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/build/html/objects.inv b/build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..85b693a9b1b08435234554166f6eaca0a1bc729d GIT binary patch literal 244 zcmY#Z2rkIT%&Sny%qvUHE6FdaR47X=D$dN$Q!wIERtPA{&q_@$u~H~bO)f1;)y+*U zE>29(%u5H#g+bI=DFE3a8L0|Iskw=nc`2zy3i)XYB^jB;3Tc@+sR}?kIX}0c2&gkP zMWM79s9B*ZCo@TptKyco|Jl=LygkI+yXZ mJEVHL)yb`T_vp%zMNfD_dIbz;2p{~!*!gm041?gku{ literal 0 HcmV?d00001 diff --git a/build/html/search.html b/build/html/search.html new file mode 100644 index 0000000..72e490e --- /dev/null +++ b/build/html/search.html @@ -0,0 +1,117 @@ + + + + + + + Search — secure-messaging documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/build/html/searchindex.js b/build/html/searchindex.js new file mode 100644 index 0000000..5a26db6 --- /dev/null +++ b/build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles":{"Errors":[[0,"errors"]],"Messages":[[0,"messages"]],"Secure messaging":[[0,null]],"Who calls this module":[[0,"who-calls-this-module"]]},"docnames":["index"],"envversion":{"sphinx":66,"sphinx.domains.c":3,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":9,"sphinx.domains.index":1,"sphinx.domains.javascript":3,"sphinx.domains.math":2,"sphinx.domains.python":4,"sphinx.domains.rst":2,"sphinx.domains.std":2},"filenames":["index.rst"],"indexentries":{},"objects":{},"objnames":{},"objtypes":{},"terms":{"15s":0,"5s":0,"From":0,"TO":0,"This":0,"To":0,"accept":0,"ack":0,"admin":0,"alg":0,"append":0,"bad":0,"bodi":0,"bounc":0,"bundl":0,"catalog":0,"certif":0,"ciphertext":0,"clear":0,"cmd":0,"config":0,"configur":0,"connector":0,"consol":0,"contain":0,"crypto":0,"ct":0,"ct_sender":0,"ct_system":0,"datacub":0,"dead":0,"dest":0,"doc":0,"ed25519":0,"empti":0,"endpoint":0,"envelop":0,"failur":0,"field":0,"filter":0,"georgelambert":0,"git":0,"go":0,"good":0,"health":0,"hipaa":0,"histori":0,"https":0,"hub":0,"iso":0,"json":0,"leaf":0,"log":0,"lookup_id":0,"loopback":0,"mail":0,"mailbox":0,"marchon":0,"md":0,"miss":0,"mode":0,"must":0,"nat":0,"network":0,"npe":0,"onli":0,"op":0,"option":0,"org":0,"passthrough":0,"pfc":0,"plaintext":0,"process":0,"py":0,"python":0,"reopen":0,"rout":0,"secure_messag":0,"see":0,"send":0,"sender":0,"servic":0,"sidecar":0,"sign":0,"sm":0,"sm_http":0,"sm_leaf_hub":0,"soc":0,"spec":0,"status":0,"success":0,"summari":0,"sync":0,"system":0,"systemd":0,"target":0,"test":0,"timeout":0,"variabl":0,"vera":0},"titles":["Secure messaging"],"titleterms":{"Who":0,"call":0,"error":0,"messag":0,"modul":0,"secur":0}}) \ No newline at end of file diff --git a/build/latex/.doctrees/environment.pickle b/build/latex/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..42ddaec579bfd9cb889759a9315bfd60cf05915b GIT binary patch literal 14289 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 z zj-kxU>vW^n+xD1lclm3(R`<|$23=9ya#+34aquWOP65*48it%Dx*K&(mbQ?nmRor_e17m9i;C9Vo1z+m6__rUKEu zvNecF0Smf@2(S?yaeLTrB%6@QxX{99tDEs8Nsavs%l{1YB#6$jG>&$`Ow~B;?R7

t4 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 aFIX#fuToGj@6sx}SZE(Q6-dy$KK4I4Ov_3D literal 0 HcmV?d00001 diff --git a/build/latex/.doctrees/index.doctree b/build/latex/.doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9cb143083ddcad61a9ff179f221ee29e8a75a911 GIT binary patch literal 12622 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 U{Z9h3xYzO1!h7t@qPVy6UnnP1NdN!< literal 0 HcmV?d00001 diff --git a/build/latex/LICRcyr2utf8.xdy b/build/latex/LICRcyr2utf8.xdy new file mode 100644 index 0000000..a9ca1c8 --- /dev/null +++ b/build/latex/LICRcyr2utf8.xdy @@ -0,0 +1,101 @@ +;; -*- coding: utf-8; mode: Lisp; -*- +;; style file for xindy +;; filename: LICRcyr2utf8.xdy +;; description: style file for xindy which maps back LaTeX Internal +;; Character Representation of Cyrillic to utf-8 +;; usage: for use with pdflatex produced .idx files. +;; Contributed by the Sphinx team, July 2018. +(merge-rule "\IeC {\'\CYRG }" "Ѓ" :string) +(merge-rule "\IeC {\'\CYRK }" "Ќ" :string) +(merge-rule "\IeC {\'\cyrg }" "ѓ" :string) +(merge-rule "\IeC {\'\cyrk }" "ќ" :string) +(merge-rule "\IeC {\CYRA }" "А" :string) +(merge-rule "\IeC {\CYRB }" "Б" :string) +(merge-rule "\IeC {\CYRC }" "Ц" :string) +(merge-rule "\IeC {\CYRCH }" "Ч" :string) +(merge-rule "\IeC {\CYRD }" "Д" :string) +(merge-rule "\IeC {\CYRDJE }" "Ђ" :string) +(merge-rule "\IeC {\CYRDZE }" "Ѕ" :string) +(merge-rule "\IeC {\CYRDZHE }" "Џ" :string) +(merge-rule "\IeC {\CYRE }" "Е" :string) +(merge-rule "\IeC {\CYREREV }" "Э" :string) +(merge-rule "\IeC {\CYRERY }" "Ы" :string) +(merge-rule "\IeC {\CYRF }" "Ф" :string) +(merge-rule "\IeC {\CYRG }" "Г" :string) +(merge-rule "\IeC {\CYRGUP }" "Ґ" :string) +(merge-rule "\IeC {\CYRH }" "Х" :string) +(merge-rule "\IeC {\CYRHRDSN }" "Ъ" :string) +(merge-rule "\IeC {\CYRI }" "И" :string) +(merge-rule "\IeC {\CYRIE }" "Є" :string) +(merge-rule "\IeC {\CYRII }" "І" :string) +(merge-rule "\IeC {\CYRISHRT }" "Й" :string) +(merge-rule "\IeC {\CYRJE }" "Ј" :string) +(merge-rule "\IeC {\CYRK }" "К" :string) +(merge-rule "\IeC {\CYRL }" "Л" :string) +(merge-rule "\IeC {\CYRLJE }" "Љ" :string) +(merge-rule "\IeC {\CYRM }" "М" :string) +(merge-rule "\IeC {\CYRN }" "Н" :string) +(merge-rule "\IeC {\CYRNJE }" "Њ" :string) +(merge-rule "\IeC {\CYRO }" "О" :string) +(merge-rule "\IeC {\CYRP }" "П" :string) +(merge-rule "\IeC {\CYRR }" "Р" :string) +(merge-rule "\IeC {\CYRS }" "С" :string) +(merge-rule "\IeC {\CYRSFTSN }" "Ь" :string) +(merge-rule "\IeC {\CYRSH }" "Ш" :string) +(merge-rule "\IeC {\CYRSHCH }" "Щ" :string) +(merge-rule "\IeC {\CYRT }" "Т" :string) +(merge-rule "\IeC {\CYRTSHE }" "Ћ" :string) +(merge-rule "\IeC {\CYRU }" "У" :string) +(merge-rule "\IeC {\CYRUSHRT }" "Ў" :string) +(merge-rule "\IeC {\CYRV }" "В" :string) +(merge-rule "\IeC {\CYRYA }" "Я" :string) +(merge-rule "\IeC {\CYRYI }" "Ї" :string) +(merge-rule "\IeC {\CYRYO }" "Ё" :string) +(merge-rule "\IeC {\CYRYU }" "Ю" :string) +(merge-rule "\IeC {\CYRZ }" "З" :string) +(merge-rule "\IeC {\CYRZH }" "Ж" :string) +(merge-rule "\IeC {\cyra }" "а" :string) +(merge-rule "\IeC {\cyrb }" "б" :string) +(merge-rule "\IeC {\cyrc }" "ц" :string) +(merge-rule "\IeC {\cyrch }" "ч" :string) +(merge-rule "\IeC {\cyrd }" "д" :string) +(merge-rule "\IeC {\cyrdje }" "ђ" :string) +(merge-rule "\IeC {\cyrdze }" "ѕ" :string) +(merge-rule "\IeC {\cyrdzhe }" "џ" :string) +(merge-rule "\IeC {\cyre }" "е" :string) +(merge-rule "\IeC {\cyrerev }" "э" :string) +(merge-rule "\IeC {\cyrery }" "ы" :string) +(merge-rule "\IeC {\cyrf }" "ф" :string) +(merge-rule "\IeC {\cyrg }" "г" :string) +(merge-rule "\IeC {\cyrgup }" "ґ" :string) +(merge-rule "\IeC {\cyrh }" "х" :string) +(merge-rule "\IeC {\cyrhrdsn }" "ъ" :string) +(merge-rule "\IeC {\cyri }" "и" :string) +(merge-rule "\IeC {\cyrie }" "є" :string) +(merge-rule "\IeC {\cyrii }" "і" :string) +(merge-rule "\IeC {\cyrishrt }" "й" :string) +(merge-rule "\IeC {\cyrje }" "ј" :string) +(merge-rule "\IeC {\cyrk }" "к" :string) +(merge-rule "\IeC {\cyrl }" "л" :string) +(merge-rule "\IeC {\cyrlje }" "љ" :string) +(merge-rule "\IeC {\cyrm }" "м" :string) +(merge-rule "\IeC {\cyrn }" "н" :string) +(merge-rule "\IeC {\cyrnje }" "њ" :string) +(merge-rule "\IeC {\cyro }" "о" :string) +(merge-rule "\IeC {\cyrp }" "п" :string) +(merge-rule "\IeC {\cyrr }" "р" :string) +(merge-rule "\IeC {\cyrs }" "с" :string) +(merge-rule "\IeC {\cyrsftsn }" "ь" :string) +(merge-rule "\IeC {\cyrsh }" "ш" :string) +(merge-rule "\IeC {\cyrshch }" "щ" :string) +(merge-rule "\IeC {\cyrt }" "т" :string) +(merge-rule "\IeC {\cyrtshe }" "ћ" :string) +(merge-rule "\IeC {\cyru }" "у" :string) +(merge-rule "\IeC {\cyrushrt }" "ў" :string) +(merge-rule "\IeC {\cyrv }" "в" :string) +(merge-rule "\IeC {\cyrya }" "я" :string) +(merge-rule "\IeC {\cyryi }" "ї" :string) +(merge-rule "\IeC {\cyryo }" "ё" :string) +(merge-rule "\IeC {\cyryu }" "ю" :string) +(merge-rule "\IeC {\cyrz }" "з" :string) +(merge-rule "\IeC {\cyrzh }" "ж" :string) diff --git a/build/latex/LICRlatin2utf8.xdy b/build/latex/LICRlatin2utf8.xdy new file mode 100644 index 0000000..1d76825 --- /dev/null +++ b/build/latex/LICRlatin2utf8.xdy @@ -0,0 +1,239 @@ +;; style file for xindy +;; filename: LICRlatin2utf8.xdy +;; description: style file for xindy which maps back LaTeX Internal +;; Character Representation of letters (as arising in .idx index +;; file) to UTF-8 encoding for correct sorting by xindy. +;; usage: for use with the pdflatex engine, +;; *not* for use with xelatex or lualatex. +;; +;; This is based upon xindy's distributed file tex/inputenc/utf8.xdy. +;; The modifications include: +;; +;; - Updates for compatibility with current LaTeX macro encoding. +;; +;; - Systematic usage of the \IeC {...} mark-up, because mark-up in +;; tex/inputenc/utf8.xdy was using it on seemingly random basis, and +;; Sphinx coercing of xindy usability for both Latin and Cyrillic scripts +;; with pdflatex requires its systematic presence here. +;; +;; - Support for some extra letters: Ÿ, Ŋ, ŋ, Œ, œ, IJ, ij, ȷ and ẞ. +;; +;; Indeed Sphinx needs to support for pdflatex engine all Unicode letters +;; available in TeX T1 font encoding. The above letters are found in +;; that encoding but not in the Latin1, 2, 3 charsets which are those +;; covered by original tex/inputenc/utf8.xdy. +;; +;; - There is a problem that ȷ is not supported out-of-the box by LaTeX +;; with inputenc, one must add explicitly +;; \DeclareUnicodeCharacter{0237}{\j} +;; to preamble of LaTeX document. However this character is not supported +;; by the TeX "times" font used by default by Sphinx for pdflatex engine. +;; +;; **Update**: since LaTeX 2018/12/01, the \j as well as \SS, \k{} and +;; \.{} need no extra user declaration anymore. +;; +;; - ẞ needs \DeclareUnicodeCharacter{1E9E}{\SS} (but ß needs no extra set-up). +;; +;; - U+02DB (˛) and U+02D9 (˙) are also not supported by inputenc +;; out of the box and require +;; \DeclareUnicodeCharacter{02DB}{\k{}} +;; \DeclareUnicodeCharacter{02D9}{\.{}} +;; to be added to preamble. +;; +;; - U+0127 ħ and U+0126 Ħ are absent from TeX T1+TS1 font encodings. +;; +;; - Characters Ŋ and ŋ are not supported by TeX font "times" used by +;; default by Sphinx for pdflatex engine but they are supported by +;; some TeX fonts, in particular by the default LaTeX font for T1 +;; encoding. +;; +;; - " and ~ must be escaped as ~" and resp. ~~ in xindy merge rules. +;; +;; Contributed by the Sphinx team, July 2018. +;; +;; See sphinx.xdy for superior figures, as they are escaped by LaTeX writer. +(merge-rule "\IeC {\textonesuperior }" "¹" :string) +(merge-rule "\IeC {\texttwosuperior }" "²" :string) +(merge-rule "\IeC {\textthreesuperior }" "³" :string) +(merge-rule "\IeC {\'a}" "á" :string) +(merge-rule "\IeC {\'A}" "Á" :string) +(merge-rule "\IeC {\`a}" "à" :string) +(merge-rule "\IeC {\`A}" "À" :string) +(merge-rule "\IeC {\^a}" "â" :string) +(merge-rule "\IeC {\^A}" "Â" :string) +(merge-rule "\IeC {\~"a}" "ä" :string) +(merge-rule "\IeC {\~"A}" "Ä" :string) +(merge-rule "\IeC {\~~a}" "ã" :string) +(merge-rule "\IeC {\~~A}" "Ã" :string) +(merge-rule "\IeC {\c c}" "ç" :string) +(merge-rule "\IeC {\c C}" "Ç" :string) +(merge-rule "\IeC {\'c}" "ć" :string) +(merge-rule "\IeC {\'C}" "Ć" :string) +(merge-rule "\IeC {\^c}" "ĉ" :string) +(merge-rule "\IeC {\^C}" "Ĉ" :string) +(merge-rule "\IeC {\.c}" "ċ" :string) +(merge-rule "\IeC {\.C}" "Ċ" :string) +(merge-rule "\IeC {\c s}" "ş" :string) +(merge-rule "\IeC {\c S}" "Ş" :string) +(merge-rule "\IeC {\c t}" "ţ" :string) +(merge-rule "\IeC {\c T}" "Ţ" :string) +(merge-rule "\IeC {\-}" "­" :string); soft hyphen +(merge-rule "\IeC {\textdiv }" "÷" :string) +(merge-rule "\IeC {\'e}" "é" :string) +(merge-rule "\IeC {\'E}" "É" :string) +(merge-rule "\IeC {\`e}" "è" :string) +(merge-rule "\IeC {\`E}" "È" :string) +(merge-rule "\IeC {\^e}" "ê" :string) +(merge-rule "\IeC {\^E}" "Ê" :string) +(merge-rule "\IeC {\~"e}" "ë" :string) +(merge-rule "\IeC {\~"E}" "Ë" :string) +(merge-rule "\IeC {\^g}" "ĝ" :string) +(merge-rule "\IeC {\^G}" "Ĝ" :string) +(merge-rule "\IeC {\.g}" "ġ" :string) +(merge-rule "\IeC {\.G}" "Ġ" :string) +(merge-rule "\IeC {\^h}" "ĥ" :string) +(merge-rule "\IeC {\^H}" "Ĥ" :string) +(merge-rule "\IeC {\H o}" "ő" :string) +(merge-rule "\IeC {\H O}" "Ő" :string) +(merge-rule "\IeC {\textacutedbl }" "˝" :string) +(merge-rule "\IeC {\H u}" "ű" :string) +(merge-rule "\IeC {\H U}" "Ű" :string) +(merge-rule "\IeC {\ae }" "æ" :string) +(merge-rule "\IeC {\AE }" "Æ" :string) +(merge-rule "\IeC {\textcopyright }" "©" :string) +(merge-rule "\IeC {\c \ }" "¸" :string) +(merge-rule "\IeC {\dh }" "ð" :string) +(merge-rule "\IeC {\DH }" "Ð" :string) +(merge-rule "\IeC {\dj }" "đ" :string) +(merge-rule "\IeC {\DJ }" "Đ" :string) +(merge-rule "\IeC {\guillemotleft }" "«" :string) +(merge-rule "\IeC {\guillemotright }" "»" :string) +(merge-rule "\IeC {\'\i }" "í" :string) +(merge-rule "\IeC {\`\i }" "ì" :string) +(merge-rule "\IeC {\^\i }" "î" :string) +(merge-rule "\IeC {\~"\i }" "ï" :string) +(merge-rule "\IeC {\i }" "ı" :string) +(merge-rule "\IeC {\^\j }" "ĵ" :string) +(merge-rule "\IeC {\k {}}" "˛" :string) +(merge-rule "\IeC {\l }" "ł" :string) +(merge-rule "\IeC {\L }" "Ł" :string) +(merge-rule "\IeC {\nobreakspace }" " " :string) +(merge-rule "\IeC {\o }" "ø" :string) +(merge-rule "\IeC {\O }" "Ø" :string) +(merge-rule "\IeC {\textsterling }" "£" :string) +(merge-rule "\IeC {\textparagraph }" "¶" :string) +(merge-rule "\IeC {\ss }" "ß" :string) +(merge-rule "\IeC {\textsection }" "§" :string) +(merge-rule "\IeC {\textbrokenbar }" "¦" :string) +(merge-rule "\IeC {\textcent }" "¢" :string) +(merge-rule "\IeC {\textcurrency }" "¤" :string) +(merge-rule "\IeC {\textdegree }" "°" :string) +(merge-rule "\IeC {\textexclamdown }" "¡" :string) +(merge-rule "\IeC {\texthbar }" "ħ" :string) +(merge-rule "\IeC {\textHbar }" "Ħ" :string) +(merge-rule "\IeC {\textonehalf }" "½" :string) +(merge-rule "\IeC {\textonequarter }" "¼" :string) +(merge-rule "\IeC {\textordfeminine }" "ª" :string) +(merge-rule "\IeC {\textordmasculine }" "º" :string) +(merge-rule "\IeC {\textperiodcentered }" "·" :string) +(merge-rule "\IeC {\textquestiondown }" "¿" :string) +(merge-rule "\IeC {\textregistered }" "®" :string) +(merge-rule "\IeC {\textthreequarters }" "¾" :string) +(merge-rule "\IeC {\textyen }" "¥" :string) +(merge-rule "\IeC {\th }" "þ" :string) +(merge-rule "\IeC {\TH }" "Þ" :string) +(merge-rule "\IeC {\'I}" "Í" :string) +(merge-rule "\IeC {\`I}" "Ì" :string) +(merge-rule "\IeC {\^I}" "Î" :string) +(merge-rule "\IeC {\~"I}" "Ï" :string) +(merge-rule "\IeC {\.I}" "İ" :string) +(merge-rule "\IeC {\^J}" "Ĵ" :string) +(merge-rule "\IeC {\k a}" "ą" :string) +(merge-rule "\IeC {\k A}" "Ą" :string) +(merge-rule "\IeC {\k e}" "ę" :string) +(merge-rule "\IeC {\k E}" "Ę" :string) +(merge-rule "\IeC {\'l}" "ĺ" :string) +(merge-rule "\IeC {\'L}" "Ĺ" :string) +(merge-rule "\IeC {\textlnot }" "¬" :string) +(merge-rule "\IeC {\textmu }" "µ" :string) +(merge-rule "\IeC {\'n}" "ń" :string) +(merge-rule "\IeC {\'N}" "Ń" :string) +(merge-rule "\IeC {\~~n}" "ñ" :string) +(merge-rule "\IeC {\~~N}" "Ñ" :string) +(merge-rule "\IeC {\'o}" "ó" :string) +(merge-rule "\IeC {\'O}" "Ó" :string) +(merge-rule "\IeC {\`o}" "ò" :string) +(merge-rule "\IeC {\`O}" "Ò" :string) +(merge-rule "\IeC {\^o}" "ô" :string) +(merge-rule "\IeC {\^O}" "Ô" :string) +(merge-rule "\IeC {\~"o}" "ö" :string) +(merge-rule "\IeC {\~"O}" "Ö" :string) +(merge-rule "\IeC {\~~o}" "õ" :string) +(merge-rule "\IeC {\~~O}" "Õ" :string) +(merge-rule "\IeC {\textpm }" "±" :string) +(merge-rule "\IeC {\r a}" "å" :string) +(merge-rule "\IeC {\r A}" "Å" :string) +(merge-rule "\IeC {\'r}" "ŕ" :string) +(merge-rule "\IeC {\'R}" "Ŕ" :string) +(merge-rule "\IeC {\r u}" "ů" :string) +(merge-rule "\IeC {\r U}" "Ů" :string) +(merge-rule "\IeC {\'s}" "ś" :string) +(merge-rule "\IeC {\'S}" "Ś" :string) +(merge-rule "\IeC {\^s}" "ŝ" :string) +(merge-rule "\IeC {\^S}" "Ŝ" :string) +(merge-rule "\IeC {\textasciidieresis }" "¨" :string) +(merge-rule "\IeC {\textasciimacron }" "¯" :string) +(merge-rule "\IeC {\.{}}" "˙" :string) +(merge-rule "\IeC {\textasciiacute }" "´" :string) +(merge-rule "\IeC {\texttimes }" "×" :string) +(merge-rule "\IeC {\u a}" "ă" :string) +(merge-rule "\IeC {\u A}" "Ă" :string) +(merge-rule "\IeC {\u g}" "ğ" :string) +(merge-rule "\IeC {\u G}" "Ğ" :string) +(merge-rule "\IeC {\textasciibreve }" "˘" :string) +(merge-rule "\IeC {\'u}" "ú" :string) +(merge-rule "\IeC {\'U}" "Ú" :string) +(merge-rule "\IeC {\`u}" "ù" :string) +(merge-rule "\IeC {\`U}" "Ù" :string) +(merge-rule "\IeC {\^u}" "û" :string) +(merge-rule "\IeC {\^U}" "Û" :string) +(merge-rule "\IeC {\~"u}" "ü" :string) +(merge-rule "\IeC {\~"U}" "Ü" :string) +(merge-rule "\IeC {\u u}" "ŭ" :string) +(merge-rule "\IeC {\u U}" "Ŭ" :string) +(merge-rule "\IeC {\v c}" "č" :string) +(merge-rule "\IeC {\v C}" "Č" :string) +(merge-rule "\IeC {\v d}" "ď" :string) +(merge-rule "\IeC {\v D}" "Ď" :string) +(merge-rule "\IeC {\v e}" "ě" :string) +(merge-rule "\IeC {\v E}" "Ě" :string) +(merge-rule "\IeC {\v l}" "ľ" :string) +(merge-rule "\IeC {\v L}" "Ľ" :string) +(merge-rule "\IeC {\v n}" "ň" :string) +(merge-rule "\IeC {\v N}" "Ň" :string) +(merge-rule "\IeC {\v r}" "ř" :string) +(merge-rule "\IeC {\v R}" "Ř" :string) +(merge-rule "\IeC {\v s}" "š" :string) +(merge-rule "\IeC {\v S}" "Š" :string) +(merge-rule "\IeC {\textasciicaron }" "ˇ" :string) +(merge-rule "\IeC {\v t}" "ť" :string) +(merge-rule "\IeC {\v T}" "Ť" :string) +(merge-rule "\IeC {\v z}" "ž" :string) +(merge-rule "\IeC {\v Z}" "Ž" :string) +(merge-rule "\IeC {\'y}" "ý" :string) +(merge-rule "\IeC {\'Y}" "Ý" :string) +(merge-rule "\IeC {\~"y}" "ÿ" :string) +(merge-rule "\IeC {\'z}" "ź" :string) +(merge-rule "\IeC {\'Z}" "Ź" :string) +(merge-rule "\IeC {\.z}" "ż" :string) +(merge-rule "\IeC {\.Z}" "Ż" :string) +;; letters not in Latin1, 2, 3 but available in TeX T1 font encoding +(merge-rule "\IeC {\~"Y}" "Ÿ" :string) +(merge-rule "\IeC {\NG }" "Ŋ" :string) +(merge-rule "\IeC {\ng }" "ŋ" :string) +(merge-rule "\IeC {\OE }" "Œ" :string) +(merge-rule "\IeC {\oe }" "œ" :string) +(merge-rule "\IeC {\IJ }" "IJ" :string) +(merge-rule "\IeC {\ij }" "ij" :string) +(merge-rule "\IeC {\j }" "ȷ" :string) +(merge-rule "\IeC {\SS }" "ẞ" :string) diff --git a/build/latex/LatinRules.xdy b/build/latex/LatinRules.xdy new file mode 100644 index 0000000..b20fbbb --- /dev/null +++ b/build/latex/LatinRules.xdy @@ -0,0 +1,611 @@ +;; Common Lisp style file for xindy +;; filename: LatinRules.xdy +;; +;; Please note that this data file deliberately uses strings +;; with single non-ascii bytes. This is intentional and +;; follows the usage observed in similar xindy support files. +;; +;; It is based upon xindy's files lang/general/utf8.xdy and +;; lang/general/utf8-lang.xdy which implement +;; "a general sorting order for Western European languages". +;; +;; The aim for Sphinx is to be able to index in a Cyrillic document +;; also terms using the Latin alphabets, inclusive of letters +;; with diacritics. To this effect the xindy rules from lang/general +;; got manually re-coded to avoid collisions with the encoding +;; done by xindy for sorting words in Cyrillic languages, which was +;; observed not to use bytes with octal encoding 0o266 or higher. +;; +;; So here we use only 0o266 or higher bytes. +;; (Ŋ, ŋ, IJ, and ij are absent from +;; lang/general/utf8.xdy and not included here.) +;; Contributed by the Sphinx team, 2018. + +(define-letter-group "A" :prefixes ("")) +(define-letter-group "B" :after "A" :prefixes ("")) +(define-letter-group "C" :after "B" :prefixes ("")) +(define-letter-group "D" :after "C" :prefixes ("")) +(define-letter-group "E" :after "D" :prefixes ("")) +(define-letter-group "F" :after "E" :prefixes ("")) +(define-letter-group "G" :after "F" :prefixes ("")) +(define-letter-group "H" :after "G" :prefixes ("")) +(define-letter-group "I" :after "H" :prefixes ("")) +(define-letter-group "J" :after "I" :prefixes ("")) +(define-letter-group "K" :after "J" :prefixes ("")) +(define-letter-group "L" :after "K" :prefixes ("")) +(define-letter-group "M" :after "L" :prefixes ("")) +(define-letter-group "N" :after "M" :prefixes ("")) +(define-letter-group "O" :after "N" :prefixes ("")) +(define-letter-group "P" :after "O" :prefixes ("")) +(define-letter-group "Q" :after "P" :prefixes ("")) +(define-letter-group "R" :after "Q" :prefixes ("")) +(define-letter-group "S" :after "R" :prefixes ("")) +(define-letter-group "T" :after "S" :prefixes ("")) +(define-letter-group "U" :after "T" :prefixes ("")) +(define-letter-group "V" :after "U" :prefixes ("")) +(define-letter-group "W" :after "V" :prefixes ("")) +(define-letter-group "X" :after "W" :prefixes ("")) +(define-letter-group "Y" :after "X" :prefixes ("")) +(define-letter-group "Z" :after "Y" :prefixes ("")) + +(define-rule-set "sphinx-xy-alphabetize" + + :rules (("À" "" :string) + ("Ă" "" :string) + ("â" "" :string) + ("Ä" "" :string) + ("à" "" :string) + ("Å" "" :string) + ("Ã" "" :string) + ("Á" "" :string) + ("á" "" :string) + ("ã" "" :string) + ("Â" "" :string) + ("ă" "" :string) + ("å" "" :string) + ("ą" "" :string) + ("ä" "" :string) + ("Ą" "" :string) + ("æ" "" :string) + ("Æ" "" :string) + ("ć" "" :string) + ("ĉ" "" :string) + ("ç" "" :string) + ("Č" "" :string) + ("č" "" :string) + ("Ĉ" "" :string) + ("Ç" "" :string) + ("Ć" "" :string) + ("ď" "" :string) + ("Đ" "" :string) + ("Ď" "" :string) + ("đ" "" :string) + ("ê" "" :string) + ("Ę" "" :string) + ("Ě" "" :string) + ("ë" "" :string) + ("ě" "" :string) + ("é" "" :string) + ("È" "" :string) + ("Ë" "" :string) + ("É" "" :string) + ("è" "" :string) + ("Ê" "" :string) + ("ę" "" :string) + ("ĝ" "" :string) + ("ğ" "" :string) + ("Ğ" "" :string) + ("Ĝ" "" :string) + ("ĥ" "" :string) + ("Ĥ" "" :string) + ("Ï" "" :string) + ("Í" "" :string) + ("ï" "" :string) + ("Î" "" :string) + ("î" "" :string) + ("ı" "" :string) + ("İ" "" :string) + ("í" "" :string) + ("Ì" "" :string) + ("ì" "" :string) + ("Ĵ" "" :string) + ("ĵ" "" :string) + ("ł" "" :string) + ("Ł" "" :string) + ("ľ" "" :string) + ("Ľ" "" :string) + ("ń" "" :string) + ("Ń" "" :string) + ("ñ" "" :string) + ("ň" "" :string) + ("Ñ" "" :string) + ("Ň" "" :string) + ("Õ" "" :string) + ("Ő" "" :string) + ("ó" "" :string) + ("ö" "" :string) + ("ô" "" :string) + ("ő" "" :string) + ("Ø" "" :string) + ("Ö" "" :string) + ("õ" "" :string) + ("Ô" "" :string) + ("ø" "" :string) + ("Ó" "" :string) + ("Ò" "" :string) + ("ò" "" :string) + ("œ" "ĺ" :string) + ("Œ" "ĺ" :string) + ("Ř" "" :string) + ("ř" "" :string) + ("Ŕ" "" :string) + ("ŕ" "" :string) + ("ŝ" "" :string) + ("Ś" "" :string) + ("ș" "" :string) + ("ş" "" :string) + ("Ŝ" "" :string) + ("ś" "" :string) + ("Ș" "" :string) + ("š" "" :string) + ("Ş" "" :string) + ("Š" "" :string) + ("ß" "" :string) + ("Ț" "" :string) + ("Ť" "" :string) + ("ț" "" :string) + ("ť" "" :string) + ("û" "" :string) + ("ŭ" "" :string) + ("ů" "" :string) + ("ű" "" :string) + ("ù" "" :string) + ("Ŭ" "" :string) + ("Ù" "" :string) + ("Ű" "" :string) + ("Ü" "" :string) + ("Ů" "" :string) + ("ú" "" :string) + ("Ú" "" :string) + ("Û" "" :string) + ("ü" "" :string) + ("ÿ" "" :string) + ("Ý" "" :string) + ("Ÿ" "" :string) + ("ý" "" :string) + ("Ż" "" :string) + ("Ž" "" :string) + ("Ź" "" :string) + ("ž" "" :string) + ("ż" "" :string) + ("ź" "" :string) + ("a" "" :string) + ("A" "" :string) + ("b" "" :string) + ("B" "" :string) + ("c" "" :string) + ("C" "" :string) + ("d" "" :string) + ("D" "" :string) + ("e" "" :string) + ("E" "" :string) + ("F" "" :string) + ("f" "" :string) + ("G" "" :string) + ("g" "" :string) + ("H" "" :string) + ("h" "" :string) + ("i" "" :string) + ("I" "" :string) + ("J" "" :string) + ("j" "" :string) + ("K" "" :string) + ("k" "" :string) + ("L" "" :string) + ("l" "" :string) + ("M" "" :string) + ("m" "" :string) + ("n" "" :string) + ("N" "" :string) + ("O" "" :string) + ("o" "" :string) + ("p" "" :string) + ("P" "" :string) + ("Q" "" :string) + ("q" "" :string) + ("r" "" :string) + ("R" "" :string) + ("S" "" :string) + ("s" "" :string) + ("t" "" :string) + ("T" "" :string) + ("u" "" :string) + ("U" "" :string) + ("v" "" :string) + ("V" "" :string) + ("W" "" :string) + ("w" "" :string) + ("x" "" :string) + ("X" "" :string) + ("Y" "" :string) + ("y" "" :string) + ("z" "" :string) + ("Z" "" :string) + )) + +(define-rule-set "sphinx-xy-resolve-diacritics" + + :rules (("Ĥ" "" :string) + ("ó" "" :string) + ("ľ" "" :string) + ("Ř" "" :string) + ("ĝ" "" :string) + ("ď" "" :string) + ("Ě" "" :string) + ("ĥ" "" :string) + ("Č" "" :string) + ("Ĵ" "" :string) + ("ě" "" :string) + ("ž" "" :string) + ("Ď" "" :string) + ("ř" "" :string) + ("Ž" "" :string) + ("ı" "" :string) + ("Ť" "" :string) + ("á" "" :string) + ("č" "" :string) + ("Á" "" :string) + ("ň" "" :string) + ("Š" "" :string) + ("Ň" "" :string) + ("ĵ" "" :string) + ("ť" "" :string) + ("Ó" "" :string) + ("ý" "" :string) + ("Ĝ" "" :string) + ("Ú" "" :string) + ("Ľ" "" :string) + ("š" "" :string) + ("Ý" "" :string) + ("ú" "" :string) + ("Ś" "" :string) + ("ć" "" :string) + ("Ł" "" :string) + ("ł" "" :string) + ("ń" "" :string) + ("À" "" :string) + ("Ź" "" :string) + ("à" "" :string) + ("Ń" "" :string) + ("Đ" "" :string) + ("ÿ" "" :string) + ("ś" "" :string) + ("Ğ" "" :string) + ("ğ" "" :string) + ("Ù" "" :string) + ("İ" "" :string) + ("đ" "" :string) + ("ù" "" :string) + ("Ț" "" :string) + ("é" "" :string) + ("ŕ" "" :string) + ("Ć" "" :string) + ("ț" "" :string) + ("ò" "" :string) + ("ź" "" :string) + ("Ò" "" :string) + ("Ÿ" "" :string) + ("Ŕ" "" :string) + ("É" "" :string) + ("ĉ" "" :string) + ("ô" "" :string) + ("Í" "" :string) + ("ŝ" "" :string) + ("Ż" "" :string) + ("Ă" "" :string) + ("Ŝ" "" :string) + ("ñ" "" :string) + ("ŭ" "" :string) + ("í" "" :string) + ("È" "" :string) + ("Ô" "" :string) + ("Ŭ" "" :string) + ("ż" "" :string) + ("Ñ" "" :string) + ("è" "" :string) + ("Ĉ" "" :string) + ("ă" "" :string) + ("â" "" :string) + ("û" "" :string) + ("ê" "" :string) + ("Õ" "" :string) + ("õ" "" :string) + ("ș" "" :string) + ("ç" "" :string) + ("Â" "" :string) + ("Ê" "" :string) + ("Û" "" :string) + ("Ç" "" :string) + ("ì" "" :string) + ("Ì" "" :string) + ("Ș" "" :string) + ("ö" "" :string) + ("Ö" "" :string) + ("ş" "" :string) + ("ů" "" :string) + ("ë" "" :string) + ("ã" "" :string) + ("î" "" :string) + ("Î" "" :string) + ("Ã" "" :string) + ("Ş" "" :string) + ("Ů" "" :string) + ("Ë" "" :string) + ("ï" "" :string) + ("Ő" "" :string) + ("Ï" "" :string) + ("Ę" "" :string) + ("ő" "" :string) + ("Ü" "" :string) + ("Å" "" :string) + ("ü" "" :string) + ("ę" "" :string) + ("å" "" :string) + ("Ä" "" :string) + ("ű" "" :string) + ("Ø" "" :string) + ("ø" "" :string) + ("Ű" "" :string) + ("ä" "" :string) + ("Ą" "" :string) + ("ą" "" :string) + ("œ" "" :string) + ("ß" "" :string) + ("Æ" "" :string) + ("Œ" "" :string) + ("æ" "" :string) + ("e" "" :string) + ("t" "" :string) + ("L" "" :string) + ("Y" "" :string) + ("J" "" :string) + ("a" "" :string) + ("p" "" :string) + ("u" "" :string) + ("j" "" :string) + ("b" "" :string) + ("G" "" :string) + ("U" "" :string) + ("F" "" :string) + ("H" "" :string) + ("i" "" :string) + ("z" "" :string) + ("c" "" :string) + ("l" "" :string) + ("A" "" :string) + ("Q" "" :string) + ("w" "" :string) + ("D" "" :string) + ("R" "" :string) + ("d" "" :string) + ("s" "" :string) + ("r" "" :string) + ("k" "" :string) + ("v" "" :string) + ("m" "" :string) + ("P" "" :string) + ("y" "" :string) + ("K" "" :string) + ("q" "" :string) + ("S" "" :string) + ("I" "" :string) + ("C" "" :string) + ("M" "" :string) + ("Z" "" :string) + ("T" "" :string) + ("W" "" :string) + ("B" "" :string) + ("h" "" :string) + ("x" "" :string) + ("X" "" :string) + ("f" "" :string) + ("E" "" :string) + ("V" "" :string) + ("N" "" :string) + ("O" "" :string) + ("o" "" :string) + ("g" "" :string) + ("n" "" :string) + )) + +(define-rule-set "sphinx-xy-resolve-case" + + :rules (("Ú" "8" :string) + ("Ÿ" "8" :string) + ("Ç" "8" :string) + ("Ĉ" "8" :string) + ("Ŕ" "8" :string) + ("Ľ" "8" :string) + ("Ů" "8" :string) + ("Ý" "8" :string) + ("É" "8" :string) + ("Ë" "8" :string) + ("Ș" "8" :string) + ("Ì" "8" :string) + ("Ê" "8" :string) + ("Ň" "8" :string) + ("Ą" "8" :string) + ("Š" "8" :string) + ("Û" "8" :string) + ("Ş" "8" :string) + ("Ć" "8" :string) + ("Ò" "8" :string) + ("Ĝ" "8" :string) + ("Ñ" "8" :string) + ("Ó" "8" :string) + ("Î" "8" :string) + ("Á" "8" :string) + ("Ã" "8" :string) + ("Ț" "8" :string) + ("Å" "8" :string) + ("Ğ" "8" :string) + ("Ü" "8" :string) + ("È" "8" :string) + ("Ô" "8" :string) + ("İ" "8" :string) + ("Ű" "8" :string) + ("Ù" "8" :string) + ("Ŭ" "8" :string) + ("Â" "8" :string) + ("Ť" "8" :string) + ("Ń" "8" :string) + ("Ď" "8" :string) + ("Ź" "8" :string) + ("Ž" "8" :string) + ("Đ" "8" :string) + ("Ŝ" "8" :string) + ("Č" "8" :string) + ("Ĵ" "8" :string) + ("Ö" "8" :string) + ("Ø" "8" :string) + ("Ż" "8" :string) + ("Ł" "8" :string) + ("Ă" "8" :string) + ("Ě" "8" :string) + ("Ő" "8" :string) + ("Õ" "8" :string) + ("Ę" "8" :string) + ("Ï" "8" :string) + ("À" "8" :string) + ("Ĥ" "8" :string) + ("Ä" "8" :string) + ("Ś" "8" :string) + ("Ř" "8" :string) + ("Í" "8" :string) + ("Œ" "89" :string) + ("Æ" "89" :string) + ("ì" "9" :string) + ("è" "9" :string) + ("ą" "9" :string) + ("š" "9" :string) + ("ú" "9" :string) + ("å" "9" :string) + ("ă" "9" :string) + ("ę" "9" :string) + ("ü" "9" :string) + ("ź" "9" :string) + ("ò" "9" :string) + ("ť" "9" :string) + ("ț" "9" :string) + ("ĵ" "9" :string) + ("ŕ" "9" :string) + ("ż" "9" :string) + ("ä" "9" :string) + ("ý" "9" :string) + ("ù" "9" :string) + ("á" "9" :string) + ("é" "9" :string) + ("č" "9" :string) + ("ň" "9" :string) + ("ś" "9" :string) + ("ø" "9" :string) + ("í" "9" :string) + ("đ" "9" :string) + ("ı" "9" :string) + ("ğ" "9" :string) + ("î" "9" :string) + ("ã" "9" :string) + ("à" "9" :string) + ("ř" "9" :string) + ("ő" "9" :string) + ("ů" "9" :string) + ("ș" "9" :string) + ("ÿ" "9" :string) + ("ë" "9" :string) + ("ŭ" "9" :string) + ("ç" "9" :string) + ("ű" "9" :string) + ("ñ" "9" :string) + ("õ" "9" :string) + ("ě" "9" :string) + ("ş" "9" :string) + ("ž" "9" :string) + ("ĝ" "9" :string) + ("ŝ" "9" :string) + ("ń" "9" :string) + ("û" "9" :string) + ("ł" "9" :string) + ("ď" "9" :string) + ("ĥ" "9" :string) + ("ê" "9" :string) + ("ô" "9" :string) + ("ĉ" "9" :string) + ("â" "9" :string) + ("ć" "9" :string) + ("ï" "9" :string) + ("ö" "9" :string) + ("ľ" "9" :string) + ("ó" "9" :string) + ("æ" "99" :string) + ("ß" "99" :string) + ("œ" "99" :string) + ("N" "8" :string) + ("V" "8" :string) + ("O" "8" :string) + ("X" "8" :string) + ("E" "8" :string) + ("P" "8" :string) + ("K" "8" :string) + ("T" "8" :string) + ("Z" "8" :string) + ("M" "8" :string) + ("C" "8" :string) + ("I" "8" :string) + ("S" "8" :string) + ("B" "8" :string) + ("W" "8" :string) + ("D" "8" :string) + ("R" "8" :string) + ("H" "8" :string) + ("F" "8" :string) + ("Q" "8" :string) + ("A" "8" :string) + ("G" "8" :string) + ("U" "8" :string) + ("J" "8" :string) + ("Y" "8" :string) + ("L" "8" :string) + ("o" "9" :string) + ("n" "9" :string) + ("g" "9" :string) + ("x" "9" :string) + ("f" "9" :string) + ("y" "9" :string) + ("q" "9" :string) + ("h" "9" :string) + ("w" "9" :string) + ("s" "9" :string) + ("d" "9" :string) + ("v" "9" :string) + ("k" "9" :string) + ("r" "9" :string) + ("m" "9" :string) + ("z" "9" :string) + ("c" "9" :string) + ("i" "9" :string) + ("l" "9" :string) + ("b" "9" :string) + ("j" "9" :string) + ("a" "9" :string) + ("p" "9" :string) + ("u" "9" :string) + ("t" "9" :string) + ("e" "9" :string) + )) + +(use-rule-set :run 0 + :rule-set ("sphinx-xy-alphabetize")) +(use-rule-set :run 1 + :rule-set ("sphinx-xy-resolve-diacritics")) +(use-rule-set :run 2 + :rule-set ("sphinx-xy-resolve-case")) diff --git a/build/latex/Makefile b/build/latex/Makefile new file mode 100644 index 0000000..3d4f1c9 --- /dev/null +++ b/build/latex/Makefile @@ -0,0 +1,65 @@ +# Makefile for Sphinx LaTeX output + +ALLDOCS = $(basename $(wildcard *.tex)) +ALLPDF = $(addsuffix .pdf,$(ALLDOCS)) +ALLDVI = $(addsuffix .dvi,$(ALLDOCS)) +ALLXDV = +ALLPS = $(addsuffix .ps,$(ALLDOCS)) + +# Prefix for archive names +ARCHIVEPREFIX = +# Additional LaTeX options (passed via variables in latexmkrc/latexmkjarc file) +export LATEXOPTS ?= +# Additional latexmk options +LATEXMKOPTS ?= +# format: pdf or dvi (used only by archive targets) +FMT = pdf + +LATEX = latexmk -dvi +PDFLATEX = latexmk -pdf -dvi- -ps- + + +%.dvi: %.tex FORCE_MAKE + $(LATEX) $(LATEXMKOPTS) '$<' + +%.ps: %.dvi + dvips '$<' + +%.pdf: %.tex FORCE_MAKE + $(PDFLATEX) $(LATEXMKOPTS) '$<' + +all: $(ALLPDF) + +all-dvi: $(ALLDVI) + +all-ps: $(ALLPS) + +all-pdf: $(ALLPDF) + +zip: all-$(FMT) + mkdir $(ARCHIVEPREFIX)docs-$(FMT) + cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT) + zip -q -r -9 $(ARCHIVEPREFIX)docs-$(FMT).zip $(ARCHIVEPREFIX)docs-$(FMT) + rm -r $(ARCHIVEPREFIX)docs-$(FMT) + +tar: all-$(FMT) + mkdir $(ARCHIVEPREFIX)docs-$(FMT) + cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT) + tar cf $(ARCHIVEPREFIX)docs-$(FMT).tar $(ARCHIVEPREFIX)docs-$(FMT) + rm -r $(ARCHIVEPREFIX)docs-$(FMT) + +gz: tar + # -n to omit mtime from gzip headers + gzip -n -9 < $(ARCHIVEPREFIX)docs-$(FMT).tar > $(ARCHIVEPREFIX)docs-$(FMT).tar.gz + +bz2: tar + bzip2 -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar + +xz: tar + xz -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar + +clean: + rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ps *.tar *.tar.gz *.tar.bz2 *.tar.xz $(ALLPDF) $(ALLDVI) $(ALLXDV) *.fls *.fdb_latexmk + +.PHONY: all all-pdf all-dvi all-ps clean zip tar gz bz2 xz +.PHONY: FORCE_MAKE \ No newline at end of file diff --git a/build/latex/latexmkjarc b/build/latex/latexmkjarc new file mode 100644 index 0000000..6e36b19 --- /dev/null +++ b/build/latex/latexmkjarc @@ -0,0 +1,22 @@ +$latex = 'pdflatex ' . $ENV{'LATEXOPTS'} . ' -kanji=utf8 %O %S'; +$dvipdf = 'dvipdfmx %O -o %D %S'; +$makeindex = 'internal mendex %S %B %D'; +sub mendex { + my ($source, $basename, $destination) = @_; + my $dictfile = $basename . ".dic"; + unlink($destination); + system("mendex", "-U", "-f", "-d", $dictfile, "-s", "python.ist", $source); + if ($? > 0) { + print("mendex exited with error code $? (ignored)\n"); + } + if (!-e $destination) { + # create an empty .ind file if nothing + open(FH, ">" . $destination); + close(FH); + } + return 0; +} +add_cus_dep( "glo", "gls", 0, "makeglo" ); +sub makeglo { + return system( "mendex -J -f -s gglo.ist -o '$_[0].gls' '$_[0].glo'" ); +} \ No newline at end of file diff --git a/build/latex/latexmkrc b/build/latex/latexmkrc new file mode 100644 index 0000000..bba17fa --- /dev/null +++ b/build/latex/latexmkrc @@ -0,0 +1,9 @@ +$latex = 'latex ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$pdflatex = 'pdflatex ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$lualatex = 'lualatex ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$xelatex = 'xelatex --no-pdf ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$makeindex = 'makeindex -s python.ist %O -o %D %S'; +add_cus_dep( "glo", "gls", 0, "makeglo" ); +sub makeglo { + return system( "makeindex -s gglo.ist -o '$_[0].gls' '$_[0].glo'" ); +} \ No newline at end of file diff --git a/build/latex/make.bat b/build/latex/make.bat new file mode 100644 index 0000000..94bda21 --- /dev/null +++ b/build/latex/make.bat @@ -0,0 +1,31 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +pushd %~dp0 + +set PDFLATEX=latexmk -pdf -dvi- -ps- + +set "LATEXOPTS= " + +if "%1" == "" goto all-pdf + +if "%1" == "all-pdf" ( + :all-pdf + for %%i in (*.tex) do ( + %PDFLATEX% %LATEXMKOPTS% %%i + ) + goto end +) + +if "%1" == "all-pdf-ja" ( + goto all-pdf +) + +if "%1" == "clean" ( + del /q /s *.dvi *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ps *.tar *.tar.gz *.tar.bz2 *.tar.xz *.fls *.fdb_latexmk + goto end +) + +:end +popd \ No newline at end of file diff --git a/build/latex/python.ist b/build/latex/python.ist new file mode 100644 index 0000000..70536a6 --- /dev/null +++ b/build/latex/python.ist @@ -0,0 +1,16 @@ +line_max 100 +headings_flag 1 +heading_prefix " \\bigletter " + +preamble "\\begin{sphinxtheindex} +\\let\\bigletter\\sphinxstyleindexlettergroup +\\let\\spxpagem \\sphinxstyleindexpagemain +\\let\\spxentry \\sphinxstyleindexentry +\\let\\spxextra \\sphinxstyleindexextra + +" + +postamble "\n\n\\end{sphinxtheindex}\n" + +symhead_positive "{\\sphinxsymbolsname}" +numhead_positive "{\\sphinxnumbersname}" diff --git a/build/latex/secure-messaging.aux b/build/latex/secure-messaging.aux new file mode 100644 index 0000000..05c77b3 --- /dev/null +++ b/build/latex/secure-messaging.aux @@ -0,0 +1,21 @@ +\relax +\providecommand \babel@aux [2]{\global \let \babel@toc \@gobbletwo } +\@nameuse{bbl@beforestart} +\providecommand\hyper@newdestlabel[2]{} +\providecommand\HyField@AuxAddToFields[1]{} +\providecommand\HyField@AuxAddToCoFields[2]{} +\babel@aux{english}{} +\newlabel{index::doc}{{}{1}{}{section*.2}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {1}Who calls this module}{3}{chapter.1}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{index:who-calls-this-module}{{1}{3}{Who calls this module}{chapter.1}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {2}Messages}{5}{chapter.2}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{index:messages}{{2}{5}{Messages}{chapter.2}{}} +\@writefile{toc}{\contentsline {chapter}{\numberline {3}Errors}{7}{chapter.3}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{index:errors}{{3}{7}{Errors}{chapter.3}{}} +\gdef \@abspage@last{11} diff --git a/build/latex/secure-messaging.idx b/build/latex/secure-messaging.idx new file mode 100644 index 0000000..e69de29 diff --git a/build/latex/secure-messaging.log b/build/latex/secure-messaging.log new file mode 100644 index 0000000..e24e0ae --- /dev/null +++ b/build/latex/secure-messaging.log @@ -0,0 +1,927 @@ +This is pdfTeX, Version 3.141592653-2.6-1.40.29 (TeX Live 2026) (preloaded format=pdflatex 2026.8.11) 15 SEP 2026 23:08 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**secure-messaging.tex +(./secure-messaging.tex +LaTeX2e <2026-06-01> +L3 programming layer <2026-07-20> +(./sphinxmanual.cls +Document Class: sphinxmanual 2019/12/01 v2.3.0 Document class (Sphinx manual) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/report.cls +Document Class: report 2025/01/22 v1.4n Standard LaTeX document class +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/size10.clo +File: size10.clo 2025/01/22 v1.4n Standard LaTeX file (size option) +) +\c@part=\count276 +\c@chapter=\count277 +\c@section=\count278 +\c@subsection=\count279 +\c@subsubsection=\count280 +\c@paragraph=\count281 +\c@subparagraph=\count282 +\c@figure=\count283 +\c@table=\count284 +\abovecaptionskip=\skip49 +\belowcaptionskip=\skip50 +\bibindent=\dimen150 +) +LaTeX Info: Redefining \and on input line 35. +) +\sphinxremdimen=\dimen151 + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/inputenc.sty +Package: inputenc 2024/02/08 v1.3d Input encoding file +\inpenc@prehook=\toks17 +\inpenc@posthook=\toks18 +) + defining Unicode char U+00A0 (decimal 160) + defining Unicode char U+2500 (decimal 9472) + defining Unicode char U+2502 (decimal 9474) + defining Unicode char U+2514 (decimal 9492) + defining Unicode char U+251C (decimal 9500) + defining Unicode char U+2572 (decimal 9586) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/cmap/cmap.sty +Package: cmap 2021/02/06 v1.0j CMap support: searchable PDF +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/fontenc.sty +Package: fontenc 2025/07/18 v2.1d Standard LaTeX package +<>) (/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsmath/amsmath +.sty +Package: amsmath 2026/05/19 v2.18d AMS math features +\@mathmargin=\skip51 + +For additional information on amsmath, use the `?' option. +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2024/11/17 v2.01 AMS text + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 generic functions +\@emptytoks=\toks19 +\ex@=\dimen152 +)) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d Bold Symbols +\pmbraise@=\dimen153 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 2022/04/08 v2.04 operator names +) +\inf@bad=\count285 +LaTeX Info: Redefining \frac on input line 233. +\uproot@=\count286 +\leftroot@=\count287 +LaTeX Info: Redefining \overline on input line 398. +LaTeX Info: Redefining \colon on input line 409. +\classnum@=\count288 +\DOTSCASE@=\count289 +LaTeX Info: Redefining \ldots on input line 495. +LaTeX Info: Redefining \dots on input line 498. +LaTeX Info: Redefining \cdots on input line 619. +\Mathstrutbox@=\box53 +\strutbox@=\box54 +LaTeX Info: Redefining \big on input line 721. +LaTeX Info: Redefining \Big on input line 722. +LaTeX Info: Redefining \bigg on input line 723. +LaTeX Info: Redefining \Bigg on input line 724. +\big@size=\dimen154 +LaTeX Font Info: Redeclaring font encoding OML on input line 742. +LaTeX Font Info: Redeclaring font encoding OMS on input line 743. +\macc@depth=\count290 +LaTeX Info: Redefining \bmod on input line 904. +LaTeX Info: Redefining \pmod on input line 909. +LaTeX Info: Redefining \smash on input line 939. +LaTeX Info: Redefining \relbar on input line 969. +LaTeX Info: Redefining \Relbar on input line 970. +\c@MaxMatrixCols=\count291 +\dotsspace@=\muskip17 +\c@parentequation=\count292 +\dspbrk@lvl=\count293 +\tag@help=\toks20 +\row@=\count294 +\column@=\count295 +\maxfields@=\count296 +\andhelp@=\toks21 +\eqnshift@=\dimen155 +\alignsep@=\dimen156 +\tagshift@=\dimen157 +\tagwidth@=\dimen158 +\totwidth@=\dimen159 +\lineht@=\dimen160 +\@envbody=\toks22 +\multlinegap=\skip52 +\multlinetaggap=\skip53 +\mathdisplay@stack=\toks23 +LaTeX Info: Redefining \[ on input line 2965. +LaTeX Info: Redefining \] on input line 2966. +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsfonts/amssymb.sty +Package: amssymb 2013/01/14 v3.01 AMS font symbols + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsfonts/amsfonts.sty +Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support +\symAMSa=\mathgroup4 +\symAMSb=\mathgroup5 +LaTeX Font Info: Redeclaring math symbol \hbar on input line 98. +LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' +(Font) U/euf/m/n --> U/euf/b/n on input line 106. +)) +(/Users/marchon/Library/texmf/tex/generic/babel/babel.sty +Package: babel 2026/08/21 v26.11 The multilingual framework for LuaLaTeX, pdfLa +TeX and XeLaTeX +\babel@savecnt=\count297 +LaTeX Encoding Info: Redeclaring text command \ij (encoding OT1) on input li +ne 2105. +LaTeX Encoding Info: Redeclaring text command \IJ (encoding OT1) on input li +ne 2107. +LaTeX Encoding Info: Redeclaring text command \ij (encoding T1) on input lin +e 2109. +LaTeX Encoding Info: Redeclaring text command \IJ (encoding T1) on input lin +e 2110. +LaTeX Encoding Info: Ignoring declaration for text command \ij (encoding ?) +on input line 2111. +LaTeX Encoding Info: Ignoring declaration for text command \IJ (encoding ?) +on input line 2113. +LaTeX Encoding Info: Ignoring declaration for text command \SS (encoding ?) +on input line 2138. +\U@D=\dimen161 +\l@unhyphenated=\language23 + +(/Users/marchon/Library/texmf/tex/generic/babel/txtbabel.def) +\bbl@readstream=\read2 +\bbl@dirlevel=\count298 + +(/Users/marchon/Library/texmf/tex/generic/babel/locale/en/babel-english.tex) +Package babel Info: Importing font and identification data for 'english' +(babel) from babel-en.ini. Reported on input line 4460. + +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/babel-english/english.ldf +Language: english 2017/06/06 v3.3r English support from the babel system +Package babel Info: Hyphen rules for 'canadian' set to \l@english +(babel) (\language0). Reported on input line 102. +Package babel Info: Hyphen rules for 'australian' set to \l@ukenglish +(babel) (\language7). Reported on input line 105. +Package babel Info: Hyphen rules for 'newzealand' set to \l@ukenglish +(babel) (\language7). Reported on input line 108. +)) (/Users/marchon/Library/texmf/tex/latex/tex-gyre/tgtermes.sty +Package: tgtermes 2009/09/27 v1.2 TeX Gyre Termes as default roman family + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/kvoptions/kvoptions.sty +Package: kvoptions 2022-06-15 v3.15 Key value format for package options (HO) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 2026-05-17 v1.15 key=value parser (DPC) +\KV@toks@=\toks24 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/ltxcmds/ltxcmds.sty +Package: ltxcmds 2023-12-04 v1.26 LaTeX kernel commands for general use (HO) +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/kvsetkeys/kvsetkeys.sty +Package: kvsetkeys 2022-10-05 v1.19 Key value parser (HO) +))) +(/Users/marchon/Library/texmf/tex/latex/tex-gyre/tgheros.sty +Package: tgheros 2009/09/27 v1.2 TeX Gyre Heros as default sans serif family +) +(/Users/marchon/Library/texmf/tex/latex/fncychap/fncychap.sty +Package: fncychap 2007/07/30 v1.34 LaTeX package (Revised chapters) +\RW=\skip54 +\mylen=\skip55 +\myhi=\skip56 +\px=\skip57 +\py=\skip58 +\pyy=\skip59 +\pxx=\skip60 +\c@AlphaCnt=\count299 +\c@AlphaDecCnt=\count300 +) (./sphinx.sty +Package: sphinx 2025/12/26 v9.1.0 Sphinx LaTeX package (sphinx-doc) + +(/Users/marchon/Library/texmf/tex/latex/xcolor/xcolor.sty +Package: xcolor 2024/09/29 v3.02 LaTeX color extensions (UK) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics-cfg/color.cfg +File: color.cfg 2016/01/02 v1.6 sample color configuration +) +Package xcolor Info: Driver file: pdftex.def on input line 274. + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics-def/pdftex.def +File: pdftex.def 2025/09/29 v1.2d Graphics/color driver for pdftex +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics/mathcolor.ltx) +Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1349. +Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1353. +Package xcolor Info: Model `RGB' extended on input line 1365. +Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1367. +Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1368. +Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1369. +Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1370. +Package xcolor Info: Model `Gray' substituted by `gray' on input line 1371. +Package xcolor Info: Model `wave' substituted by `hsb' on input line 1372. +) +(./sphinxoptionshyperref.sty +Package: sphinxoptionshyperref 2021/01/27 hyperref +) (./sphinxoptionsgeometry.sty +Package: sphinxoptionsgeometry 2021/01/27 geometry +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/textcomp.sty +Package: textcomp 2024/04/24 v2.1b Standard LaTeX package +) +(/Users/marchon/Library/texmf/tex/latex/float/float.sty +Package: float 2001/11/08 v1.3d Float enhancements (AL) +\c@float@type=\count301 +\float@exts=\toks25 +\float@box=\box55 +\@float@everytoks=\toks26 +\@floatcapt=\box56 +) +(/Users/marchon/Library/texmf/tex/latex/wrapfig/wrapfig.sty +\wrapoverhang=\dimen162 +\WF@size=\dimen163 +\c@WF@wrappedlines=\count302 +\WF@box=\box57 +\WF@everypar=\toks27 +Package: wrapfig 2003/01/31 v 3.6 +) +(/Users/marchon/Library/texmf/tex/latex/capt-of/capt-of.sty +Package: capt-of 2009/12/29 v0.2 standard captions outside of floats +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/tools/multicol.sty +Package: multicol 2025/10/21 v2.0b multicolumn formatting (FMi) +\c@tracingmulticols=\count303 +\mult@box=\box58 +\multicol@leftmargin=\dimen164 +\c@unbalance=\count304 +\c@collectmore=\count305 +\doublecol@number=\count306 +\multicoltolerance=\count307 +\multicolpretolerance=\count308 +\full@width=\dimen165 +\page@free=\dimen166 +\premulticols=\dimen167 +\postmulticols=\dimen168 +\multicolsep=\skip61 +\multicolbaselineskip=\skip62 +\partial@page=\box59 +\last@line=\box60 +\mc@boxedresult=\box61 +\maxbalancingoverflow=\dimen169 +\mult@rightbox=\box62 +\mult@grightbox=\box63 +\mult@firstbox=\box64 +\mult@gfirstbox=\box65 +\@tempa=\box66 +\@tempa=\box67 +\@tempa=\box68 +\@tempa=\box69 +\@tempa=\box70 +\@tempa=\box71 +\@tempa=\box72 +\@tempa=\box73 +\@tempa=\box74 +\@tempa=\box75 +\@tempa=\box76 +\@tempa=\box77 +\@tempa=\box78 +\@tempa=\box79 +\@tempa=\box80 +\@tempa=\box81 +\@tempa=\box82 +\@tempa=\box83 +\@tempa=\box84 +\@tempa=\box85 +\@tempa=\box86 +\@tempa=\box87 +\@tempa=\box88 +\@tempa=\box89 +\@tempa=\box90 +\@tempa=\box91 +\@tempa=\box92 +\@tempa=\box93 +\@tempa=\box94 +\@tempa=\box95 +\@tempa=\box96 +\@tempa=\box97 +\@tempa=\box98 +\@tempa=\box99 +\@tempa=\box100 +\@tempa=\box101 +\c@minrows=\count309 +\c@columnbadness=\count310 +\c@finalcolumnbadness=\count311 +\last@try=\dimen170 +\multicolovershoot=\dimen171 +\multicolundershoot=\dimen172 +\mult@nat@firstbox=\box102 +\colbreak@box=\box103 +\mc@col@check@num=\count312 +\g__mc_curr_col_int=\count313 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 2026-05-17 v1.2e Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2026-05-17 v1.4h Standard LaTeX Graphics (DPC,SPQR) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 2023/12/02 v1.11 sin cos tan (DPC) +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration +) +Package graphics Info: Driver file: pdftex.def on input line 106. +) +\Gin@req@height=\dimen173 +\Gin@req@width=\dimen174 +) (./sphinxlatexgraphics.sty +Package: sphinxlatexgraphics 2024/08/13 v8.1.0 graphics +\spx@image@maxheight=\dimen175 +\spx@image@box=\box104 +) (./sphinxpackageboxes.sty +Package: sphinxpackageboxes 2024/07/01 v7.4.0 advanced colored boxes + + +Package sphinx Warning: The package pict2e is required for rounded boxes. +(sphinx) It does not seem to be available on your system. +(sphinx) Options for setting radii will be ignored. + + +Package sphinx Warning: The package ellipse is required for elliptical corners. + +(sphinx) It does not seem to be available on your system. +(sphinx) All non-straight corners will use circle arcs.. + +\spx@tempboxa=\box105 +\spx@tempboxb=\box106 +\spx@boxes@border@top=\dimen176 +\spx@boxes@border@right=\dimen177 +\spx@boxes@border@bottom=\dimen178 +\spx@boxes@border@left=\dimen179 +\spx@boxes@padding@top=\dimen180 +\spx@boxes@padding@right=\dimen181 +\spx@boxes@padding@bottom=\dimen182 +\spx@boxes@padding@left=\dimen183 +\spx@boxes@shadow@xoffset=\dimen184 +\spx@boxes@shadow@yoffset=\dimen185 +\spx@boxes@radius@topleft@x=\dimen186 +\spx@boxes@radius@topright@x=\dimen187 +\spx@boxes@radius@bottomright@x=\dimen188 +\spx@boxes@radius@bottomleft@x=\dimen189 +\spx@boxes@radius@topleft@y=\dimen190 +\spx@boxes@radius@topright@y=\dimen191 +\spx@boxes@radius@bottomright@y=\dimen192 +\spx@boxes@radius@bottomleft@y=\dimen193 +) (./sphinxlatexadmonitions.sty +Package: sphinxlatexadmonitions 2025/10/24 v9.0.0 admonitions + +(/Users/marchon/Library/texmf/tex/latex/framed/framed.sty +Package: framed 2011/10/22 v 0.96: framed or shaded text with page breaks +\OuterFrameSep=\skip63 +\fb@frw=\dimen194 +\fb@frh=\dimen195 +\FrameRule=\dimen196 +\FrameSep=\dimen197 +) +(/Users/marchon/Library/texmf/tex/latex/needspace/needspace.sty +Package: needspace 2025/03/13 v1.3e reserve vertical space +) +(./sphinxpackagefootnote.sty +Package: sphinxpackagefootnote 2025/11/15 v9.0.0 Sphinx custom footnotehyper pa +ckage (Sphinx team) +\FNH@notes=\box107 +\FNH@toks=\toks28 +\FNH@width=\dimen198 +\c@sphinxfootnotemark=\count314 +) +\spx@notice@border=\dimen199 +\c@sphinxtodo=\count315 +) (./sphinxlatexliterals.sty +Package: sphinxlatexliterals 2025/12/26 v9.1.0 code-blocks and parsed literals + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/fancyvrb/fancyvrb.sty +Package: fancyvrb 2026/04/16 4.6a verbatim text (tvz,hv) +\FV@CodeLineNo=\count316 +\FV@InFile=\read3 +\FV@TabBox=\box108 +\c@FancyVerbLine=\count317 +\FV@StepNumber=\count318 +\FV@OutFile=\write3 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/alltt.sty +Package: alltt 2024/07/07 v2.0g defines alltt environment +) +(/Users/marchon/Library/texmf/tex/latex/upquote/upquote.sty +Package: upquote 2012/04/19 v1.3 upright-quote and grave-accent glyphs in verba +tim +) +\sphinxcontinuationbox=\box109 +\sphinxvisiblespacebox=\box110 +\sphinxVerbatim@TitleBox=\box111 +\sphinxVerbatim@ContentsBox=\box112 +) +(./sphinxlatexshadowbox.sty +Package: sphinxlatexshadowbox 2024/07/28 v8.1.0 sphinxShadowBox +) (./sphinxlatexcontainers.sty +Package: sphinxlatexcontainers 2021/05/03 containers +) +(./sphinxhighlight.sty +Package: sphinxhighlight 2022/06/30 stylesheet for highlighting with pygments +) (./sphinxlatextables.sty +Package: sphinxlatextables 2025/12/30 v9.1.0 tables + +(/Users/marchon/Library/texmf/tex/latex/tabulary/tabulary.sty +Package: tabulary 2024/06/04 v0.11 tabulary package (DPC) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/tools/array.sty +Package: array 2026/02/24 v2.7b Tabular extension package (FMi) +\col@sep=\dimen256 +\ar@mcellbox=\box113 +\extrarowheight=\dimen257 +\NC@list=\toks29 +\extratabsurround=\skip64 +\backup@length=\skip65 +\ar@cellbox=\box114 +) +\TY@count=\count319 +\TY@linewidth=\dimen258 +\tymin=\dimen259 +\tymax=\dimen260 +\TY@tablewidth=\dimen261 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/tools/longtable.sty +Package: longtable 2026-01-28 v4.27 Multi-page Table package (DPC) +\LTleft=\skip66 +\LTright=\skip67 +\LTpre=\skip68 +\LTpost=\skip69 +\LTchunksize=\count320 +\LTcapwidth=\dimen262 +\LT@head=\box115 +\LT@firsthead=\box116 +\LT@foot=\box117 +\LT@lastfoot=\box118 +\LT@gbox=\box119 +\LT@cols=\count321 +\LT@rows=\count322 +\c@LT@tables=\count323 +\c@LT@chunks=\count324 +\LT@p@ftn=\toks30 +) +(/Users/marchon/Library/texmf/tex/latex/varwidth/varwidth.sty +Package: varwidth 2009/03/30 ver 0.92; Variable-width minipages +\@vwid@box=\box120 +\sift@deathcycles=\count325 +\@vwid@loff=\dimen263 +\@vwid@roff=\dimen264 +) +==> First Aid for varwidth.sty applied! +\sphinx@TY@tablewidth=\dimen265 +(/Users/marchon/Library/texmf/tex/latex/colortbl/colortbl.sty +Package: colortbl 2026/05/01 v1.0l Color table columns (DPC) + +new hooks used!! +\minrowclearance=\skip70 +\rownum=\count326 +) (/Users/marchon/Library/texmf/tex/latex/booktabs/booktabs.sty +Package: booktabs 2020/01/12 v1.61803398 Publication quality tables +\heavyrulewidth=\dimen266 +\lightrulewidth=\dimen267 +\cmidrulewidth=\dimen268 +\belowrulesep=\dimen269 +\belowbottomsep=\dimen270 +\aboverulesep=\dimen271 +\abovetopsep=\dimen272 +\cmidrulesep=\dimen273 +\cmidrulekern=\dimen274 +\defaultaddspace=\dimen275 +\@cmidla=\count327 +\@cmidlb=\count328 +\@aboverulesep=\dimen276 +\@belowrulesep=\dimen277 +\@thisruleclass=\count329 +\@lastruleclass=\count330 +\@thisrulewidth=\dimen278 +)) +(./sphinxlatexnumfig.sty +Package: sphinxlatexnumfig 2024/07/31 v8.1.0 numbering +) (./sphinxlatexlists.sty +Package: sphinxlatexlists 2021/12/20 lists +\spx@lineitemlabel=\toks31 +) +\c@sphinxscope=\count331 + (./sphinxlatexindbibtoc.sty +Package: sphinxlatexindbibtoc 2021/01/27 index, bib., toc + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/base/makeidx.sty +Package: makeidx 2021/10/04 v1.0m Standard LaTeX package +)) +(./sphinxlatexstylepage.sty +Package: sphinxlatexstylepage 2021/01/27 page styling + +(/Users/marchon/Library/texmf/tex/latex/parskip/parskip.sty +Package: parskip 2021-03-14 v2.0h non-zero parskip adjustments + +(/Users/marchon/Library/texmf/tex/latex/etoolbox/etoolbox.sty +Package: etoolbox 2025/10/02 v2.5m e-TeX tools for LaTeX (JAW) +\etb@tempcnta=\count332 +)) +(/Users/marchon/Library/texmf/tex/latex/fancyhdr/fancyhdr.sty +Package: fancyhdr 2025/02/07 v5.2 Extensive control of page headers and footers + +\f@nch@headwidth=\skip71 +\f@nch@offset@elh=\skip72 +\f@nch@offset@erh=\skip73 +\f@nch@offset@olh=\skip74 +\f@nch@offset@orh=\skip75 +\f@nch@offset@elf=\skip76 +\f@nch@offset@erf=\skip77 +\f@nch@offset@olf=\skip78 +\f@nch@offset@orf=\skip79 +\f@nch@height=\skip80 +\f@nch@footalignment=\skip81 +\f@nch@widthL=\skip82 +\f@nch@widthC=\skip83 +\f@nch@widthR=\skip84 +\@temptokenb=\toks32 +)) +(./sphinxlatexstyleheadings.sty +Package: sphinxlatexstyleheadings 2023/02/11 headings + +(/Users/marchon/Library/texmf/tex/latex/titlesec/titlesec.sty +Package: titlesec 2025/01/04 v2.17 Sectioning titles +\ttl@box=\box121 +\beforetitleunit=\skip85 +\aftertitleunit=\skip86 +\ttl@plus=\dimen279 +\ttl@minus=\dimen280 +\ttl@toksa=\toks33 +\titlewidth=\dimen281 +\titlewidthlast=\dimen282 +\titlewidthfirst=\dimen283 +)) +(./sphinxlatexstyletext.sty +Package: sphinxlatexstyletext 2025/05/24 v9.0.0 text styling +) (./sphinxlatexobjects.sty +Package: sphinxlatexobjects 2025/06/06 documentation environments +\sphinxsignaturesep=\skip87 +\sphinxsignaturelistskip=\skip88 +\py@argswidth=\skip89 +\lineblockindentation=\skip90 +\DUlineblockindent=\skip91 +) +\sphinxvwdimen=\dimen284 +\sphinxvhdimen=\dimen285 +\sphinxvmindimen=\dimen286 +\sphinxvmaxdimen=\dimen287 +\sphinxQdimen=\dimen288 +) +(/Users/marchon/Library/texmf/tex/latex/geometry/geometry.sty +Package: geometry 2026/03/07 v6.0 Page Geometry + +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/iftex/ifvtex.sty +Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead. + +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/iftex/iftex.sty +Package: iftex 2024/12/12 v1.0g TeX engine tests +)) +\Gm@cnth=\count333 +\Gm@cntv=\count334 +\c@Gm@tempcnt=\count335 +\Gm@bindingoffset=\dimen289 +\Gm@wd@mp=\dimen290 +\Gm@odd@mp=\dimen291 +\Gm@even@mp=\dimen292 +\Gm@layoutwidth=\dimen293 +\Gm@layoutheight=\dimen294 +\Gm@layouthoffset=\dimen295 +\Gm@layoutvoffset=\dimen296 +\Gm@dimlist=\toks34 +) +(/Users/marchon/Library/texmf/tex/latex/hyperref/hyperref.sty +Package: hyperref 2026-06-17 v7.01r Hypertext links for LaTeX + +(/Users/marchon/Library/texmf/tex/generic/kvdefinekeys/kvdefinekeys.sty +Package: kvdefinekeys 2019-12-19 v1.6 Define keys (HO) +) +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/pdfescape/pdfescape.sty +Package: pdfescape 2019/12/09 v1.15 Implements pdfTeX's escape features (HO) + +(/Users/marchon/Library/texmf/tex/generic/pdftexcmds/pdftexcmds.sty +Package: pdftexcmds 2020-06-27 v0.33 Utility functions of pdfTeX for LuaTeX (HO +) + +(/Users/marchon/Library/texmf/tex/generic/infwarerr/infwarerr.sty +Package: infwarerr 2019/12/03 v1.5 Providing info/warning/error messages (HO) +) +Package pdftexcmds Info: \pdf@primitive is available. +Package pdftexcmds Info: \pdf@ifprimitive is available. +Package pdftexcmds Info: \pdfdraftmode found. +)) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/hycolor/hycolor.sty +Package: hycolor 2020-01-27 v1.10 Color options for hyperref/bookmark (HO) +) +(/Users/marchon/Library/texmf/tex/latex/hyperref/nameref.sty +Package: nameref 2026-01-29 v2.58 Cross-referencing by name of section + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/refcount/refcount.sty +Package: refcount 2019/12/15 v3.6 Data extraction from label references (HO) +) +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/gettitlestring/gettitlestr +ing.sty +Package: gettitlestring 2019/12/15 v1.6 Cleanup title references (HO) +) +\c@section@level=\count336 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/stringenc/stringenc.sty +Package: stringenc 2019/11/29 v1.12 Convert strings between diff. encodings (HO +) +) +\@linkdim=\dimen297 +\Hy@linkcounter=\count337 +\Hy@pagecounter=\count338 + +(/Users/marchon/Library/texmf/tex/latex/hyperref/pd1enc.def +File: pd1enc.def 2026-06-17 v7.01r Hyperref: PDFDocEncoding definition (HO) +Now handling font encoding PD1 ... +... no UTF-8 mapping file for font encoding PD1 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/intcalc/intcalc.sty +Package: intcalc 2019/12/15 v1.3 Expandable calculations with integers (HO) +) +\Hy@SavedSpaceFactor=\count339 + +(/Users/marchon/Library/texmf/tex/latex/hyperref/puenc.def +File: puenc.def 2026-06-17 v7.01r Hyperref: PDF Unicode definition (HO) +Now handling font encoding PU ... +... no UTF-8 mapping file for font encoding PU +) +Package hyperref Info: Option `unicode' set `true' on input line 4070. +Package hyperref Info: Option `colorlinks' set `true' on input line 4070. +Package hyperref Info: Option `breaklinks' set `true' on input line 4070. +Package hyperref Info: Hyper figures OFF on input line 4199. +Package hyperref Info: Link nesting OFF on input line 4204. +Package hyperref Info: Hyper index ON on input line 4207. +Package hyperref Info: Plain pages OFF on input line 4214. +Package hyperref Info: Backreferencing OFF on input line 4219. +Package hyperref Info: Implicit mode ON; LaTeX internals redefined. +Package hyperref Info: Bookmarks ON on input line 4466. +\c@Hy@tempcnt=\count340 + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/url/url.sty +\Urlmuskip=\muskip18 +Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc. +) +LaTeX Info: Redefining \url on input line 4805. +\XeTeXLinkMargin=\dimen298 + +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/bitset/bitset.sty +Package: bitset 2019/12/09 v1.3 Handle bit-vector datatype (HO) + +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/bigintcalc/bigintcalc.sty +Package: bigintcalc 2019/12/15 v1.5 Expandable calculations on big integers (HO +) +)) +\Fld@menulength=\count341 +\Field@Width=\dimen299 +\Fld@charsize=\dimen300 +Package hyperref Info: Hyper figures OFF on input line 6091. +Package hyperref Info: Link nesting OFF on input line 6096. +Package hyperref Info: Hyper index ON on input line 6099. +Package hyperref Info: backreferencing OFF on input line 6106. +Package hyperref Info: Link coloring ON on input line 6109. +Package hyperref Info: Link coloring with OCG OFF on input line 6116. +Package hyperref Info: PDF/A mode OFF on input line 6121. +\Hy@abspage=\count342 +\c@Item=\count343 +\c@Hfootnote=\count344 +) +Package hyperref Info: Driver (autodetected): hpdftex. + (/Users/marchon/Library/texmf/tex/latex/hyperref/hpdftex.def +File: hpdftex.def 2026-06-17 v7.01r Hyperref driver for pdfTeX +\Fld@listcount=\count345 +\c@bookmark@seq@number=\count346 + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/rerunfilecheck/rerunfilechec +k.sty +Package: rerunfilecheck 2025-06-21 v1.11 Rerun checks for auxiliary files (HO) + +(/usr/local/texlive/2026basic/texmf-dist/tex/generic/uniquecounter/uniquecounte +r.sty +Package: uniquecounter 2019/12/15 v1.4 Provide unlimited unique counter (HO) +) +Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2 +84. +) +\Hy@SectionHShift=\skip92 +) (/usr/local/texlive/2026basic/texmf-dist/tex/latex/hypcap/hypcap.sty +Package: hypcap 2024-07-26 v1.13 Adjusting the anchors of captions (HO) + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/letltxmacro/letltxmacro.sty +Package: letltxmacro 2019/12/03 v1.6 Let assignment for LaTeX macros (HO) +)) (./sphinxmessages.sty +Package: sphinxmessages 2019/01/04 v2.0 Localized LaTeX macros (Sphinx team) +) +\@indexfile=\write4 +\openout4 = `secure-messaging.idx'. + + +Writing index file secure-messaging.idx +LaTeX Font Info: Trying to load font information for T1+qtm on input line 73 +. +(/Users/marchon/Library/texmf/tex/latex/tex-gyre/t1qtm.fd +File: t1qtm.fd 2009/09/25 v1.2 font definition file for T1/qtm +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/l3backend/l3backend-pdftex.d +ef +File: l3backend-pdftex.def 2026-07-20 L3 backend support: PDF output (pdfTeX) +\l__color_backend_stack_int=\count347 +) +No file secure-messaging.aux. +\openout1 = `secure-messaging.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +LaTeX Font Info: Checking defaults for PU/pdf/m/n on input line 73. +LaTeX Font Info: ... okay on input line 73. +(/usr/local/texlive/2026basic/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count348 +\scratchdimen=\dimen301 +\scratchbox=\box122 +\nofMPsegments=\count349 +\nofMParguments=\count350 +\everyMPshowfont=\toks35 +\MPscratchCnt=\count351 +\MPscratchDim=\dimen302 +\MPnumerator=\count352 +\makeMPintoPDFobject=\count353 +\everyMPtoPDFconversion=\toks36 +) +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.s +ty +Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf +Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 +85. + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +\c@literalblock=\count354 + +*geometry* driver: auto-detecting +*geometry* detected driver: pdftex +*geometry* verbose mode - [ preamble ] result: +* driver: pdftex +* paper: letterpaper +* layout: +* layoutoffset:(h,v)=(0.0pt,0.0pt) +* modes: twoside +* h-part:(L,W,R)=(72.26999pt, 469.75502pt, 72.26999pt) +* v-part:(T,H,B)=(72.26999pt, 650.43001pt, 72.26999pt) +* \paperwidth=614.295pt +* \paperheight=794.96999pt +* \textwidth=469.75502pt +* \textheight=650.43001pt +* \oddsidemargin=0.0pt +* \evensidemargin=0.0pt +* \topmargin=-37.0pt +* \headheight=12.0pt +* \headsep=25.0pt +* \topskip=10.0pt +* \footskip=30.0pt +* \marginparwidth=36.135pt +* \marginparsep=11.0pt +* \columnsep=10.0pt +* \skip\footins=9.0pt plus 4.0pt minus 2.0pt +* \hoffset=0.0pt +* \voffset=0.0pt +* \mag=1000 +* \@twocolumnfalse +* \@twosidetrue +* \@mparswitchtrue +* \@reversemarginfalse +* (1in=72.27pt=25.4mm, 1cm=28.453pt) + +Package hyperref Info: Link coloring ON on input line 73. +\@outlinefile=\write5 +\openout5 = `secure-messaging.out'. + +Package babel Info: Main language set to 'english'. +Package hyperref Info: Option `pageanchor' set `false' on input line 81. +LaTeX Font Info: Trying to load font information for T1+qhv on input line 81 +. +(/Users/marchon/Library/texmf/tex/latex/tex-gyre/t1qhv.fd +File: t1qhv.fd 2009/09/25 v1.2 font definition file for T1/qhv +) [1 + +{/Users/marchon/Library/texlive/2026basic/texmf-var/fonts/map/pdftex/updmap/pdf +tex.map}{/Users/marchon/Library/texmf/fonts/enc/dvips/tex-gyre/q-ec.enc}] [2 + + +] +No file secure-messaging.toc. +\tf@toc=\write6 +\openout6 = `secure-messaging.toc'. + +[1 + +] [2 + +] +LaTeX Font Info: Trying to load font information for TS1+qtm on input line 9 +5. + (/Users/marchon/Library/texmf/tex/latex/tex-gyre/ts1qtm.fd +File: ts1qtm.fd 2009/09/25 v1.2 font definition file for TS1/qtm +) +LaTeX Font Info: Trying to load font information for T1+txtt on input line 9 +7. + +(/Users/marchon/Library/texmf/tex/latex/txfonts/t1txtt.fd +File: t1txtt.fd 2000/12/15 v3.1 +)<> +LaTeX Font Info: Trying to load font information for U+msa on input line 1. + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsfonts/umsa.fd +File: umsa.fd 2013/01/14 v3.01 AMS symbols A +) +LaTeX Font Info: Trying to load font information for U+msb on input line 1. + +(/usr/local/texlive/2026basic/texmf-dist/tex/latex/amsfonts/umsb.fd +File: umsb.fd 2013/01/14 v3.01 AMS symbols B +) [1{/Users/marchon/Library/texmf/fonts/enc/dvips/tex-gyre/q-ts1.enc}] [2 + +] +Chapter 1. +[3] [4 + +] +Chapter 2. +[5] [6 + +] +Chapter 3. +No file secure-messaging.ind. + +Package sphinx Warning: The package pict2e is required for rounded boxes. +(sphinx) As it does not seem to be available on your system, +(sphinx) options setting radii have all been ignored. + + +Package sphinx Warning: The package ellipse is required for elliptical corners. + +(sphinx) As it does not seem to be available on your system, +(sphinx) all non-straight corners have used circle arcs.. + +[7] (./secure-messaging.aux) + *********** +LaTeX2e <2026-06-01> +L3 programming layer <2026-07-20> + *********** + + +LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. + + +Package rerunfilecheck Warning: File `secure-messaging.out' has changed. +(rerunfilecheck) Rerun to get outlines right +(rerunfilecheck) or use package `bookmark'. + +Package rerunfilecheck Info: Checksums for `secure-messaging.out': +(rerunfilecheck) Before: +(rerunfilecheck) After: 68FEE9D73189B836406FEDA2D622DC76;313. + ) +Here is how much of TeX's memory you used: + 17010 strings out of 468640 + 295675 string characters out of 5445039 + 707636 words of memory out of 5000000 + 45734 multiletter control sequences out of 15000+600000 + 666201 words of font info for 63 fonts, out of 8000000 for 9000 + 320 hyphenation exceptions out of 8191 + 74i,11n,82p,1205b,524s stack positions out of 10000i,1000n,20000p,200000b,200000s + +Output written on secure-messaging.pdf (11 pages, 99138 bytes). +PDF statistics: + 91 PDF objects out of 1000 (max. 8388607) + 68 compressed objects within 1 object stream + 15 named destinations out of 1000 (max. 500000) + 9 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/build/latex/secure-messaging.out b/build/latex/secure-messaging.out new file mode 100644 index 0000000..ed7f042 --- /dev/null +++ b/build/latex/secure-messaging.out @@ -0,0 +1,3 @@ +\BOOKMARK [0][-]{chapter.1}{\376\377\000W\000h\000o\000\040\000c\000a\000l\000l\000s\000\040\000t\000h\000i\000s\000\040\000m\000o\000d\000u\000l\000e}{}% 1 +\BOOKMARK [0][-]{chapter.2}{\376\377\000M\000e\000s\000s\000a\000g\000e\000s}{}% 2 +\BOOKMARK [0][-]{chapter.3}{\376\377\000E\000r\000r\000o\000r\000s}{}% 3 diff --git a/build/latex/secure-messaging.pdf b/build/latex/secure-messaging.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7b5af7fc0a5ae99645217b2fabc435901115c987 GIT binary patch literal 99138 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 +% macros which are (now) used nowhere, only @top, @right, @bottom, @left. +\def\spx@tempa#1{% #1 = macro prefix + \expandafter\spx@tempb + \csname #1border@top\expandafter\endcsname + \csname #1border@right\expandafter\endcsname + \csname #1border@bottom\expandafter\endcsname + \csname #1border@left\expandafter\endcsname + \csname if#1border@open\expandafter\endcsname + \csname #1border@opentrue\expandafter\endcsname + \csname #1border@openfalse\endcsname +}% +\def\spx@tempb #1#2#3#4#5#6#7#8#9{% #8 = option prefix + \define@key{sphinx}{#8border-top-width}{\def#1{##1}}% + \define@key{sphinx}{#8border-right-width}{\def#2{##1}}% + \define@key{sphinx}{#8border-bottom-width}{\def#3{##1}}% + \define@key{sphinx}{#8border-left-width}{\def#4{##1}}% + \define@key{sphinx}{#8border-width}{% + % MEMO: not immediately expanded, should this be changed? + \def#1{##1}\let#2#1\let#3#1\let#4#1% + }% + \newif#5% + % 6.2.0 has added support for box-decoration-break also to admonition + % directives, formerly the option setting was ignored for them. + \define@key{sphinx}{#8box-decoration-break}% + {\begingroup\edef\spx@tempa{##1}\expandafter\endgroup + \ifx\spx@tempa\spxstring@clone#7\else#6\fi}% + % 7.4.0 sets the default behaviour to "slice" not only for code-blocks but + % also for admonitions, as the latter now have a background colour each. + #6% + % #8 = option prefix (with underscore), #9 = legacy option name + % keep legacy option names as aliases to new-named options + \expandafter\let\csname KV@sphinx@#9\expandafter\endcsname + \csname KV@sphinx@#8border-width\endcsname + % init border-width (fetches next argument) + \csname KV@sphinx@#8border-width\endcsname +} +% MEMO: from 6.2.0 to 7.4.0 (excluive) \fboxrule was used in the first +% two, and was resolved only at location of use. At 7.4.0, we again +% use 0.4pt rather and not \fboxrule dimen register. +% macro prefix option prefix legacy option init value +\spx@tempa{spx@pre@} {pre_} {verbatimborder} {0.4pt} +\spx@tempa{spx@topic@} {div.topic_} {shadowrule} {0.5pt}% mod. at 7.4.0 +\spx@tempa{spx@contents@} {div.contents_} {shadowrule} {0.5pt}% 8.1.0 +\spx@tempa{spx@sidebar@} {div.sidebar_} {shadowrule} {1pt}% 8.1.0 +% let legacy shadowrule key set all topic/contents/sidebar border +% keys to the common value given by user to shadowrule +\def\KV@sphinx@shadowrule #1{% + \@nameuse{KV@sphinx@div.topic_border-width}{#1}% + \@nameuse{KV@sphinx@div.contents_border-width}{#1}% + \@nameuse{KV@sphinx@div.sidebar_border-width}{#1}% +}% +\spx@tempa{spx@note@} {div.note_} {noteborder} {0.5pt} +\spx@tempa{spx@hint@} {div.hint_} {hintborder} {0.5pt} +\spx@tempa{spx@important@}{div.important_}{importantborder}{0.5pt} +\spx@tempa{spx@tip@} {div.tip_} {tipborder} {0.5pt} +\spx@tempa{spx@seealso@} {div.seealso_} {seealsoborder} {0.5pt}% new at 7.4.0 +\spx@tempa{spx@todo@} {div.todo_} {todoborder} {0.5pt}% new at 7.4.0 +\spx@tempa{spx@warning@} {div.warning_} {warningborder} {1pt} +\spx@tempa{spx@caution@} {div.caution_} {cautionborder} {1pt} +\spx@tempa{spx@attention@}{div.attention_}{attentionborder}{1pt} +\spx@tempa{spx@danger@} {div.danger_} {dangerborder} {1pt} +\spx@tempa{spx@error@} {div.error_} {errorborder} {1.25pt}% mod. at 7.4.0 +% this one new at 6.2.0: (we do not create a "legacy name" for it) +\spx@tempa{spx@box@} {box_} {box_border-width}{0.4pt} +% Reset default box-decoration-break style to "clone" for \sphinxbox, +% but anyhow this is ignored as \sphinxbox produces unbreakable boxes. +\spx@box@border@openfalse + +% Padding keys +% At 7.4.0, \spx@@padding internal macros removed, only @top, @right, +% @bottom, @left are actually needed by sphinxpackageboxes.sty. +\def\spx@tempa#1{% + \expandafter\spx@tempb + \csname #1padding@top\expandafter\endcsname + \csname #1padding@right\expandafter\endcsname + \csname #1padding@bottom\expandafter\endcsname + \csname #1padding@left\endcsname +}% +\def\spx@tempb #1#2#3#4#5#6#7#8#9{% #5 = option prefix + \define@key{sphinx}{#5padding-top}{\def#1{##1}}% + \define@key{sphinx}{#5padding-right}{\def#2{##1}}% + \define@key{sphinx}{#5padding-bottom}{\def#3{##1}}% + \define@key{sphinx}{#5padding-left}{\def#4{##1}}% + \define@key{sphinx}{#5padding}{% + \def#1{##1}\let#2#1\let#3#1\let#4#1% + }% + % initial defaults + \def#1{#6}\def#2{#7}\def#3{#8}\def#4{#9}% +} +% MEMO: prior to 6.2.0 the \fboxsep value (3pt, a priori) was frozen here via +% a \dimen assignment done immediately. From 6.2.0 to 7.4.0 an unfrozen +% \fboxsep was used, and at 7.4.0 it is again explicit 3pt. +% The defaults for admonitions were all modified at 7.4.0. +% For topic/contents and all admonitions the horizontal padding plus borders +% are put inside the text area (i.e. do not go into the margins). +% In order for perfect exact same vertical alignment of contents from all such +% directives, the value of horizontal border-width+padding is kept constant +% (equal to 7.5pt since 7.4.0). +% 8.1.0 styles separately topic, contents, and sidebar. +% #1 macro prefix #6 option prefix top right bottom left +\spx@tempa{spx@pre@} {pre_} {3pt}{3pt}{3pt}{3pt} +\spx@tempa{spx@topic@} {div.topic_} {6pt}{7pt}{6pt}{7pt}% mod. at 8.1.0 +% contents styling inherits at 8.1.0 the former 7.4.0 topic defaults +\spx@tempa{spx@contents@} {div.contents_} {10pt}{7pt}{12pt}{7pt}% 8.1.0 +\spx@tempa{spx@sidebar@} {div.sidebar_} {6pt}{6.5pt}{6pt}{6.5pt}% 8.1.0 +% 7.4.0 drops legacy settings which linked strangely padding with border width +\spx@tempa{spx@note@} {div.note_} {6pt}{7pt}{6pt}{7pt} +\spx@tempa{spx@hint@} {div.hint_} {6pt}{7pt}{6pt}{7pt} +\spx@tempa{spx@important@}{div.important_} {6pt}{7pt}{6pt}{7pt} +\spx@tempa{spx@tip@} {div.tip_} {6pt}{7pt}{6pt}{7pt} +\spx@tempa{spx@seealso@} {div.seealso_} {6pt}{7pt}{6pt}{7pt} +\spx@tempa{spx@todo@} {div.todo_} {6pt}{7pt}{6pt}{7pt} +\spx@tempa{spx@warning@} {div.warning_} {6pt}{6.5pt}{6pt}{6.5pt} +\spx@tempa{spx@caution@} {div.caution_} {6pt}{6.5pt}{6pt}{6.5pt} +\spx@tempa{spx@attention@}{div.attention_} {6pt}{6.5pt}{6pt}{6.5pt} +\spx@tempa{spx@danger@} {div.danger_} {6pt}{6.5pt}{6pt}{6.5pt} +\spx@tempa{spx@error@} {div.error_} {6pt}{6.25pt}{6pt}{6.25pt} +\spx@tempa{spx@box@} {box_} {3pt}{3pt}{3pt}{3pt} +% define legacy verbatimsep key as alias of pre_padding key +\expandafter\let\expandafter\KV@sphinx@verbatimsep\csname KV@sphinx@pre_padding\endcsname +% let legacy shadowsep key set all topic/contents/sidebar padding +% keys to the common value given by user to shadosep +\def\KV@sphinx@shadowsep #1{% + \@nameuse{KV@sphinx@div.topic_padding}{#1}% + \@nameuse{KV@sphinx@div.contents_padding}{#1}% + \@nameuse{KV@sphinx@div.sidebar_padding}{#1}% +}% + +% Corner radii keys +% +% Prior to 6.2.0, the "rounded box" branch obeyed the 4 radii but ignored +% the separate border widths and used only the border-width setting. +% Now, all 4 + 4 parameters are obeyed. +\def\spx@tempa#1{% #1 = macro prefix + \expandafter\spx@tempb + \csname #1radius@topleft\expandafter\endcsname + \csname #1radius@topright\expandafter\endcsname + \csname #1radius@bottomright\expandafter\endcsname + \csname #1radius@bottomleft\endcsname +}% +\def\spx@tempb #1#2#3#4#5#6#7#8#9{% #5 = option prefix + \define@key{sphinx}{#5border-top-left-radius}{\def#1{##1}}% + \define@key{sphinx}{#5border-top-right-radius}{\def#2{##1}}% + \define@key{sphinx}{#5border-bottom-right-radius}{\def#3{##1}}% + \define@key{sphinx}{#5border-bottom-left-radius}{\def#4{##1}}% + \define@key{sphinx}{#5border-radius}{\def#1{##1}\let#2#1\let#3#1\let#4#1}% + \def#1{#6}\def#2{#7}\def#3{#8}\def#4{#9}% +} +% The init value for corner radius in code-blocks was \z@ (i.e. 0pt) prior +% to 6.0.0., then 3pt, then \fboxsep at 6.2.0 as padding was also \fboxsep. +% At 7.4.0: +% - the 3pt is used (which is normal value of \fboxsep). +% - some admonitions use rounded corners as well. +% - topic boxed have only their bottom right corner rounded. +% At 8.1.0 topic, contents and sidebar separately styled. +% macro prefix option prefix tl tr br bl +\spx@tempa{spx@pre@} {pre_} {3pt}{3pt}{3pt}{3pt} +% use four rounded corners (and no shadow) for topic at 8.1.0 +\spx@tempa{spx@topic@} {div.topic_} {8pt}{8pt}{8pt}{8pt} +% contents inherits at 8.1.0 the 7.4.0 former styling of topic +\spx@tempa{spx@contents@} {div.contents_} \z@ \z@ {12pt} \z@ +% make sidebard distinctive as we can't really safely implement +% it with text flowing around it, but rather as a full width block +\spx@tempa{spx@sidebar@} {div.sidebar_} {12pt}\z@ {12pt} \z@ +\spx@tempa{spx@note@} {div.note_} {5pt}{5pt}{5pt}{5pt} +\spx@tempa{spx@hint@} {div.hint_} {5pt}{5pt}{5pt}{5pt} +\spx@tempa{spx@important@}{div.important_} \z@\z@\z@\z@ +\spx@tempa{spx@tip@} {div.tip_} {5pt}{5pt}{5pt}{5pt} +\spx@tempa{spx@seealso@} {div.seealso_} \z@\z@\z@\z@ +\spx@tempa{spx@todo@} {div.todo_} \z@\z@\z@\z@ +\spx@tempa{spx@warning@} {div.warning_} \z@\z@\z@\z@ +\spx@tempa{spx@caution@} {div.caution_} \z@\z@\z@\z@ +\spx@tempa{spx@attention@}{div.attention_} \z@\z@\z@\z@ +\spx@tempa{spx@danger@} {div.danger_} \z@\z@\z@\z@ +\spx@tempa{spx@error@} {div.error_} \z@\z@\z@\z@ +\spx@tempa{spx@box@} {box_} {3pt}{3pt}{3pt}{3pt} + +% Shadow keys +% +% Prior to 6.2.0, an "inset" shadow caused the rendering to ignore +% rounded corners. Starting with 6.2.0, an "inset" shadow is simply +% ignored (not implemented) if any of the corner radii is positive, +% rather than forcing a rectangle+inset shadow output. +\def\spx@tempa#1{% + \expandafter\spx@tempb + \csname if#1withshadow\expandafter\endcsname + \csname if#1insetshadow\endcsname +}% +\def\spx@tempb#1#2{\newif#1\newif#2}% +% macro prefix +\spx@tempa{spx@pre@} +\spx@tempa{spx@topic@} +\spx@tempa{spx@contents@}% 8.1.0 +\spx@tempa{spx@sidebar@}% 8.1.0 +\spx@tempa{spx@note@} +\spx@tempa{spx@hint@} +\spx@tempa{spx@important@} +\spx@tempa{spx@tip@} +\spx@tempa{spx@seealso@}% 7.4.0 +\spx@tempa{spx@todo@}% 7.4.0 +\spx@tempa{spx@warning@} +\spx@tempa{spx@caution@} +\spx@tempa{spx@attention@} +\spx@tempa{spx@danger@} +\spx@tempa{spx@error@} +\spx@tempa{spx@box@} +% +\def\spx@tempa#1{% #1 = macro prefix + \expandafter\spx@tempb + \csname #1withshadowtrue\expandafter\endcsname + \csname #1withshadowfalse\expandafter\endcsname + \csname #1insetshadowtrue\expandafter\endcsname + \csname #1insetshadowfalse\expandafter\endcsname + \csname #1shadow@setter\expandafter\endcsname + \csname #1shadow@xoffset\expandafter\endcsname + \csname #1shadow@yoffset\endcsname +}% +\def\spx@tempb#1#2#3#4#5#6#7#8{% #8 = option prefix + \define@key{sphinx}{#8box-shadow}{#5##1 {} {} \@nnil}% + \def#5##1 ##2 ##3 ##4\@nnil{% + \begingroup\edef\spx@tempa{##1}\expandafter\endgroup + \ifx\spx@tempa\spxstring@none + #2% + % MEMO: at 5.1.0 and up to 6.2.0, an \edef with \number\dimexpr was + % used here. Since 6.2.0, expansion is delayed to time of use as for + % the other dimensions handled above. This is synched with an added + % encapsulation in \dimexpr...\relax by the "setup" from + % sphinxpackageboxes.sty. + \else #1% + \def#6{##1}% + \if\relax\detokenize{##2}\relax\let#7#6\else\def#7{##2}\fi + \if\relax\detokenize{##3}\relax#4\else#3\fi + \fi + }% + #5none {} {} \@nnil % no shadow by default (except for topic, see below) +} +\spx@tempa{spx@pre@} {pre_} +\spx@tempa{spx@topic@} {div.topic_} +\spx@tempa{spx@contents@} {div.contents_} +\spx@tempa{spx@sidebar@} {div.sidebar_} +% This corresponds to the legacy parameters for topic/contents/sidebar, +% but they are now only kept for contents + \spx@contents@shadow@setter 4pt 4pt {} \@nnil +% topic and sidebar default to no shadow +\spx@tempa{spx@note@} {div.note_} +\spx@tempa{spx@hint@} {div.hint_} +\spx@tempa{spx@important@}{div.important_} +\spx@tempa{spx@tip@} {div.tip_} +\spx@tempa{spx@seealso@} {div.seealso_} +\spx@tempa{spx@todo@} {div.todo_} +\spx@tempa{spx@warning@} {div.warning_} +\spx@tempa{spx@caution@} {div.caution_} +\spx@tempa{spx@attention@}{div.attention_} +\spx@tempa{spx@danger@} {div.danger_} +\spx@tempa{spx@error@} {div.error_} +\spx@tempa{spx@box@} {box_} + +% Support for legacy shadowsize (topic/contents/sidebar) +% This definition was broken due to a typo at 5.1.0 and got fixed at 6.1.2 +% MEMO: at 6.2.0 this no longer does \number\dimexpr in an \edef. Reason is to +% keep in sync with div.topic_box-shadow handling of xoffset and yoffset. +\define@key{sphinx}{shadowsize}{% + \def\spx@topic@shadow@xoffset{#1}% + \let\spx@contents@shadow@xoffset\spx@topic@shadow@xoffset + \let\spx@sidebar@shadow@xoffset \spx@topic@shadow@xoffset + \let\spx@topic@shadow@yoffset \spx@topic@shadow@xoffset + \let\spx@contents@shadow@yoffset\spx@topic@shadow@xoffset + \let\spx@sidebar@shadow@yoffset \spx@topic@shadow@xoffset + \ifdim\dimexpr\spx@topic@shadow@xoffset=\z@ + \spx@topic@withshadowfalse + \spx@contents@withshadowfalse + \spx@sidebar@withshadowfalse + \else + \spx@topic@withshadowtrue + \spx@topic@insetshadowfalse + \spx@contents@withshadowtrue + \spx@contents@insetshadowfalse + \spx@sidebar@withshadowtrue + \spx@sidebar@insetshadowfalse + \fi +}% + +% Color keys, TeXextras key, keys for admonition titles with icon +% +% Historical remarks to be removed at some point: +% +% Some problems due to legacy naming scheme which had diverging conventions +% for code-blocks (VerbatimBorderColor, VerbatimColor) and admonitions +% (sphinxwarningBorderColor, sphinxwarningBgColor, etc...) regarding the +% internal names of the used colors. Unfortunately VerbatimColor and for +% example sphinxwarningBgColor are also documented at user level, they are not +% only internally used. +% +% For topic directive, "legacy" (around 2016-2017) had no interface for +% colours, so some internals could be changed with no breakage during 5.x up +% to 6.2.0. For example topic (shadowbox) could be unified with admonitions +% (sphinxheavybox), and the "setup" macros could all be moved into a single +% one in the sphinxpackageboxes.sty file, with only one argument holding the +% directive type. +% +% It was then needed only by sphinxlatexliterals.sty to let its emitted +% \spx@verb@boxes@fcolorbox@setup incorporate some extra adjustment. +% +% 7.4.0 removes usages of booleans relative to usage of a colour for +% background or border which were there to optimize the boxing code from +% sphinxpackageboxes.sty when colours where not needed. These were internal +% macros so their removal should not be considered breaking. +% We keep the infrastructure for "shadowcolor" and "textcolor" because the +% defaults for them remain not to have specific colour. +% +% 7.4.0 adds keys for admonition titles: for background and foreground colors, +% and for icons. +\def\spx@tempa#1{% + \expandafter\spx@tempb + \csname if#1withshadowcolor\expandafter\endcsname + \csname if#1withtextcolor\endcsname +}% +\def\spx@tempb#1#2{\newif#1\newif#2}% +% macro prefix +\spx@tempa{spx@pre@} +\spx@tempa{spx@topic@} +\spx@tempa{spx@contents@} +\spx@tempa{spx@sidebar@} +\spx@tempa{spx@note@} +\spx@tempa{spx@hint@} +\spx@tempa{spx@important@} +\spx@tempa{spx@tip@} +\spx@tempa{spx@seealso@} +\spx@tempa{spx@todo@} +\spx@tempa{spx@warning@} +\spx@tempa{spx@caution@} +\spx@tempa{spx@attention@} +\spx@tempa{spx@danger@} +\spx@tempa{spx@error@} +\spx@tempa{spx@box@} +% +\def\spx@tempa#1{% #1 = macro prefix + \expandafter\spx@tempb + \csname #1withshadowcolortrue\expandafter\endcsname + \csname #1withtextcolortrue\expandafter\endcsname + \csname #1TeXextras\endcsname +} +% 7.4.0 adds options for a title. They have an action only for admonitions, +% seealso and todo directives. +\def\spx@tempb#1#2#3#4#5{% #4 = option prefix, #5 = color name prefix + \define@key{sphinx}{#4border-TeXcolor}% + {\spx@defineorletcolor{#5BorderColor}##1\relax}% + \define@key{sphinx}{#4background-TeXcolor}% + {\spx@defineorletcolor{#5BgColor}##1\relax}% + \define@key{sphinx}{#4title-background-TeXcolor}% + {\spx@defineorletcolor{#5TtlBgColor}##1\relax}% + \define@key{sphinx}{#4title-foreground-TeXcolor}% + {\spx@defineorletcolor{#5TtlFgColor}##1\relax}% + \define@key{sphinx}{#4title-icon}% + {\@namedef{#5TtlIcon}{##1}}% + \define@key{sphinx}{#4box-shadow-TeXcolor}% + {#1\spx@defineorletcolor{#5ShadowColor}##1\relax}% + \define@key{sphinx}{#4TeXcolor}% + {#2\spx@defineorletcolor{#5TextColor}##1\relax}% + \define@key{sphinx}{#4TeXextras}% + {\def#3{##1}}% +} +% macro prefix option prefix color name prefix +\spx@tempa{spx@pre@} {pre_} {Verbatim} + % (memo: internal VerbatimShadowColor was formerly sphinxVerbatimShadowColor) + % internal legacy color name is VerbatimColor not VerbatimBgColor, so redefine: + \define@key{sphinx}{pre_background-TeXcolor}% + {\spx@defineorletcolor{VerbatimColor}#1\relax}% + % Keep legacy option names working + \expandafter\let\expandafter\KV@sphinx@VerbatimBorderColor + \csname KV@sphinx@pre_border-TeXcolor\endcsname + \expandafter\let\expandafter\KV@sphinx@VerbatimColor + \csname KV@sphinx@pre_background-TeXcolor\endcsname +% (6.2.0 modified some internal namings for the colors of topic boxes) +% macro prefix option prefix color name prefix +% There was no legacy interface for topic/contents/sidebar +% 8.1.0 allows separate styling for topic/contents/sidebar +\spx@tempa{spx@topic@} {div.topic_} {sphinxtopic} +\spx@tempa{spx@contents@} {div.contents_} {sphinxcontents} +\spx@tempa{spx@sidebar@} {div.sidebar_} {sphinxsidebar} +\spx@tempa{spx@note@} {div.note_} {sphinxnote} +\spx@tempa{spx@hint@} {div.hint_} {sphinxhint} +\spx@tempa{spx@important@}{div.important_} {sphinximportant} +\spx@tempa{spx@tip@} {div.tip_} {sphinxtip} +\spx@tempa{spx@seealso@} {div.seealso_} {sphinxseealso} +\spx@tempa{spx@todo@} {div.todo_} {sphinxtodo} +\spx@tempa{spx@warning@} {div.warning_} {sphinxwarning} +\spx@tempa{spx@caution@} {div.caution_} {sphinxcaution} +\spx@tempa{spx@attention@}{div.attention_} {sphinxattention} +\spx@tempa{spx@danger@} {div.danger_} {sphinxdanger} +\spx@tempa{spx@error@} {div.error_} {sphinxerror} +\spx@tempa{spx@box@} {box_} {sphinxbox} + % Keep legacy sphinxsetup color options interface for "strong" admonitions + \def\spx@tempa#1#2{% #1 = option prefix, #2 = legacy option prefix + \expandafter\let\csname KV@sphinx@#2BorderColor\expandafter\endcsname + \csname KV@sphinx@#1border-TeXcolor\endcsname + \expandafter\let\csname KV@sphinx@#2BgColor\expandafter\endcsname + \csname KV@sphinx@#1background-TeXcolor\endcsname + } + \spx@tempa{div.warning_} {warning} + \spx@tempa{div.caution_} {caution} + \spx@tempa{div.attention_} {attention} + \spx@tempa{div.danger_} {danger} + \spx@tempa{div.error_} {error} + + % Keep legacy sphinxsetup BorderColor for =note, hint, ... + % Add "legacy" names BgColor (added at 7.4.0) and TextColor + \def\spx@tempa#1#2{% #1 = CSS like option prefix, #2 = legacy option prefix + \expandafter\let\csname KV@sphinx@#2BorderColor\expandafter\endcsname + \csname KV@sphinx@#1border-TeXcolor\endcsname + \expandafter\let\csname KV@sphinx@#2BgColor\expandafter\endcsname + \csname KV@sphinx@#1background-TeXcolor\endcsname + \expandafter\let\csname KV@sphinx@#2TextColor\expandafter\endcsname + \csname KV@sphinx@#1TeXcolor\endcsname + } + \spx@tempa{div.note_} {note} + \spx@tempa{div.hint_} {hint} + \spx@tempa{div.important_} {important} + \spx@tempa{div.tip_} {tip} + + % Add "legacy" hintTeXextras etc... + \def\spx@tempa#1#2{% #1 = CSS like option prefix, #2 = legacy option prefix + \expandafter\let\csname KV@sphinx@#2TeXextras\expandafter\endcsname + \csname KV@sphinx@#1TeXextras\endcsname + } + \spx@tempa{div.note_} {note} + \spx@tempa{div.hint_} {hint} + \spx@tempa{div.important_} {important} + \spx@tempa{div.tip_} {tip} + + % At 7.4.0, let topic/contents boxes acquire background and border colours + % and give the shadow some colour other than black + % 8.1.0 styles separately topic/contents/sidebar + % topic has no shadow but we keep 7.4.0 color in case it gets needed + \setkeys{sphinx}{% + div.topic_border-TeXcolor=sphinx-admonition-bordercolor, + div.topic_background-TeXcolor=sphinx-admonition-bgcolor, + div.topic_box-shadow-TeXcolor={RGB}{108,108,108}, + div.contents_border-TeXcolor=sphinx-admonition-bordercolor, + div.contents_background-TeXcolor=sphinx-admonition-bgcolor, + div.contents_box-shadow-TeXcolor={RGB}{108,108,108}, + div.sidebar_border-TeXcolor=sphinx-admonition-bordercolor, + div.sidebar_background-TeXcolor=sphinx-admonition-bgcolor, + div.sidebar_box-shadow-TeXcolor=sphinx-admonition-bordercolor!80,% #9eacaf + } + + +% 7.4.0 lets all types of admonitions style especially their titlss. +% The Sphinx default colours for admonition titles are copied from PR #12486 +% which modified sphinx13.css (see also earlier #12439) +% The actual code using the colours and icons whose defaults are set here +% is to be found in sphinxlatexadmonitions.sty. +% +% MEMO: unfortunately xcolor does NOT implement HSL but only HSB! +% So the sphinx13.css colours specified via hsl() got converted to RGB here +\definecolor{sphinx-admonition-title-bgcolor}{RGB}{229,229,229} % hsl(0, 0%, 90%); +\definecolor{sphinx-admonition-title-fgcolor}{RGB}{127,127,127} % hsl(0, 0%, 50%); +\definecolor{sphinx-warning-title-bgcolor} {RGB}{248,228,210} % hsl(28.5, 74%, 90%); +\definecolor{sphinx-warning-title-fgcolor} {RGB}{221,122,33} % hsl(28.5, 74%, 50%); +\definecolor{sphinx-note-title-bgcolor} {RGB}{208,222,250} % hsl(219.5, 84%, 90%); +\definecolor{sphinx-note-title-fgcolor} {RGB}{20,93,234} % hsl(219.5, 84%, 50%); +\definecolor{sphinx-success-title-bgcolor} {RGB}{220,239,230} % hsl(150, 36.7%, 90%); +\definecolor{sphinx-success-title-fgcolor} {RGB}{81,174,128} % hsl(150, 36.7%, 50%); +\definecolor{sphinx-error-title-bgcolor} {RGB}{238,220,220} % hsl(0, 37%, 90%); +\definecolor{sphinx-error-title-fgcolor} {RGB}{174,80,80} % hsl(0, 37%, 50%); +\definecolor{sphinx-todo-title-bgcolor} {RGB}{226,204,254} % hsl(266.8, 100%, 90%); +\definecolor{sphinx-todo-title-fgcolor} {RGB}{113,0,255} % hsl(266.8, 100%, 50%); + +% Now use the above colours as default settings, following the choices +% done in sphinx13.css +\setkeys{sphinx}{ + div.note_title-background-TeXcolor=sphinx-note-title-bgcolor, + div.note_title-foreground-TeXcolor=sphinx-note-title-fgcolor, +% + div.hint_title-background-TeXcolor=sphinx-success-title-bgcolor, + div.hint_title-foreground-TeXcolor=sphinx-success-title-fgcolor, + div.tip_title-background-TeXcolor=sphinx-success-title-bgcolor, + div.tip_title-foreground-TeXcolor=sphinx-success-title-fgcolor, + div.seealso_title-background-TeXcolor=sphinx-success-title-bgcolor, + div.seealso_title-foreground-TeXcolor=sphinx-success-title-fgcolor, + div.todo_title-background-TeXcolor=sphinx-todo-title-bgcolor, + div.todo_title-foreground-TeXcolor=sphinx-todo-title-fgcolor, +% + div.important_title-background-TeXcolor=sphinx-warning-title-bgcolor, + div.important_title-foreground-TeXcolor=sphinx-warning-title-fgcolor, + div.caution_title-background-TeXcolor=sphinx-warning-title-bgcolor, + div.caution_title-foreground-TeXcolor=sphinx-warning-title-fgcolor, + div.warning_title-background-TeXcolor=sphinx-warning-title-bgcolor, + div.warning_title-foreground-TeXcolor=sphinx-warning-title-fgcolor, +% + div.attention_title-background-TeXcolor=sphinx-error-title-bgcolor, + div.attention_title-foreground-TeXcolor=sphinx-error-title-fgcolor, + div.danger_title-background-TeXcolor=sphinx-error-title-bgcolor, + div.danger_title-foreground-TeXcolor=sphinx-error-title-fgcolor, + div.error_title-background-TeXcolor=sphinx-error-title-bgcolor, + div.error_title-foreground-TeXcolor=sphinx-error-title-fgcolor, +% +% 8.1.0 add title rows, but will not use icons per default, so +% the fgcolor setting will be used only if user uses title-icon key + div.topic_title-background-TeXcolor=sphinx-admonition-title-bgcolor, + div.topic_title-foreground-TeXcolor=sphinx-admonition-title-fgcolor, + div.contents_title-background-TeXcolor=sphinx-admonition-title-bgcolor, + div.contents_title-foreground-TeXcolor=sphinx-admonition-title-fgcolor, + div.sidebar_title-background-TeXcolor=sphinx-note-title-bgcolor, + div.sidebar_title-foreground-TeXcolor=sphinx-note-title-fgcolor, +} + +% 7.4.0 Support for icons in admonition titles +% +% We let Sphinx use, listed in order of priority: +% - a user-specified package via iconpackage key, +% - fontawesome7 (supported since 9.0.0), +% - fontawesome6 (supported since 9.0.0), +% - fontawesome5, +% - fontawesome, +% - or nothing at all, and then icons are not drawn. +% To allow a user-specified package, an extra interface +% is provided for specifying the icon-drawing LaTeX code. +% +% We can't load fontawesome7 (or 6 or 5) unconditionally even if available, as it +% is incompatible with fontawesome package which may be preferred by user. We +% thus must delay loading the package to at begin document, and for now can +% only set the default value of iconpackage key. +\IfFileExists{fontawesome7.sty}{% + \DeclareStringOption[fontawesome7]{iconpackage}% +}% +{% + \IfFileExists{fontawesome6.sty}{% + \DeclareStringOption[fontawesome6]{iconpackage}% + }% + {% + \IfFileExists{fontawesome5.sty}{% + \DeclareStringOption[fontawesome5]{iconpackage}% + }% + {% + \IfFileExists{fontawesome.sty} + {\DeclareStringOption[fontawesome]{iconpackage}} + {\DeclareStringOption[none]{iconpackage}}% + }% + }% +}% +% Unfortunately icon macro names are not the same across fontawesome, +% fontawesome5, fontawesome6 and fontawesome7 LaTeX packages. +% At 9.0.0 we refactor the +% icon support code into something easier to maintain in future in case of a +% fontawesome8, etc... +% +% TODO: Handle spaces possibly caused by bad user usage of iconpackage key? +% This would need to check how LaTeX handle spaces in package name +% in \RequirePackage command. Things in this area may have changed +% recently (2025/04). +\AtBeginDocument{% + \ifx\spx@opt@iconpackage\spxstring@none + \else + \IfFileExists{\spx@opt@iconpackage.sty} + {\RequirePackage{\spx@opt@iconpackage}}% + {% + \let\spx@usr@iconpackage\spx@opt@iconpackage + \sphinxbuildwarning{badiconpackage}% + \PackageWarningNoLine{sphinx}{% + You have set iconpackage=\spx@usr@iconpackage\MessageBreak + But \spx@usr@iconpackage.sty is not found by LaTeX} + \let\spx@opt@iconpackage\spxstring@none + }% + \fi +} + +% Icon defaults depending on package used. +% Attention! no extra spaces (to align here) when using \@namedef! + +\@namedef{spx@fontawesome6@note}{\faIcon{circle-info}} +\@namedef{spx@fontawesome6@hint}{\faIcon[regular]{lightbulb}} +\@namedef{spx@fontawesome6@tip}{\faIcon[regular]{lightbulb}} +\@namedef{spx@fontawesome6@seealso}{\faIcon{share}} +\@namedef{spx@fontawesome6@todo}{\faIcon{pen}} +\@namedef{spx@fontawesome6@important}{\faIcon{circle-pause}} +\@namedef{spx@fontawesome6@caution}{\faIcon{radiation}} +\@namedef{spx@fontawesome6@warning}{\faIcon{triangle-exclamation}} +\@namedef{spx@fontawesome6@attention}{\faIcon{triangle-exclamation}} +\@namedef{spx@fontawesome6@danger}{\faIcon{radiation}} +\@namedef{spx@fontawesome6@error}{\faIcon{circle-xmark}} + +% Turns out that fontawesome7 commands for our target icons are +% same as with fontawesome6. So make a loop to spare a few lines here. +\@for\x:=note,hint,tip,seealso,todo,important,caution,warning,attention,% + danger,error% +\do{\expandafter\let\csname spx@fontawesome7@\x\expandafter\endcsname + \csname spx@fontawesome6@\x\endcsname} + +\@namedef{spx@fontawesome5@note}{\faIcon{info-circle}} +\@namedef{spx@fontawesome5@hint}{\faIcon[regular]{lightbulb}} +\@namedef{spx@fontawesome5@tip}{\faIcon[regular]{lightbulb}} +\@namedef{spx@fontawesome5@seealso}{\faIcon{share}} +\@namedef{spx@fontawesome5@todo}{\faIcon{pen}} +\@namedef{spx@fontawesome5@important}{\faIcon{pause-circle}} +\@namedef{spx@fontawesome5@caution}{\faIcon{radiation}} +\@namedef{spx@fontawesome5@warning}{\faIcon{exclamation-triangle}} +\@namedef{spx@fontawesome5@attention}{\faIcon{exclamation-triangle}} +\@namedef{spx@fontawesome5@danger}{\faIcon{radiation}} +\@namedef{spx@fontawesome5@error}{\faIcon{times-circle}} + +\def\spx@fontawesome@note {\faicon{info-circle}} +\def\spx@fontawesome@hint {\faicon{lightbulb-o}} +\def\spx@fontawesome@tip {\faicon{lightbulb-o}} +\def\spx@fontawesome@seealso {\faicon{share}} +\def\spx@fontawesome@todo {\faicon{pencil}} +\def\spx@fontawesome@important{\faicon{pause-circle}} +\def\spx@fontawesome@caution {\faicon{bolt}} +\def\spx@fontawesome@warning {\faicon{exclamation-triangle}} +\def\spx@fontawesome@attention{\faicon{exclamation-triangle}} +\def\spx@fontawesome@danger {\faicon{bolt}} +\def\spx@fontawesome@error {\faicon{times-circle}} + +% \spx@none@{note,hint,...} left undefined, the \@nameuse will be \relax +\def\spx@titleicon@default#1{\@nameuse{spx@\spx@opt@iconpackage @#1}} +\setkeys{sphinx}{ + div.note_title-icon = \spx@titleicon@default{note}, + div.hint_title-icon = \spx@titleicon@default{hint}, + div.tip_title-icon = \spx@titleicon@default{tip}, + div.seealso_title-icon = \spx@titleicon@default{seealso}, + div.todo_title-icon = \spx@titleicon@default{todo}, + div.important_title-icon = \spx@titleicon@default{important}, + div.caution_title-icon = \spx@titleicon@default{caution}, + div.warning_title-icon = \spx@titleicon@default{warning}, + div.attention_title-icon = \spx@titleicon@default{attention}, + div.danger_title-icon = \spx@titleicon@default{danger}, + div.error_title-icon = \spx@titleicon@default{error}, +% MEMO: the new at 8.1.0 defaults for contents/topic/sidebar directives +% use no icons, they use \sphinxdotitlerow which detects automatically +% whether title-icon key has been set or not. +} + +\newif\ifspx@opt@box@addstrut +\expandafter\def\csname KV@sphinx@box_addstrut\endcsname#1{% + \csname spx@opt@box@addstrut#1\endcsname +} +\expandafter\def\csname KV@sphinx@box_addstrut@default\endcsname{% + \spx@opt@box@addstruttrue +} + +\DeclareDefaultOption{\@unknownoptionerror} +\ProcessKeyvalOptions* +% don't allow use of maxlistdepth via \sphinxsetup. +\DisableKeyvalOption{sphinx}{maxlistdepth} +\DisableKeyvalOption{sphinx}{numfigreset} +\DisableKeyvalOption{sphinx}{nonumfigreset} +\DisableKeyvalOption{sphinx}{mathnumfig} +\DisableKeyvalOption{sphinx}{booktabs} +\DisableKeyvalOption{sphinx}{borderless} +\DisableKeyvalOption{sphinx}{rowcolors} +% FIXME: this is unrelated to an option, move this elsewhere +% To allow hyphenation of first word in narrow contexts; no option, +% customization to be done via 'preamble' key +\newcommand*\sphinxAtStartPar{\leavevmode\nobreak\hskip\z@skip} +% No need for the \hspace{0pt} trick (\hskip\z@skip) with luatex +\ifdefined\directlua\let\sphinxAtStartPar\@empty\fi +% user interface: options can be changed midway in a document! +\newcommand\sphinxsetup{\setkeys{sphinx}} + + +%% MISCELLANEOUS CONTEXT +% +% flag to be set in a framed environment +% (defined here as currently needed by three sphinxlatex....sty files and +% even if not needed if such files are replaced, the definition does no harm) +\newif\ifspx@inframed +% +% \spx@ifcaptionpackage (defined at begin document) +% is needed currently in macros from: +% sphinxlatexliterals.sty (sphinxVerbatim) +% sphinxlatextables.sty (for some macros used in the table templates) +% +% \sphinxcaption is mark-up injected by the tabular and tabulary templates +% it is defined in sphinxlatextables.sty +% +% store the original \caption macro for usage with figures inside longtable +% and tabulary cells. Make sure we get the final \caption in presence of +% caption package, whether the latter was loaded before or after sphinx. +\AtBeginDocument{% + \let\spx@originalcaption\caption + \@ifpackageloaded{caption} + {\let\spx@ifcaptionpackage\@firstoftwo + \caption@AtBeginDocument*{\let\spx@originalcaption\caption}% +% in presence of caption package, drop our own \sphinxcaption whose aim was to +% ensure same width of caption to all kinds of tables (tabular(y), longtable), +% because caption package has its own width (or margin) option + \def\sphinxcaption{\caption}% + }% + {\let\spx@ifcaptionpackage\@secondoftwo}% +} + +%% PASS OPTIONS +% +% pass options to hyperref; it must not have been loaded already +\RequirePackage{sphinxoptionshyperref} +% pass options to geometry; it must not have been loaded already +\RequirePackage{sphinxoptionsgeometry} + + +%% COLOR (general) +% +% FIXME: these two should be deprecated +% +% FIXME: \normalcolor should be used and \py@NormalColor never defined +\def\py@NormalColor{\color{black}} +% FIXME: \color{TitleColor} should be used directly and \py@TitleColor +% should never get defined. +\def\py@TitleColor{\color{TitleColor}} + + +%% PACKAGES +% +% as will be indicated below, secondary style files load some more packages +% +% For \text macro (sphinx.util.texescape) +% also for usage of \firstchoice@true(false) in sphinxlatexgraphics.sty +\RequirePackage{amstext} +% It was passed "warn" option from latex template in case it is already loaded +% via some other package before \usepackage{sphinx} in preamble +\RequirePackage{textcomp} +% For the H specifier. Do not \restylefloat{figure}, it breaks Sphinx code +% for allowing figures in tables. +\RequirePackage{float} +% For floating figures in the text. Better to load after float. +\RequirePackage{wrapfig} +% Provides \captionof, used once by latex writer (\captionof{figure}) +\RequirePackage{capt-of} +% Support hlist directive +\RequirePackage{multicol} + + +%% GRAPHICS +% +% It will always be needed, so let's load it here +\RequirePackage{graphicx} +\RequirePackage{sphinxlatexgraphics} + + +%% FRAMED ENVIRONMENTS +% +% \sphinxbox added at 6.2.0, its definition is in sphinxpackageboxes. +% +% Alias all \sphinxsetup "box_" keys to become \sphinxboxsetup no-prefix keys +\@tfor\x:={border-width}% + {border-top-width}{border-right-width}{border-bottom-width}{border-left-width}% + {box-decoration-break}% This one is actually useless, as \sphinxbox + % creates an unbreakable horizontal box, not a breakable vertical + % box. And as is well-known it is very complicated (not to say + % impossible) to create in LaTeX breakable horizontal boxes. No + % package offers them. See the complications for the support of + % verbatimforcewraps in sphinxlatexliterals.sty or see the source + % code of the soul or soulutf8 packages. + {padding}% + {padding-top}{padding-right}{padding-bottom}{padding-left}% + {border-radius}% + {border-top-left-radius}{border-top-right-radius}% + {border-bottom-right-radius}{border-bottom-left-radius}% + {box-shadow}% + {border-TeXcolor}{background-TeXcolor}{box-shadow-TeXcolor}{TeXcolor}% + {TeXextras}{addstrut}{addstrut@default}% +\do{\expandafter\let\csname KV@sphinxbox@\x\expandafter\endcsname + \csname KV@sphinx@box_\x\endcsname} +% Let \sphinxboxsetup also prepare a "reset", which will be used by nested +% boxes; currently and by laziness this is implemented simply by accumulating +% all passed options inside some storage, in the order they were given, rather +% than saving the box would-be parameters. Advantage is that this will not +% have to be modified if additional keys are added in future (e.g. for +% elliptic corners). Storing obeys TeX groups. (these details would be +% relevant only for some genuine independent LaTeX package and manual user +% authored mark-up, not Sphinx auto mark-up). +\newcommand\sphinxboxsetup[1]{% + \setkeys{sphinxbox}{#1}% + \expandafter\def\expandafter\spx@boxes@sphinxbox@defaults\expandafter + {\spx@boxes@sphinxbox@defaults,#1}% +} +\def\spx@boxes@sphinxbox@reset{% + \begingroup\def\x{\endgroup\setkeys{sphinxbox}}% + \expandafter\x\expandafter{\spx@boxes@sphinxbox@defaults}% +} +% Some of these defaults got already set. But we now list them all explicitly +% for a complete initial configuration of reset storage. +% At 7.4.0, \fboxrule and \fboxsep replaced by 0.4pt and 3pt which are anyhow +% the defaults for these LaTeX dimensions. 8.2.0 corrected border-radius +% default back to 3pt (\fboxsep) not 0.4pt (\fboxrule). +\let\spx@boxes@sphinxbox@defaults\@gobble +\sphinxboxsetup{% + border-width=0.4pt, + padding=3pt, + border-radius=3pt, + box-shadow=none, +% MEMO: as xcolor is loaded, \spx@defineorletcolor has a "\colorlet" branch +% which makes this syntax acceptable and avoids duplicating here the values. + border-TeXcolor=VerbatimBorderColor, + background-TeXcolor=VerbatimColor, +% 7.4.0 modified the color of the shadow (anyhow box-shadow is set above to none +% so no shadow is drawn), to be as the new shadow colour of topic boxes. + box-shadow-TeXcolor={RGB}{108,108,108}, + TeXextras={}, + addstrut=false, + }% +\RequirePackage{sphinxpackageboxes} +\RequirePackage{sphinxlatexadmonitions} +\RequirePackage{sphinxlatexliterals} +\RequirePackage{sphinxlatexshadowbox} + + +%% CONTAINERS +% +\RequirePackage{sphinxlatexcontainers} + + +%% PYGMENTS +% stylesheet for highlighting with pygments +\RequirePackage{sphinxhighlight} +\let\spx@PYG\PYG +% See sphinxlatexliterals.sty for \spx@FV@Tab +\protected\def\PYG#1#2{\spx@PYG{#1}{\let\FV@Tab\spx@FV@Tab#2}} + +%% TABLES +% +\RequirePackage{sphinxlatextables} + + +%% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS +% +\RequirePackage{sphinxlatexnumfig} + + +%% LISTS +% +\RequirePackage{sphinxlatexlists} + + +%% FOOTNOTES +% +% Support scopes for footnote numbering +% This is currently stepped at each input file +\newcounter{sphinxscope} +\newcommand{\sphinxstepscope}{\stepcounter{sphinxscope}} +% We ensure \thesphinxscope expands to digits tokens, independently of language +\renewcommand{\thesphinxscope}{\number\value{sphinxscope}} +\newcommand\sphinxthefootnotemark[2]{% + % this is used to make reference to an explicitly numbered footnote not on same page + % #1=label of footnote text, #2=page number where footnote text was printed + \ifdefined\pagename + \pagename\space#2, % <- space + \else + p. #2, % <- space + \fi #1% no space +} +% support large numbered footnotes in minipage; but this is now obsolete +% from systematic use of savenotes environment around minipages +\def\thempfootnote{\arabic{mpfootnote}} +% This package is needed to support hyperlinked footnotes in tables and +% framed contents, and to allow code-blocks in footnotes. +\RequirePackage{sphinxpackagefootnote} + + +%% INDEX, BIBLIOGRAPHY, APPENDIX, TABLE OF CONTENTS +% +\RequirePackage{sphinxlatexindbibtoc} + + +%% STYLING +% +\RequirePackage{sphinxlatexstylepage} +\RequirePackage{sphinxlatexstyleheadings} +\RequirePackage{sphinxlatexstyletext} + + +%% MODULE RELEASE DATA AND OBJECT DESCRIPTIONS +% +\RequirePackage{sphinxlatexobjects} + + +% FIXME: this line should be dropped, as "9" is default anyhow. +\ifdefined\pdfcompresslevel\pdfcompresslevel = 9 \fi + +%%% SUPPORT FOR CSS3 EXTRA LENGTH UNITS +% cf rstdim_to_latexdim in latex.py +% +\def\sphinxchdimen{\dimexpr\fontcharwd\font`0\relax} +% TODO: decide if we want rather \textwidth/\textheight. +\newdimen\sphinxvwdimen + \sphinxvwdimen=\dimexpr0.01\paperwidth\relax +\newdimen\sphinxvhdimen + \sphinxvhdimen=\dimexpr0.01\paperheight\relax +\newdimen\sphinxvmindimen + \sphinxvmindimen=\dimexpr + \ifdim\paperwidth<\paperheight\sphinxvwdimen\else\sphinxvhdimen\fi + \relax +\newdimen\sphinxvmaxdimen + \sphinxvmaxdimen=\dimexpr + \ifdim\paperwidth<\paperheight\sphinxvhdimen\else\sphinxvwdimen\fi + \relax +\newdimen\sphinxQdimen + \sphinxQdimen=0.25mm +% MEMO: \sphinxremdimen is defined in the template as it needs +% the config variable pointsize. +\endinput diff --git a/build/latex/sphinx.xdy b/build/latex/sphinx.xdy new file mode 100644 index 0000000..8df526e --- /dev/null +++ b/build/latex/sphinx.xdy @@ -0,0 +1,230 @@ +;;; -*- mode: lisp; coding: utf-8; -*- + +;; Unfortunately xindy is out-of-the-box hyperref-incompatible. This +;; configuration is a workaround, which requires to pass option +;; hyperindex=false to hyperref. +;; textit and emph not currently used, spxpagem replaces former textbf +(define-attributes (("textbf" "textit" "emph" "spxpagem" "default"))) +(markup-locref :open "\textbf{\hyperpage{" :close "}}" :attr "textbf") +(markup-locref :open "\textit{\hyperpage{" :close "}}" :attr "textit") +(markup-locref :open "\emph{\hyperpage{" :close "}}" :attr "emph") +(markup-locref :open "\spxpagem{\hyperpage{" :close "}}" :attr "spxpagem") +(markup-locref :open "\hyperpage{" :close "}" :attr "default") + +(require "numeric-sort.xdy") + +;; xindy base module latex.xdy loads tex.xdy and the latter instructs +;; xindy to ignore **all** TeX macros in .idx entries, except those +;; explicitly described in merge rule. But when after applying all +;; merge rules an empty string results, xindy raises an error: + +;; ERROR: CHAR: index 0 should be less than the length of the string + +;; For example when using pdflatex with utf-8 characters the index +;; file will contain \IeC macros and they will get ignored except if +;; suitable merge rules are loaded early. The texindy script coming +;; with xindy provides this, but only for Latin scripts. The texindy +;; man page says to use rather xelatex or lualatex in case of Cyrillic +;; scripts. + +;; Sphinx contributes LICRcyr2utf8.xdy to provide support for Cyrillic +;; scripts for the pdflatex engine. + +;; Another issue caused by xindy ignoring all TeX macros except those +;; explicitly declared reveals itself when attempting to index ">>>", +;; as the ">" is converted to "\textgreater{}" by Sphinx's LaTeX +;; escaping. + +;; To fix this, Sphinx does **not** use texindy, and does not even +;; load the xindy latex.xdy base module. + +;(require "latex.xdy") + +;; Rather it incorporates some suitable extracts from latex.xdy and +;; tex.xdy with additional Sphinx contributed rules. + +;; But, this means for pdflatex and Latin scripts that the xindy file +;; tex/inputenc/uf8.xdy is not usable because it refers to the macro +;; \IeC only sporadically, and as tex.xdy is not loaded, a rule such as +;; (merge-rule "\'e" "é" :string) +;; does not work, it must be +;; (merge-rule "\IeC {\'e}" "é" :string) +;; So Sphinx contributes LICRlatin2utf8.xdy to mitigate that problem. + +;;;;;;;; extracts from tex.xdy (discarding most original comments): + +;;; +;;; TeX conventions +;;; + +;; Discard leading and trailing white space. Collapse multiple white +;; space characters to blank. + +(merge-rule "^ +" "" :eregexp) +(merge-rule " +$" "" :eregexp) +(merge-rule " +" " " :eregexp) + +;; Handle TeX markup + +(merge-rule "\\([{}$%&#])" "\1" :eregexp) + +;;;;;;;; end of extracts from xindy's tex.xdy + +;;;;;;;; extracts from latex.xdy: + +;; Standard location classes: arabic and roman numbers, and alphabets. + +(define-location-class "arabic-page-numbers" ("arabic-numbers")) +(define-location-class "roman-page-numbers" ("roman-numbers-lowercase")) +(define-location-class "Roman-page-numbers" ("roman-numbers-uppercase")) +(define-location-class "alpha-page-numbers" ("alpha")) +(define-location-class "Alpha-page-numbers" ("ALPHA")) + +;; Output Markup + +(markup-letter-group-list :sep "~n~n \indexspace~n") + +(markup-indexentry :open "~n \item " :depth 0) +(markup-indexentry :open "~n \subitem " :depth 1) +(markup-indexentry :open "~n \subsubitem " :depth 2) + +(markup-locclass-list :open ", " :sep ", ") +(markup-locref-list :sep ", ") + +;;;;;;;; end of extracts from latex.xdy + +;; The LaTeX \index command turns \ into normal character so the TeX macros +;; written to .idx files are not followed by a blank. This is different +;; from non-ascii letters which end up (with pdflatex) as \IeC macros in .idx +;; file, with a blank space after \IeC + +;; Details of the syntax are explained at +;; https://xindy.sourceforge.net/doc/manual-3.html +;; In absence of :string, "xindy uses an auto-detection mechanism to decide, +;; if the pattern is a regular expression or not". But it is not obvious to +;; guess, for example "\\_" is not detected as RE but "\\P\{\}" is, so for +;; being sure we apply the :string switch everywhere and do not use \\ etc... + +;; Go back from sphinx.util.texescape TeX macros to UTF-8 + +(merge-rule "\sphinxleftcurlybrace{}" "{" :string) +(merge-rule "\sphinxrightcurlybrace{}" "}" :string) +(merge-rule "\_" "_" :string) +(merge-rule "{[}" "[" :string) +(merge-rule "{]}" "]" :string) +(merge-rule "\textbackslash{}" "\" :string) ; " for Emacs syntax highlighting +(merge-rule "\textasciitilde{}" "~~" :string); the ~~ escape is needed here +(merge-rule "\textasciicircum{}" "^" :string) +(merge-rule "\sphinxhyphen{}" "-" :string) +(merge-rule "\textquotesingle{}" "'" :string) +(merge-rule "\textasciigrave{}" "`" :string) +(merge-rule "\textless{}" "<" :string) +(merge-rule "\textgreater{}" ">" :string) +(merge-rule "\P{}" "¶" :string) +(merge-rule "\S{}" "§" :string) +(merge-rule "\texteuro{}" "€" :string) +(merge-rule "\(\infty\)" "∞" :string) +(merge-rule "\(\pm\)" "±" :string) +(merge-rule "\(\rightarrow\)" "→" :string) +(merge-rule "\(\checkmark\)" "✓" :string) +(merge-rule "\textendash{}" "–" :string) +(merge-rule "\textbar{}" "|" :string) +(merge-rule "\(\sp{\text{0}}\)" "⁰" :string) +(merge-rule "\(\sp{\text{1}}\)" "¹" :string) +(merge-rule "\(\sp{\text{2}}\)" "²" :string) +(merge-rule "\(\sp{\text{3}}\)" "³" :string) +(merge-rule "\(\sp{\text{4}}\)" "⁴" :string) +(merge-rule "\(\sp{\text{5}}\)" "⁵" :string) +(merge-rule "\(\sp{\text{6}}\)" "⁶" :string) +(merge-rule "\(\sp{\text{7}}\)" "⁷" :string) +(merge-rule "\(\sp{\text{8}}\)" "⁸" :string) +(merge-rule "\(\sp{\text{9}}\)" "⁹" :string) +(merge-rule "\(\sb{\text{0}}\)" "₀" :string) +(merge-rule "\(\sb{\text{1}}\)" "₁" :string) +(merge-rule "\(\sb{\text{2}}\)" "₂" :string) +(merge-rule "\(\sb{\text{3}}\)" "₃" :string) +(merge-rule "\(\sb{\text{4}}\)" "₄" :string) +(merge-rule "\(\sb{\text{5}}\)" "₅" :string) +(merge-rule "\(\sb{\text{6}}\)" "₆" :string) +(merge-rule "\(\sb{\text{7}}\)" "₇" :string) +(merge-rule "\(\sb{\text{8}}\)" "₈" :string) +(merge-rule "\(\sb{\text{9}}\)" "₉" :string) +(merge-rule "\IeC {\textalpha }" "α" :string) +(merge-rule "\IeC {\textbeta }" "β" :string) +(merge-rule "\IeC {\textgamma }" "γ" :string) +(merge-rule "\IeC {\textdelta }" "δ" :string) +(merge-rule "\IeC {\textepsilon }" "ε" :string) +(merge-rule "\IeC {\textzeta }" "ζ" :string) +(merge-rule "\IeC {\texteta }" "η" :string) +(merge-rule "\IeC {\texttheta }" "θ" :string) +(merge-rule "\IeC {\textiota }" "ι" :string) +(merge-rule "\IeC {\textkappa }" "κ" :string) +(merge-rule "\IeC {\textlambda }" "λ" :string) +(merge-rule "\IeC {\textmu }" "μ" :string) +(merge-rule "\IeC {\textnu }" "ν" :string) +(merge-rule "\IeC {\textxi }" "ξ" :string) +(merge-rule "\IeC {\textomicron }" "ο" :string) +(merge-rule "\IeC {\textpi }" "π" :string) +(merge-rule "\IeC {\textrho }" "ρ" :string) +(merge-rule "\IeC {\textsigma }" "σ" :string) +(merge-rule "\IeC {\texttau }" "τ" :string) +(merge-rule "\IeC {\textupsilon }" "υ" :string) +(merge-rule "\IeC {\textphi }" "φ" :string) +(merge-rule "\IeC {\textchi }" "χ" :string) +(merge-rule "\IeC {\textpsi }" "ψ" :string) +(merge-rule "\IeC {\textomega }" "ω" :string) +(merge-rule "\IeC {\textAlpha }" "Α" :string) +(merge-rule "\IeC {\textBeta }" "Β" :string) +(merge-rule "\IeC {\textGamma }" "Γ" :string) +(merge-rule "\IeC {\textDelta }" "Δ" :string) +(merge-rule "\IeC {\textEpsilon }" "Ε" :string) +(merge-rule "\IeC {\textZeta }" "Ζ" :string) +(merge-rule "\IeC {\textEta }" "Η" :string) +(merge-rule "\IeC {\textTheta }" "Θ" :string) +(merge-rule "\IeC {\textIota }" "Ι" :string) +(merge-rule "\IeC {\textKappa }" "Κ" :string) +(merge-rule "\IeC {\textLambda }" "Λ" :string) +(merge-rule "\IeC {\textMu }" "Μ" :string) +(merge-rule "\IeC {\textNu }" "Ν" :string) +(merge-rule "\IeC {\textTheta }" "Θ" :string) +(merge-rule "\IeC {\textIota }" "Ι" :string) +(merge-rule "\IeC {\textKappa }" "Κ" :string) +(merge-rule "\IeC {\textLambda }" "Λ" :string) +(merge-rule "\IeC {\textMu }" "Μ" :string) +(merge-rule "\IeC {\textNu }" "Ν" :string) +(merge-rule "\IeC {\textXi }" "Ξ" :string) +(merge-rule "\IeC {\textOmicron }" "Ο" :string) +(merge-rule "\IeC {\textPi }" "Π" :string) +(merge-rule "\IeC {\textRho }" "Ρ" :string) +(merge-rule "\IeC {\textSigma }" "Σ" :string) +(merge-rule "\IeC {\textTau }" "Τ" :string) +(merge-rule "\IeC {\textUpsilon }" "Υ" :string) +(merge-rule "\IeC {\textPhi }" "Φ" :string) +(merge-rule "\IeC {\textChi }" "Χ" :string) +(merge-rule "\IeC {\textPsi }" "Ψ" :string) +(merge-rule "\IeC {\textOmega }" "Ω" :string) +(merge-rule "\IeC {\textohm }" "Ω" :string) + +;; This xindy module provides some basic support for "see" +(require "makeindex.xdy") + +;; This creates one-letter headings and works fine with utf-8 letters. +;; For Cyrillic with pdflatex works thanks to LICRcyr2utf8.xdy +(require "latin-lettergroups.xdy") + +;; currently we don't (know how to easily) separate "Numbers" from +;; "Symbols" with xindy as is the case with makeindex. +(markup-index :open "\begin{sphinxtheindex} +\let\lettergroup\sphinxstyleindexlettergroup +\let\lettergroupDefault\sphinxstyleindexlettergroupDefault +\let\spxpagem\sphinxstyleindexpagemain +\let\spxentry\sphinxstyleindexentry +\let\spxextra\sphinxstyleindexextra + +" + :close " + +\end{sphinxtheindex} +" + :tree) + diff --git a/build/latex/sphinxhighlight.sty b/build/latex/sphinxhighlight.sty new file mode 100644 index 0000000..170f557 --- /dev/null +++ b/build/latex/sphinxhighlight.sty @@ -0,0 +1,130 @@ +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{sphinxhighlight}[2022/06/30 stylesheet for highlighting with pygments] +% Its contents depend on pygments_style configuration variable. + + +\makeatletter +\def\PYG@reset{\let\PYG@it=\relax \let\PYG@bf=\relax% + \let\PYG@ul=\relax \let\PYG@tc=\relax% + \let\PYG@bc=\relax \let\PYG@ff=\relax} +\def\PYG@tok#1{\csname PYG@tok@#1\endcsname} +\def\PYG@toks#1+{\ifx\relax#1\empty\else% + \PYG@tok{#1}\expandafter\PYG@toks\fi} +\def\PYG@do#1{\PYG@bc{\PYG@tc{\PYG@ul{% + \PYG@it{\PYG@bf{\PYG@ff{#1}}}}}}} +\def\PYG#1#2{\PYG@reset\PYG@toks#1+\relax+\PYG@do{#2}} + +\@namedef{PYG@tok@w}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}} +\@namedef{PYG@tok@c}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@cp}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@cs}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}\def\PYG@bc##1{{\setlength{\fboxsep}{0pt}\colorbox[rgb]{1.00,0.94,0.94}{\strut ##1}}}} +\@namedef{PYG@tok@k}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kp}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kt}{\def\PYG@tc##1{\textcolor[rgb]{0.56,0.13,0.00}{##1}}} +\@namedef{PYG@tok@o}{\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\@namedef{PYG@tok@ow}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@nb}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@nf}{\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.49}{##1}}} +\@namedef{PYG@tok@nc}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}} +\@namedef{PYG@tok@nn}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}} +\@namedef{PYG@tok@ne}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@nv}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@no}{\def\PYG@tc##1{\textcolor[rgb]{0.38,0.68,0.84}{##1}}} +\@namedef{PYG@tok@nl}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.13,0.44}{##1}}} +\@namedef{PYG@tok@ni}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.84,0.33,0.22}{##1}}} +\@namedef{PYG@tok@na}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@nt}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.45}{##1}}} +\@namedef{PYG@tok@nd}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.33,0.33,0.33}{##1}}} +\@namedef{PYG@tok@s}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sd}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@si}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.44,0.63,0.82}{##1}}} +\@namedef{PYG@tok@se}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sr}{\def\PYG@tc##1{\textcolor[rgb]{0.14,0.33,0.53}{##1}}} +\@namedef{PYG@tok@ss}{\def\PYG@tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}} +\@namedef{PYG@tok@sx}{\def\PYG@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}} +\@namedef{PYG@tok@m}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@gh}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}} +\@namedef{PYG@tok@gu}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}} +\@namedef{PYG@tok@gd}{\def\PYG@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}} +\@namedef{PYG@tok@gi}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}} +\@namedef{PYG@tok@gr}{\def\PYG@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}} +\@namedef{PYG@tok@ge}{\let\PYG@it=\textit} +\@namedef{PYG@tok@gs}{\let\PYG@bf=\textbf} +\@namedef{PYG@tok@ges}{\let\PYG@bf=\textbf\let\PYG@it=\textit} +\@namedef{PYG@tok@gp}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}} +\@namedef{PYG@tok@go}{\def\PYG@tc##1{\textcolor[rgb]{0.20,0.20,0.20}{##1}}} +\@namedef{PYG@tok@gt}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.27,0.87}{##1}}} +\@namedef{PYG@tok@err}{\def\PYG@bc##1{{\setlength{\fboxsep}{\string -\fboxrule}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}} +\@namedef{PYG@tok@kc}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kd}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kn}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kr}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@bp}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@fm}{\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.49}{##1}}} +\@namedef{PYG@tok@vc}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@vg}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@vi}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@vm}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@sa}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sb}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sc}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@dl}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@s2}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sh}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@s1}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@mb}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mf}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mh}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mi}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@il}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mo}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@ch}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@cm}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@cpf}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@c1}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} + +\def\PYGZbs{\char`\\} +\def\PYGZus{\char`\_} +\def\PYGZob{\char`\{} +\def\PYGZcb{\char`\}} +\def\PYGZca{\char`\^} +\def\PYGZam{\char`\&} +\def\PYGZlt{\char`\<} +\def\PYGZgt{\char`\>} +\def\PYGZsh{\char`\#} +\def\PYGZpc{\char`\%} +\def\PYGZdl{\char`\$} +\def\PYGZhy{\char`\-} +\def\PYGZsq{\char`\'} +\def\PYGZdq{\char`\"} +\def\PYGZti{\char`\~} +% for compatibility with earlier versions +\def\PYGZat{@} +\def\PYGZlb{[} +\def\PYGZrb{]} +\makeatother + +% Sphinx redefinitions +% Originally to obtain a straight single quote via package textcomp, then +% to fix problems for the 5.0.0 inline code highlighting (captions!). +% The \text is from amstext, a dependency of sphinx.sty. It is here only +% to avoid build errors if for some reason expansion is in math mode. +\def\PYGZbs{\text\textbackslash} +\def\PYGZus{\_} +\def\PYGZob{\{} +\def\PYGZcb{\}} +\def\PYGZca{\text\textasciicircum} +\def\PYGZam{\&} +\def\PYGZlt{\text\textless} +\def\PYGZgt{\text\textgreater} +\def\PYGZsh{\#} +\def\PYGZpc{\%} +\def\PYGZdl{\$} +\def\PYGZhy{\sphinxhyphen}% defined in sphinxlatexstyletext.sty +\def\PYGZsq{\text\textquotesingle} +\def\PYGZdq{"} +\def\PYGZti{\text\textasciitilde} +\makeatletter +% use \protected to allow syntax highlighting in captions +\protected\def\PYG#1#2{\PYG@reset\PYG@toks#1+\relax+{\PYG@do{#2}}} +\makeatother diff --git a/build/latex/sphinxhowto.cls b/build/latex/sphinxhowto.cls new file mode 100644 index 0000000..8d7dd0e --- /dev/null +++ b/build/latex/sphinxhowto.cls @@ -0,0 +1,102 @@ +% +% sphinxhowto.cls for Sphinx (https://www.sphinx-doc.org/) +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{sphinxhowto}[2019/12/01 v2.3.0 Document class (Sphinx howto)] + +% 'oneside' option overriding the 'twoside' default +\newif\if@oneside +\DeclareOption{oneside}{\@onesidetrue} +% Pass remaining document options to the parent class. +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\sphinxdocclass}} +\ProcessOptions\relax + +% Default to two-side document +\if@oneside +% nothing to do (oneside is the default) +\else +\PassOptionsToClass{twoside}{\sphinxdocclass} +\fi + +\LoadClass{\sphinxdocclass} + +% Set some sane defaults for section numbering depth and TOC depth. You can +% reset these counters in your preamble. +% +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2}% i.e. section and subsection + +% Adapt \and command to the flushright context of \sphinxmaketitle, to +% avoid ragged line endings if author names do not fit all on one single line +\DeclareRobustCommand{\and}{% + \end{tabular}\kern-\tabcolsep + \allowbreak + \hskip\dimexpr1em+\tabcolsep\@plus.17fil\begin{tabular}[t]{c}% +}% +% If it is desired that each author name be on its own line, use in preamble: +%\DeclareRobustCommand{\and}{% +% \end{tabular}\kern-\tabcolsep\\\begin{tabular}[t]{c}% +%}% +% Change the title page to look a bit better, and fit in with the fncychap +% ``Bjarne'' style a bit better. +% +\newcommand{\sphinxmaketitle}{% + \noindent\rule{\linewidth}{1pt}\par + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}% + \endgroup + \begin{flushright} + \sphinxlogo + \py@HeaderFamily + {\Huge \@title }\par + {\itshape\large \py@release \releaseinfo}\par + \vspace{25pt} + {\Large + \begin{tabular}[t]{c} + \@author + \end{tabular}\kern-\tabcolsep}\par + \vspace{25pt} + \@date \par + \py@authoraddress \par + \end{flushright} + \@thanks + \setcounter{footnote}{0} + \let\thanks\relax\let\maketitle\relax + %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + +\newcommand{\sphinxtableofcontents}{% + \begingroup + \parskip \z@skip + \sphinxtableofcontentshook + \tableofcontents + \endgroup + \noindent\rule{\linewidth}{1pt}\par + \vspace{12pt}% +} +\newcommand\sphinxtableofcontentshook{} +\pagenumbering{arabic} + +% Fix the bibliography environment to add an entry to the Table of +% Contents. +% For an article document class this environment is a section, +% so no page break before it. +% +\newenvironment{sphinxthebibliography}[1]{% + % \phantomsection % not needed here since TeXLive 2010's hyperref + \begin{thebibliography}{#1}% + \addcontentsline{toc}{section}{\ifdefined\refname\refname\else\ifdefined\bibname\bibname\fi\fi}}{\end{thebibliography}} + + +% Same for the indices. +% The memoir class already does this, so we don't duplicate it in that case. +% +\@ifclassloaded{memoir} + {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}} + {\newenvironment{sphinxtheindex}{% + \phantomsection % needed because no chapter, section, ... is created by theindex + \begin{theindex}% + \addcontentsline{toc}{section}{\indexname}}{\end{theindex}}} diff --git a/build/latex/sphinxlatexadmonitions.sty b/build/latex/sphinxlatexadmonitions.sty new file mode 100644 index 0000000..dd3145d --- /dev/null +++ b/build/latex/sphinxlatexadmonitions.sty @@ -0,0 +1,408 @@ +%% NOTICES AND ADMONITIONS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexadmonitions}[2025/10/24 v9.0.0 admonitions] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - sphinxseealso environment added at 6.1.0. +% +% - sphinxtodo environment added at 7.4.0. +% +% - sphinxadmonition (environment) +% This is a dispatch which formerly configured +% +% - note, hint, important, tip to use sphinxlightbox (or optionally +% sphinxheavybox since 6.2.0), +% - warning, caution, attention, danger, error to use sphinxheavybox. +% +% Since 7.4.0 all admonitions use sphinxheavybox. +% +% - All environments sphinxnote, sphinxwarning, etc... can be redefined as +% will by user. Thay have a single parameter #1 which is the title. +% +% - Also redefinable by user are the one-argument commands +% * \sphinxstylenotetitle, +% * \sphinxstylewarningtitle, +% * etc.... one for each admonition type (also seealso and todo). +% +% - At 7.4.0, all commands of previous item use \sphinxdotitlerow. +% (the 7.4.0 name, still usable, was \sphinxdotitlerowwithicon; the 8.1.0 +% version is also used for topic, contents and sidebar directives, see +% sphinxlatexshadowbox.sty, and handles both "with icon" and "without +% icon" situations). +% +% The sphinxlightbox environment is kept for backward compatibility, for user +% custom code which used it via custom definitions done in preamble or via +% raw latex directive. +% MEMO: here is for example how sphinxnote was formerly defined: +% (where #1 is the localized string Note, followed with a colon) +% \newenvironment{sphinxnote}[1] +% {\begin{sphinxlightbox}\sphinxstrong{#1} } +% {\end{sphinxlightbox}} +% Use this if you want to revert the 7.4.0 switch to usage of sphinxheavybox. +% (the 7.4.0 redefined \sphinxstylenotetitle will not work in sphinxlightbox, +% so \sphinxstrong{#1} which was its former default is used above). + +% Dependencies (they do not need to be defined at time of loading): +% +% - of course the various colour and dimension options handled via sphinx.sty +% - dimension register \spx@image@maxheight from sphinxlatexgraphics.sty +% - \savenotes/\spewnotes from sphinxpackagefootnote.sty +% - \ifspx@inframed defined in sphinx.sty +% - \spx@boxes@fcolorbox@setup from sphinxpackageboxes.sty +% +\RequirePackage{framed} +\RequirePackage{needspace} +% Those are required either before or after by sphinx.sty anyhow, but for +% clarity we list them here: +\RequirePackage{sphinxlatexgraphics} +\RequirePackage{sphinxpackagefootnote} +\RequirePackage{sphinxpackageboxes} +% +% Provides: (also in sphinxlatexliterals.sty) +% Only needed here by legacy (deprecated) sphinxlightbox environment. +\providecommand*\sphinxvspacefixafterfrenchlists{% + \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi +} + +% This \dimen register is a legacy relic from Sphinx 1.5 which is used now +% only for sphinxlightbox. It is set in the sphinxadmonition environment. +\newdimen\spx@notice@border +% sphinxlightbox is now also a legacy relic, not used by Sphinx anymore +\newenvironment{sphinxlightbox}{% + \par + \noindent{\color{spx@notice@bordercolor}% + \rule{\linewidth}{\spx@notice@border}}% + \par\nobreak + {\parskip\z@skip\noindent}% + } + {% + % counteract previous possible negative skip (French lists!): + % (we can't cancel that any earlier \vskip introduced a potential pagebreak) + \sphinxvspacefixafterfrenchlists + \nobreak\vbox{\noindent\kern\@totalleftmargin + {\color{spx@notice@bordercolor}% + \rule[\dimexpr.4\baselineskip-\spx@notice@border\relax] + {\linewidth}{\spx@notice@border}}\hss}\allowbreak + }% end of sphinxlightbox environment definition + +% Since 1.5 these environments are named individually sphinxnote, sphinxhint, +% etc... to allow user to redefine them entirely. +% +% The Sphinx definitions for note/hint/important/tip notices were done like +% this, prior to 6.2.0: +% +% \newenvironment{sphinxhint}[1] +% {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}} +% +% Then from 6.2.0 to 7.4.0 (exclusive) a more complex definition decided +% to use either sphinxlightbox or sphinxheavybox according to whether +% some CSS-like options had been used, for example for a background color. +% +% 6.2.0 also added one layer of mark-up via \sphinxnotetitle etc..., because +% the former \sphinxstrong{#1} used a too generic \sphinxstrong. +% +% At 7.4.0, sphinxheavybox environment is default for all types of notices +% and also for the seealso and todo directives. +% +% Code adapted from framed.sty's "snugshade" environment. +% Nesting works (inner frames do not allow page breaks). +% +% At 9.0, avoid admonition title getting separated from contents at a +% page break. +\newcommand\sphinxheavyboxneedspacecommand{\needspace{5\baselineskip}} +\newenvironment{sphinxheavybox}{\par + \sphinxheavyboxneedspacecommand + % (MEMO: it is not a problem here if there is no sphinxShadowColor, + % as it used only if set) + \spx@boxes@fcolorbox@setup{\spx@noticetype}% + % Those are used by sphinxVerbatim if the \ifspx@inframed boolean is true + \setlength{\FrameRule}{0.5\dimexpr\spx@boxes@border@top+\spx@boxes@border@bottom\relax}% + % MEMO: prior to 5.1.0 \FrameSep was determined as 0.6\baselineskip - + % \FrameRule, and there was no possibility for user to adjust padding. + % Then \fcolorbox was used with \fboxrule set to \FrameRule and \fboxsep + % set to \FrameSep. + % The 5.1.0 default calculation of padding parameters maintains PDF output + % identical to legacy behaviour, as long as padding is not set by user. + \setlength{\FrameSep}{0.5\dimexpr\spx@boxes@padding@top+\spx@boxes@padding@bottom\relax}% + % "setup" macro has prepared the \spx@boxes@... dimen registers + \advance\spx@image@maxheight + -\dimexpr\spx@boxes@border@top+\spx@boxes@border@bottom + +\spx@boxes@padding@top+\spx@boxes@padding@bottom + +\baselineskip\relax % will happen again if nested, needed indeed! + % MEMO: the next comment is before boxing was extended to allow padding and + % multiple border-widths, not to mention shadows... + % configure framed.sty's parameters to obtain same vertical spacing + % as for "light" boxes. We need for this to manually insert parskip glue and + % revert a skip done by framed before the frame. + \ltx@ifundefined{OuterFrameSep}{}{\OuterFrameSep\z@skip}% + \vspace{\FrameHeightAdjust} + % copied/adapted from framed.sty's snugshade + % but now using in place of \fcolorbox the Sphinx sophisticated own + \def\FrameCommand##1{% + \hskip\@totalleftmargin + % "setup" macro MUST have been called before + \spx@boxes@fcolorbox{##1}% + \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth + }% + % 6.2.0 adds support for div._box-decoration-break=slice. + % (it is yet undecided if slice style should inhibit a bottom shadow) + \csname ifspx@\spx@noticetype @border@open\endcsname + \def\FirstFrameCommand + {\spx@boxes@fcolorbox@setup@openbottom\FrameCommand}% + \def\MidFrameCommand + {\spx@boxes@fcolorbox@setup@openboth \FrameCommand}% + \def\LastFrameCommand + {\spx@boxes@fcolorbox@setup@opentop \FrameCommand}% + \fi + \savenotes + % use a minipage if we are already inside a framed environment + \ifspx@inframed + \noindent\begin{minipage}{\linewidth} + \else + % handle case where notice is first thing in a list item (or is quoted) + \if@inlabel + \noindent\par\vspace{-\baselineskip} + \else + \vspace{\parskip} + \fi + \fi + \MakeFramed {\spx@inframedtrue + \advance\hsize-\width \@totalleftmargin\z@ \linewidth\hsize + % minipage initialization copied from LaTeX source code. + \@pboxswfalse + \let\@listdepth\@mplistdepth \@mplistdepth\z@ + \@minipagerestore + \@setminipage }% + \color@begingroup % workaround to an upstream framed.sty bug + } + {% + \par\unskip + \color@endgroup % matches the \color@begingroup + \@minipagefalse + \endMakeFramed + \ifspx@inframed\end{minipage}\fi + % set footnotes at bottom of page + \spewnotes + % arrange for similar spacing below frame as for "light" boxes. + \vskip .4\baselineskip + }% end of sphinxheavybox environment definition + +% - Since 1.5 these environments are named individually to allow user to +% redefine them entirely. +% +% - Since 5.1.0, sphinxheavybox is more versatile and four border widths, four +% padding widths, four corner radii, optional shadow, and three colors can all +% be modified via CSS-named alike options. +% +% - Since 6.2.0, also note/hint/important/tip notices can use these options +% and then they go automatically via sphinxheavybox. If only the legacy options +% are used, they keep using sphinxlightbox. +% +% - Since 6.2.0, \sphinxwarningtitle etc... add one level of mark-up (they +% expand to \sphinxstrong{#1} which was former hard-coded mark-up). +% Example: +% \renewcommand{\sphinxwarningtitle}[1]{\textbf{#1}\par\smallskip +% {\color{sphinxwarningBorderColor}\hrule height1pt}\smallskip} +% +% - Since 7.4.0, all types of notices use sphinxheavybox and the default +% for \sphinxstyletitle is mapped to using \sphinxdotitlerowwithicon{} +% +% MEMO: except for the generic admonition directive (which uses "note" type) +% the argument #1 in these environments has a postfixed colon originating +% in Sphinx LaTeX writer legacy code. The +% \sphinxremovefinalcolon utility in sphinxlatexstyletext.sty can be used as +% \sphinxremovefinalcolon{#1} from inside the definitions of +% \sphinxstylenotetitle et al. commands. + +% Important: even prior to 5.1.0 it was not really possible to use directly +% sphinxheavybox if not triggered from sphinxadmonition, because some +% parameters were defined in sphinxadmonition. This meant that the +% sphinxwarning, sphinxcaution etc... environments (defined below) could not +% be used directly in a document, they had to be triggered via +% sphinxadmonition. The sole data since 5.1.0 needed by sphinxheavybox is the +% type of the notice which sphinxadmonition stores into \spx@noticetype. +% +% In order to facilitate recycling or imitation of the sphinx +% environments, 7.4.0 inserts an extra \def\spx@noticetype{} in their +% definitions, so that they can be used independently of sphinxadmonition +% dispatcher. +% +% MEMO: direct usage of these environments does not execute the div._TeXextras +% and div._TexColor code, there are only done from the sphinxadmonition wrapper. +\newenvironment{sphinxnote}[1] + {\def\spx@noticetype{note}\begin{sphinxheavybox}\sphinxstylenotetitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxhint}[1] + {\def\spx@noticetype{hint}\begin{sphinxheavybox}\sphinxstylehinttitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxtip}[1] + {\def\spx@noticetype{tip}\begin{sphinxheavybox}\sphinxstyletiptitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinximportant}[1] + {\def\spx@noticetype{important}\begin{sphinxheavybox}\sphinxstyleimportanttitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxwarning}[1] + {\def\spx@noticetype{warning}\begin{sphinxheavybox}\sphinxstylewarningtitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxcaution}[1] + {\def\spx@noticetype{caution}\begin{sphinxheavybox}\sphinxstylecautiontitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxattention}[1] + {\def\spx@noticetype{attention}\begin{sphinxheavybox}\sphinxstyleattentiontitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxdanger}[1] + {\def\spx@noticetype{danger}\begin{sphinxheavybox}\sphinxstyledangertitle{#1}} + {\end{sphinxheavybox}} +\newenvironment{sphinxerror}[1] + {\def\spx@noticetype{error}\begin{sphinxheavybox}\sphinxstyleerrortitle{#1}} + {\end{sphinxheavybox}} +% The "see also" was quite plain until 7.4.0 as it simply did +% \newenvironment{sphinxseealso}[1]{\sphinxstyleseealsotitle{#1}}{} +% Here we need to manually insert execution of div.seealso_TeX{color,extras} values +\newenvironment{sphinxseealso}[1] + {\def\spx@noticetype{seealso}% + \begin{sphinxheavybox}\sphinxstyleseealsotitle{#1}% + \ifspx@seealso@withtextcolor\color{sphinxseealsoTextColor}\fi + \spx@seealso@TeXextras + } + {\end{sphinxheavybox}} +% There was no sphinxtodo environment until 7.4.0 because sphinx.ext.todo +% generated \begin{sphinxadmonition}{note}{Todo:} mark-up. +\newcounter{sphinxtodo}% to provide targets from todolist directive output +\newenvironment{sphinxtodo}[1] + {\refstepcounter{sphinxtodo}\def\spx@noticetype{todo}% + \begin{sphinxheavybox}\sphinxstyletodotitle{#1}% + \ifspx@todo@withtextcolor\color{sphinxtodoTextColor}\fi + \spx@todo@TeXextras + } + {\end{sphinxheavybox}} + + +% the main dispatch for all types of notices +\newenvironment{sphinxadmonition}[2]{% #1=type, #2=heading + % can't use #1 directly in definition of end part + \def\spx@noticetype {#1}% + % those next three are a remnant of legacy code; they are not used at + % all by sphinxheavybox, and their usage could be disposed of by sphinxlightbox + % but we keep for backward compatibility and also because it may be simpler + % for user redefinitions to employ for example "spx@notice@bgcolor" and not + % the more bulky "sphinx\spx@noticetype BgColor". + \sphinxcolorlet{spx@notice@bordercolor}{sphinx#1BorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinx#1BgColor}% + % At 7.4.0 there are no \spx@@boder macros anymore only top, left, + % bottom, right. For this legacy \spx@notice@border only needed by + % sphinxlightbox (which is not used by own Sphinx environments anymore) + % we thus use here @top + \spx@notice@border \dimexpr\csname spx@#1@border@top\endcsname\relax + % trigger the sphinx environment, #2=heading is passed as argument + \begin{sphinx#1}{#2}% + % MEMO: the heading #2 will be typeset before the next lines are executed + % 6.2.0 support of div._TeX{color,extras} options + \csname ifspx@\spx@noticetype @withtextcolor\endcsname + \color{sphinx\spx@noticetype TextColor}% + \fi + % Other code to be executed at start of contents (after title) + \csname spx@\spx@noticetype @TeXextras\endcsname + } + % workaround some LaTeX "feature" of \end command (i.e. can't use "sphinx#1" here) + {\edef\spx@temp{\noexpand\end{sphinx\spx@noticetype}}\spx@temp} + +% TODO: allow these next three settings to be customized individually. +% This can however already be done at user level by \renewcommand +% inside renew'ed environments sphinxnote, sphinxhint etc... +\newcommand\sphinxtitlerowtoppadding{5pt} +\newcommand\sphinxtitlerowbottompadding{3pt} +\newcommand\sphinxtitlerowaftericonspacecmd{\hskip0.5em\relax} +% 7.4.0 used this longer name: +\newcommand\sphinxdotitlerowwithicon{\sphinxdotitlerow} +\newcommand\sphinxdotitlerow[2]{% #1=type, #2=heading (without final colon) + \begingroup + \kern-\spx@boxes@padding@top + \parskip\z@skip % the \parskip business is a workaround to a vertical + % glue issue showing in LaTeX earlier than 2023-06-01 + \noindent + \kern-\spx@boxes@padding@left % must have been configured by a prior + % \spx@boxes@fcolorbox@setup{} + % inherit settings from the enclosing box and modify what is needed + \spx@boxes@border@top =\z@ + \spx@boxes@border@right =\z@ + \spx@boxes@border@bottom =\z@ + \spx@boxes@border@left =\z@ + \spx@boxes@radius@bottomright@x=\z@ + \spx@boxes@radius@bottomright@y=\z@ + \spx@boxes@radius@bottomleft@x=\z@ + \spx@boxes@radius@bottomleft@x=\z@ + \spx@boxes@padding@top =\sphinxtitlerowtoppadding\relax + \spx@boxes@padding@bottom=\sphinxtitlerowbottompadding\relax + \spx@boxes@withshadowfalse + \sphinxcolorlet{spx@boxes@backgroundcolor}{sphinx#1TtlBgColor}% + \spx@boxes@fcolorbox{% + \parbox[t]{\linewidth}{% 7.4.0 used \makebox, but wrapping of long titles + % is needed for generic admonition or topic box. + \sphinxAtStartPar + % 8.1.0 auto-drops extra space if no icon + \sbox\z@{\@nameuse{sphinx#1TtlIcon}}% + \ifdim\wd\z@>\z@ + \textcolor{sphinx#1TtlFgColor}{% + \@nameuse{sphinx#1TtlIcon}% + % The next macro is located here for legacy reasons of earlier + % functioning of sphinx.sty now removed \spx@faIcon macro. + % We leave it here now although it could be moved to after + % the closing brace. + \sphinxtitlerowaftericonspacecmd + }% + \fi + \sphinxstrong{#2}% + \strut + \par + }% + }% + \kern-\spx@boxes@padding@right + \par + \endgroup + \vskip-\parskip + \kern\spx@boxes@padding@top +} + +% #1 holds the localized name of the notice, postfixed with a colon. +% \sphinxremovefinalcolon{#1} will typeset #1 without the colon. +% Legacy definitions (done in sphinxlatexstyletext.sty) were all using +% a boring plain \sphinxstrong{#1}, now we use a coloured title row. +\newcommand\sphinxstylenotetitle [1]{\sphinxdotitlerow{note}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstylehinttitle [1]{\sphinxdotitlerow{hint}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyleimportanttitle[1]{\sphinxdotitlerow{important}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyletiptitle [1]{\sphinxdotitlerow{tip}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstylewarningtitle [1]{\sphinxdotitlerow{warning}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstylecautiontitle [1]{\sphinxdotitlerow{caution}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyleattentiontitle[1]{\sphinxdotitlerow{attention}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyledangertitle [1]{\sphinxdotitlerow{danger}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyleerrortitle [1]{\sphinxdotitlerow{error}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyleseealsotitle [1]{\sphinxdotitlerow{seealso}{\sphinxremovefinalcolon{#1}}} +\newcommand\sphinxstyletodotitle [1]{\sphinxdotitlerow{todo}{\sphinxremovefinalcolon{#1}}} +% +% A utility to remove a final colon. Removing last token is not easy in +% LaTeX, and there are additional complications: +% - some languages will make the : "active" in document body, +% - the generic admonition ends up using "note", so for \sphinxnotetitle to +% use it safely, the utility has to allow an input not having any final colon. +% - a bit far-fetched but maybe there is more than one colon inside the input +% (possible from a generic admonition title). +% Hence the scary code. +\newcommand\sphinxremovefinalcolon[1]{% #1 is the "active" : TeX token +% Prior to 7.4.0 this was defined with \protected\def but we do not +% see what usefulness this could have. +\renewcommand\sphinxremovefinalcolon[1]{% + % complications due to : possibly "active" + \begingroup\ifnum\catcode`:=\active + \def\x####1#1\relax{####1}% + \else\def\x####1:\relax{####1}\fi + \expandafter\endgroup\x##1\relax + % trick to let \x work also if input ##1 has no ending colon + \@gobblefour#1\relax:\relax\relax\relax + }% +}% end of wrapper to inject active : +\begingroup\catcode`:\active\expandafter\endgroup\sphinxremovefinalcolon: + +\endinput diff --git a/build/latex/sphinxlatexcontainers.sty b/build/latex/sphinxlatexcontainers.sty new file mode 100644 index 0000000..012d9ee --- /dev/null +++ b/build/latex/sphinxlatexcontainers.sty @@ -0,0 +1,22 @@ +%% CONTAINER DIRECTIVES +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexcontainers}[2021/05/03 containers] + +% The purpose of this file is to provide a dummy environment sphinxclass which +% will be inserted for each class in each container directive. The class name +% will be passed as the argument to the environment. +% +% For a class foo, the user can define customised handling of that class by +% defining the sphinxclassfoo LaTeX environment. + +\newenvironment{sphinxuseclass}[1]{% + \def\sphinxClassFunctionName{sphinxclass#1}% + \ltx@ifundefined{\sphinxClassFunctionName}% + {}% undefined so do nothing + {\expandafter\begin\expandafter{\sphinxClassFunctionName}}% +}{% + \ltx@ifundefined{\sphinxClassFunctionName}% + {}% we did nothing so we keep doing nothing + {\expandafter\end\expandafter{\sphinxClassFunctionName}}% +}% diff --git a/build/latex/sphinxlatexgraphics.sty b/build/latex/sphinxlatexgraphics.sty new file mode 100644 index 0000000..f0c7c25 --- /dev/null +++ b/build/latex/sphinxlatexgraphics.sty @@ -0,0 +1,123 @@ +%% GRAPHICS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexgraphics}[2024/08/13 v8.1.0 graphics] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - macros: +% +% - \sphinxfigcaption +% - \sphinxincludegraphics +% +% - environments: +% +% - sphinxfigure-in-table +% +% May change: +% +% - \sphinxcaption (at begin document) +% +% Also provides: +% +% - \sphinxsafeincludegraphics (default of \sphinxincludegraphics since 2.0) +% - \spx@image@maxheight dimension (used by sphinxlatexadmonitions.sty) +% - \spx@image@box scratch box register (also used by sphinxlatexliterals.sty) +% +% Requires: +% \RequirePackage{graphicx}% done in sphinx.sty +\RequirePackage{amstext}% needed for \firstchoice@true(false) + +% \sphinxincludegraphics resizes images larger than the TeX \linewidth (which +% is adjusted in indented environments), or taller than a certain maximal +% height (usually \textheight and this is reduced in the environments which use +% framed.sty to avoid infinite loop if image too tall). +% +% In case height or width options are present the rescaling is done +% (since 2.0), in a way keeping the width:height ratio either native from +% image or from the width and height options if both were present. +% +\newdimen\spx@image@maxheight +\AtBeginDocument{\spx@image@maxheight\textheight} + +% box scratch register +\newbox\spx@image@box +\newcommand*{\sphinxsafeincludegraphics}[2][]{% + % #1 contains possibly width=, height=, but no scale= since 1.8.4 + \setbox\spx@image@box\hbox{\includegraphics[#1,draft]{#2}}% + \in@false % use some handy boolean flag + \ifdim \wd\spx@image@box>\linewidth + \in@true % flag to remember to adjust options and set box dimensions + % compute height which results from rescaling width to \linewidth + % and keep current aspect ratio. multiply-divide in \numexpr uses + % temporarily doubled precision, hence no overflow. (of course we + % assume \ht is not a few sp's below \maxdimen...(about 16384pt). + \edef\spx@image@rescaledheight % with sp units + {\the\numexpr\ht\spx@image@box + *\linewidth/\wd\spx@image@box sp}% + \ifdim\spx@image@rescaledheight>\spx@image@maxheight + % the rescaled height will be too big, so it is height which decides + % the rescaling factor + \def\spx@image@requiredheight{\spx@image@maxheight}% dimen register + \edef\spx@image@requiredwidth % with sp units + {\the\numexpr\wd\spx@image@box + *\spx@image@maxheight/\ht\spx@image@box sp}% + % TODO: decide if this commented-out block could be needed due to + % rounding in numexpr operations going up + % \ifdim\spx@image@requiredwidth>\linewidth + % \def\spx@image@requiredwidth{\linewidth}% dimen register + % \fi + \else + \def\spx@image@requiredwidth{\linewidth}% dimen register + \let\spx@image@requiredheight\spx@image@rescaledheight% sp units + \fi + \else + % width is ok, let's check height + \ifdim\ht\spx@image@box>\spx@image@maxheight + \in@true + \edef\spx@image@requiredwidth % with sp units + {\the\numexpr\wd\spx@image@box + *\spx@image@maxheight/\ht\spx@image@box sp}% + \def\spx@image@requiredheight{\spx@image@maxheight}% dimen register + \fi + \fi % end of check of width and height + \ifin@ + \setbox\spx@image@box + \hbox{\includegraphics + [#1,% contains only width and/or height which are overruled next + % but in future may contain page=N hence must be kept + width=\spx@image@requiredwidth,height=\spx@image@requiredheight]% + {#2}}% + % \includegraphics does not set box dimensions to the exactly + % requested ones, see https://github.com/latex3/latex2e/issues/112 + \wd\spx@image@box\spx@image@requiredwidth + \ht\spx@image@box\spx@image@requiredheight + \leavevmode\box\spx@image@box + \else + % here we do not modify the options, no need to adjust width and height + % on output, they will be computed exactly as with "draft" option + \setbox\spx@image@box\box\voidb@x % clear memory + \includegraphics[#1]{#2}% + \fi +}% +% Use the "safe" one by default (2.0) +\def\sphinxincludegraphics{\sphinxsafeincludegraphics} + + +%% FIGURE IN TABLE +% +\newenvironment{sphinxfigure-in-table}[1][\linewidth]{% + \def\@captype{figure}% + \sphinxsetvskipsforfigintablecaption + \begin{minipage}{#1}% +}{\end{minipage}} +% tabulary expands twice contents, we need to prevent double counter stepping +\newcommand*\sphinxfigcaption + {\ifx\equation$%$% this is trick to identify tabulary first pass + \firstchoice@false\else\firstchoice@true\fi + \spx@originalcaption } +\newcommand*\sphinxsetvskipsforfigintablecaption + {\abovecaptionskip\smallskipamount + \belowcaptionskip\smallskipamount} + +\endinput diff --git a/build/latex/sphinxlatexindbibtoc.sty b/build/latex/sphinxlatexindbibtoc.sty new file mode 100644 index 0000000..052d31e --- /dev/null +++ b/build/latex/sphinxlatexindbibtoc.sty @@ -0,0 +1,69 @@ +%% INDEX, BIBLIOGRAPHY, APPENDIX, TABLE OF CONTENTS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexindbibtoc}[2021/01/27 index, bib., toc] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - environments: (backup defaults or get redefined) +% +% - sphinxtheindex (direct mark-up or via python.ist or sphinx.xdy) +% - sphinxthebibliography +% +% - macros: (defines defaults) +% +% - \sphinxmaketitle +% - \sphinxtableofcontents +% - \sphinxnonalphabeticalgroupname +% - \sphinxsymbolsname +% - \sphinxnumbersname +% - \sphinxcite +% +% Requires: +\RequirePackage{makeidx} + +% fix the double index and bibliography on the table of contents +% in jsclasses (Japanese standard document classes) +\ifx\@jsc@uplatextrue\@undefined\else + \renewenvironment{sphinxtheindex} + {\cleardoublepage\phantomsection + \begin{theindex}} + {\end{theindex}} + + \renewenvironment{sphinxthebibliography}[1] + {\cleardoublepage% \phantomsection % not needed here since TeXLive 2010's hyperref + \begin{thebibliography}{#1}} + {\end{thebibliography}} +\fi + +% disable \@chappos in Appendix in pTeX +\ifx\kanjiskip\@undefined\else + \let\py@OldAppendix=\appendix + \renewcommand{\appendix}{ + \py@OldAppendix + \gdef\@chappos{} + } +\fi + +% make commands known to non-Sphinx document classes +\providecommand*{\sphinxmaketitle}{\maketitle} +\providecommand*{\sphinxtableofcontents}{\tableofcontents} +\ltx@ifundefined{sphinxthebibliography} + {\newenvironment + {sphinxthebibliography}{\begin{thebibliography}}{\end{thebibliography}}% + } + {}% else clause of \ltx@ifundefined +\ltx@ifundefined{sphinxtheindex} + {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}}% + {}% else clause of \ltx@ifundefined + +% for usage with xindy: this string gets internationalized in preamble +\newcommand*{\sphinxnonalphabeticalgroupname}{} +% redefined in preamble, headings for makeindex produced index +\newcommand*{\sphinxsymbolsname}{} +\newcommand*{\sphinxnumbersname}{} + +\protected\def\sphinxcite{\cite} + + +\endinput diff --git a/build/latex/sphinxlatexlists.sty b/build/latex/sphinxlatexlists.sty new file mode 100644 index 0000000..4db3af2 --- /dev/null +++ b/build/latex/sphinxlatexlists.sty @@ -0,0 +1,131 @@ +%% ALPHANUMERIC LIST ITEMS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexlists}[2021/12/20 lists] + +% Provides support for this output mark-up from Sphinx latex writer: +% - \sphinxsetlistlabels +% - \sphinxlineitem +% and for the maxlistdepth key of sphinxsetup +% Dependencies: the \spx@opt@maxlistdepth from sphinx.sty + +% We need some helpers macros +\newtoks\spx@lineitemlabel +\long\def\sphinx@gobto@sphinxlineitem#1\sphinxlineitem{} +% TeX/LaTeX has no (easy to use) built-in "peek-ahead" mechanism, but +% we would like to know if next token is another \sphinxlineitem (this +% can happen in glossary entries with multiple terms for same definition) +% so we simply grab next token (assuming it is not {tokens} originally) +\newcommand\sphinxlineitem[2]{% + % safe test of whether #2 is \sphinxlineitem + \sphinx@gobto@sphinxlineitem#2\@gobbletwo\sphinxlineitem\unless + \iftrue + % case with sphinxlineitem immediately followed by another \sphinxlineitem: + % accumulate successive terms until actual definition or sub-list is found + \spx@lineitemlabel\expandafter{\the\spx@lineitemlabel\strut#1\\}% + \else + % now issue the \item command with possibly multi-line contents + % these weird incantations with \kern are related to how LaTeX + % handles \item generally + \item[\kern\labelwidth\kern-\itemindent\kern-\leftmargin + {\parbox[t]{\dimexpr\linewidth+\leftmargin\relax}{% + \raggedright + \the\spx@lineitemlabel% accumulated terms before this one, CR separated + \strut#1}}% due to LaTeX internals no \par token allowed here, + % but the \parbox will insert one tacitly at end + \kern-\labelsep]% + \spx@lineitemlabel{}% + % this causes the label to be typeset (filling up the line), clearing up + % things in case a nested list follows. + \leavevmode + \fi #2% +}% + + +\newcommand\sphinxsetlistlabels[5] +{% #1 = style, #2 = enum, #3 = enumnext, #4 = prefix, #5 = suffix + % #2 and #3 are counters used by enumerate environment e.g. enumi, enumii. + % #1 is a macro such as \arabic or \alph + % prefix and suffix are strings (by default empty and a dot). + \@namedef{the#2}{#1{#2}}% + \@namedef{label#2}{#4\@nameuse{the#2}#5}% + \@namedef{p@#3}{\@nameuse{p@#2}#4\@nameuse{the#2}#5}% +}% + + +%% MAXLISTDEPTH +% +% remove LaTeX's cap on nesting depth if 'maxlistdepth' key used. +% This is a hack, which works with the standard classes: it assumes \@toodeep +% is always used in "true" branches: "\if ... \@toodeep \else .. \fi." + +% will force use the "false" branch (if there is one) +\def\spx@toodeep@hack{\fi\iffalse} + +% do nothing if 'maxlistdepth' key not used or if package enumitem loaded. +\ifnum\spx@opt@maxlistdepth=\z@\expandafter\@gobbletwo\fi +\AtBeginDocument{% +\@ifpackageloaded{enumitem}{\remove@to@nnil}{}% + \let\spx@toodeepORI\@toodeep + \def\@toodeep{% + \ifnum\@listdepth<\spx@opt@maxlistdepth\relax + \expandafter\spx@toodeep@hack + \else + \expandafter\spx@toodeepORI + \fi}% +% define all missing \@list... macros + \count@\@ne + \loop + \ltx@ifundefined{@list\romannumeral\the\count@} + {\iffalse}{\iftrue\advance\count@\@ne}% + \repeat + \loop + \ifnum\count@>\spx@opt@maxlistdepth\relax\else + \expandafter\let + \csname @list\romannumeral\the\count@\expandafter\endcsname + \csname @list\romannumeral\the\numexpr\count@-\@ne\endcsname + % workaround 2.6--3.2d babel-french issue (fixed in 3.2e; no change needed) + \ltx@ifundefined{leftmargin\romannumeral\the\count@} + {\expandafter\let + \csname leftmargin\romannumeral\the\count@\expandafter\endcsname + \csname leftmargin\romannumeral\the\numexpr\count@-\@ne\endcsname}{}% + \advance\count@\@ne + \repeat +% define all missing enum... counters and \labelenum... macros and \p@enum.. + \count@\@ne + \loop + \ltx@ifundefined{c@enum\romannumeral\the\count@} + {\iffalse}{\iftrue\advance\count@\@ne}% + \repeat + \loop + \ifnum\count@>\spx@opt@maxlistdepth\relax\else + \newcounter{enum\romannumeral\the\count@}% + \expandafter\def + \csname labelenum\romannumeral\the\count@\expandafter\endcsname + \expandafter + {\csname theenum\romannumeral\the\numexpr\count@\endcsname.}% + \expandafter\def + \csname p@enum\romannumeral\the\count@\expandafter\endcsname + \expandafter + {\csname p@enum\romannumeral\the\numexpr\count@-\@ne\expandafter + \endcsname\csname theenum\romannumeral\the\numexpr\count@-\@ne\endcsname.}% + \advance\count@\@ne + \repeat +% define all missing labelitem... macros + \count@\@ne + \loop + \ltx@ifundefined{labelitem\romannumeral\the\count@} + {\iffalse}{\iftrue\advance\count@\@ne}% + \repeat + \loop + \ifnum\count@>\spx@opt@maxlistdepth\relax\else + \expandafter\let + \csname labelitem\romannumeral\the\count@\expandafter\endcsname + \csname labelitem\romannumeral\the\numexpr\count@-\@ne\endcsname + \advance\count@\@ne + \repeat + \PackageInfo{sphinx}{maximal list depth extended to \spx@opt@maxlistdepth}% +\@gobble\@nnil +} + +\endinput diff --git a/build/latex/sphinxlatexliterals.sty b/build/latex/sphinxlatexliterals.sty new file mode 100644 index 0000000..ef40cf6 --- /dev/null +++ b/build/latex/sphinxlatexliterals.sty @@ -0,0 +1,1229 @@ +%% LITERAL BLOCKS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexliterals}[2025/12/26 v9.1.0 code-blocks and parsed literals] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - macros: +% - \sphinxLiteralBlockLabel +% - \sphinxSetupCaptionForVerbatim +% - \sphinxSetupCodeBlockInFootnote +% - \sphinxhref +% - \sphinxnolinkurl +% - \sphinxresetverbatimhllines +% - \sphinxunactivateextrasandspace +% - \sphinxupquote +% - \sphinxurl +% +% - environments: +% - sphinxVerbatim +% - sphinxLongVerbatimFirst +% - sphinxLongVerbatimMiddle +% - sphinxLongVerbatimLast +% - sphinxVerbatimintable +% - sphinxalltt +% +% Dependency: +% +% - hyperref (for \phantomsection and \capstart) (loaded later) +% +% Executes \RequirePackage for: +% +% - framed +% - fancyvrb +% - alltt +% - upquote +% - needspace +% - sphinxpackageboxes +\RequirePackage{sphinxpackageboxes} +% 7.4.0 removes unneeded usage of \spx@boxes@border + +% Also in sphinxlatexadmonitions.sty: +% This is a workaround to a "feature" of babel-french latex package, +% which causes bad vertical spacing when a literal block follows a list. +% Due to the conditional here, this should be usable generally. +\providecommand*\sphinxvspacefixafterfrenchlists{% + \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi +} + +% For framing allowing pagebreaks +\RequirePackage{framed} +% For source code +% MEMO: fancyvrb is used mainly to +% 1- control horizontal and vertical spacing +% 2- optional line numbering +% 3- optional line emphasizing +% 4- while still allowing expansion of Pygments latex mark-up +% Other aspects such as framing, caption handling, codeline wrapping are +% added on top of it. +% Perhaps we could cease using fancyvrb and implement 1, 2, 3, 4 by own pure +% LaTeX code. But dropping fancyvrb and keeping its native features and those +% we added by hacking into it would require a significant effort. +\RequirePackage{fancyvrb} +% Next line is in order to let TAB characters (ascii 9) obey tab stops, +% MEMO: attow (2025/12/26), a TAB can not be found inside a code-block +% rendered by sphinxVerbatim because it has been replaced earlier by a +% fixed number of spaces, as applies also to HTML output (#14065). +% (default: 8 spaces per TAB). But this is not the case for contents +% inserted via a literalinclude, and next line will have an impact on +% TABs. cf #13656, #14064, #14065. +\fvset{obeytabs} +% MEMO: with the above option, fancyvrb executes at each code-block some +% initialization code which does in particular two things: +% - make TABs act according to something called \FV@TrueTab, +% - make some wrapper of each code line, called \FV@ObeyTabs, +% act like something called \FV@@ObeyTabs and thus provide +% the correct context for \FV@TrueTab. +% We need a special variant of \FV@@ObeyTabs for compatibility with +% our added feature of wrapping long code lines. Here it is: +\def\FV@@ObeyTabs#1{\setbox\FV@TabBox=\hbox{#1}\unhbox\FV@TabBox} +% In code further down this file we use \FV@ObeyTabs, not \FV@@ObeyTabs, +% knowing that the former is mapper to the latter. At some locations +% the argument #1 is already a typeset box and nothing happens. One of +% the two main locations where there will be an effect is the occurrence +% in \spx@verb@@PreProcessLine. +% +% Tab stops are located every 8 positions as per fancyvrb's default setting +% for its tabsize option. However, fancyvrb has a bug/limitation, and its +% \FV@TrueTab acting inside the #1 above can work only at "top level", +% i.e. breakage (or rather loss of contents) happens if the TAB character +% (hence \FV@TrueTab) is located in the (second) argument of \PYG. +% +% Hence, we prepare a "safe" variant, which is the one which will be used if +% found in the second argument of \PYG. For how this ends up into \PYG, see +% sphinx.sty. +\def\spx@FV@Tab{\allowbreak\hbox to\FancyVerbTabSize\fontdimen2\font{\hss\FV@TabChar}} +% MEMO: \FV@TabChar does nothing without option showtabs (which we do not +% use). With the option showtabs, it would draw something similar to +% a ->| at the end of the inserted horizontal whitespace. + +% For parsed-literal blocks. +\RequirePackage{alltt} +% Display "real" single quotes in literal blocks. +\RequirePackage{upquote} +% Skip to next page if not enough space at bottom +\RequirePackage{needspace} + +% Based on use of "fancyvrb.sty"'s Verbatim. +% - with framing allowing page breaks ("framed.sty") +% - with breaking of long lines (exploits Pygments mark-up), +% - with possibly of a top caption, non-separable by pagebreak. +% - and usable inside tables or footnotes ("sphinxpackagefootnote.sty"). + +% for emphasizing lines +\define@key{FV}{hllines}{\def\sphinx@verbatim@checkifhl##1{\in@{, ##1,}{#1}}} +% sphinxVerbatim must be usable by third party without requiring hllines set-up +\def\sphinxresetverbatimhllines{\def\sphinx@verbatim@checkifhl##1{\in@false}} +\sphinxresetverbatimhllines + +% Prior to Sphinx 1.5, \Verbatim and \endVerbatim were modified by Sphinx. +% The aliases defined here are used in sphinxVerbatim environment and can +% serve as hook-points with no need to modify \Verbatim itself. +\let\OriginalVerbatim \Verbatim +\let\endOriginalVerbatim\endVerbatim + +% for captions of literal blocks +% at start of caption title +\newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock} +% this will be overwritten in document preamble by Babel translation +\newcommand*{\literalblockname}{Listing } +% file extension needed for \caption's good functioning, the file is created +% only if a \listof{literalblock}{foo} command is encountered, which is +% analogous to \listoffigures, but for the code listings (foo = chosen title.) +\newcommand*{\ext@literalblock}{lol} + +% if forced use of minipage encapsulation is needed (e.g. table cells) +\newif\ifsphinxverbatimwithminipage \sphinxverbatimwithminipagefalse + +% Framing macro for use with framed.sty's \FrameCommand +% MEMO: the sophisticated code in \spx@fcolorbox/\spx@CustomFBox +% is here for good reasons +% - be responsive to indented list environments in the manner of +% the "framed" (\fbox) and "shaded" (\colorbox) environments of +% framed.sty; indeed code here is an evolution related to \fcolorbox +% - attach non-detachable continuation hints above/below frame +% - draw the frame and fill the background color in a manner avoiding +% problems in some pdf viewers +% - do background coloring differently from color.sty/xcolor.sty macros +% (even core internal ones) to work around issues at page breaks +% as the framed contents are split into chunks with possibly unpaired +% "color push" or "color pop" +% About the produced output: +% - it obeys current indentation, +% - frame with 4 padding parameters and 4 border-width parameters +% - the contents use the full available text width, limited by indentation, +% - #1 = will be typeset above frame, in a non detachable way, +% - #2 = will be typeset below frame, in a non detachable way, +% - #3 = will be typeset within the frame. +% #1 and #2 are expected to be already typeset \hbox'es. +% #3 are the contents, and in the context of usage of fancyvrb+framed, +% it will arrive here already transformed into horizontal boxes, +% interline penalties and glues. +% +\long\def\spx@verb@FrameCommand #1#2#3{% + % The \spx@verb@boxes@fcolorbox@setup MUST have been executed beforehand. + % These \hskips are for fancyvrb.sty measuring and will make the + % framing "adapt" to an indented context. + \hskip\@totalleftmargin + \hskip-\spx@boxes@border@left\hskip-\spx@boxes@padding@left + \spx@verb@fcolorbox {#1}{#2}{#3}% + \hskip-\spx@boxes@padding@right\hskip-\spx@boxes@border@right + \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth +}% +\long\def\spx@verb@fcolorbox #1#2#3{% + % The \spx@verb@boxes@fcolorbox@setup MUST have been executed beforehand. +% + % MEMO: in the context of framed.sty this will always expand inside some + % \hbox isolated from other code, so we can use \box\z@, \box\tw@,... + % with no need of extra group. +% + % MEMO: this code was originally using \color@b@x but the latter has + % problematic features regarding color in a context like here where #3 + % may contain an unbalanced "color push". +% + \setbox\z@\hbox{#3}% + \edef\spx@verb@fcolorbox@width@sp + {\number\dimexpr\wd\z@+\spx@boxes@border@left + +\spx@boxes@padding@left + +\spx@boxes@padding@right + +\spx@boxes@border@right\relax sp}% + \vbox{#1% continuation hint attached above frame, uses \spx@verb@fcolorbox@width@sp + % the boxes@fcolorbox constructs an \hbox with bbox containing the border + % \spx@verb@boxes@fcolorbox@setup MUST have been executed beforehand. + \spx@boxes@fcolorbox{\box\z@}% + % This \nointerlineskip to maintain legacy spacing when a \hrule was + % formerly last prior item in vertical list. TODO: remove this at 6.0.0 ? + \nointerlineskip + #2% continuation hint attached below frame, uses \spx@verb@fcolorbox@width@sp + }% end of \vbox +}% +\def\spx@verb@fcolorbox@put@c#1{% hide width from framed.sty measuring + \moveright.5\dimexpr\spx@verb@fcolorbox@width@sp\hb@xt@\z@{\hss#1\hss}% +}% +\def\spx@verb@fcolorbox@put@r#1{% right align with contents, width hidden + \moveright\dimexpr\spx@verb@fcolorbox@width@sp-% + \spx@boxes@padding@right-% + \spx@boxes@border@right\hb@xt@\z@{\hss#1}% +}% +\def\spx@verb@fcolorbox@put@l#1{% left align with contents, width hidden + \moveright\dimexpr\spx@boxes@border@left+% + \spx@boxes@padding@left\hb@xt@\z@{#1\hss}% +}% +% +\def\sphinxVerbatim@Continued{% + \csname spx@verb@fcolorbox@put@\spx@opt@verbatimcontinuedalign\endcsname + {{\normalcolor\sphinxstylecodecontinued\literalblockcontinuedname}}% +}% +\def\sphinxVerbatim@Continues{% + \csname spx@verb@fcolorbox@put@\spx@opt@verbatimcontinuesalign\endcsname + {{\normalcolor\sphinxstylecodecontinues\literalblockcontinuesname}}% +}% +\def\sphinxVerbatim@Title{% + \spx@verb@fcolorbox@put@c{\unhcopy\sphinxVerbatim@TitleBox}% +}% +\let\sphinxVerbatim@Before\@empty +\let\sphinxVerbatim@After\@empty +% Defaults are redefined in document preamble according to language +\newcommand*\literalblockcontinuedname{continued from previous page}% +\newcommand*\literalblockcontinuesname{continues on next page}% +% +\def\sphinxVerbatim@FrameCommand{% + \spx@verb@FrameCommand\sphinxVerbatim@Before\sphinxVerbatim@After +}% +\def\sphinxVerbatim@FirstFrameCommand{% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@openbottom + \fi + \spx@verb@FrameCommand\sphinxVerbatim@Before\sphinxVerbatim@Continues +}% +\def\sphinxVerbatim@MidFrameCommand{% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@openboth + \fi + \spx@verb@FrameCommand\sphinxVerbatim@Continued\sphinxVerbatim@Continues +}% +\def\sphinxVerbatim@LastFrameCommand{% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@opentop + \fi + \spx@verb@FrameCommand\sphinxVerbatim@Continued\sphinxVerbatim@After +}% +% +\def\spx@verb@boxes@fcolorbox@setup{% + % Prepares usage of \spx@boxes@fcolorbox + % Extras to remap legacy color names VerbatimBorderColor and VerbatimColor + % to a common naming scheme with admonitions (and topic directive), as + % expected by \spx@boxes@fcolorbox@setup from sphinxpackageboxes.sty. + \sphinxcolorlet{sphinxpreBorderColor}{VerbatimBorderColor}% + \sphinxcolorlet{sphinxpreBgColor}{VerbatimColor}% + % This VerbatimShadowColor is not a legacy name nor user documented but is + % an outcome of sphinx.sty batch definitions for CSS option support. + \sphinxcolorlet{sphinxpreShadowColor}{VerbatimShadowColor}% + \spx@boxes@fcolorbox@setup{pre}% + \ifspx@opt@verbatimwithframe + \else + \spx@boxes@border@top\z@ + \spx@boxes@border@right\z@ + \spx@boxes@border@bottom\z@ + \spx@boxes@border@left\z@ + % MEMO: rounded corners still make sense in presence of a background + % color, so we do not force the fcolorbox@rectangle here + \fi +}% + +% For linebreaks inside Verbatim environment from package fancyvrb. +\newbox\sphinxcontinuationbox +\newbox\sphinxvisiblespacebox +\newcommand*\sphinxafterbreak {\copy\sphinxcontinuationbox} + +% Take advantage of the already applied Pygments mark-up to insert +% potential linebreaks for TeX processing. +% {, <, #, %, $, ' and ": go to next line. +% _, }, ^, &, >, -, ~, and \: stay at end of broken line. +% Use of \textquotesingle for straight quote. +% FIXME: convert this to package options ? +% MEMO: "beforelist" and "afterlist" hold no relation with lists, +% they are just "\do lists" in the inherited TeX sense. +\newcommand*\sphinxbreaksbeforelist {% + \do\PYGZob\{\do\PYGZlt\<\do\PYGZsh\#\do\PYGZpc\%% {, <, #, %, + \do\PYGZdl\$\do\PYGZdq\"% $, " + \def\PYGZsq + {\discretionary{}{\sphinxafterbreak\textquotesingle}{\textquotesingle}}% ' +} +\newcommand*\sphinxbreaksafterlist {% + \do\PYGZus\_\do\PYGZcb\}\do\PYGZca\^\do\PYGZam\&% _, }, ^, &, + \do\PYGZgt\>\do\PYGZhy\-\do\PYGZti\~% >, -, ~ + \do\PYGZbs\\% \ +} +\newcommand*\sphinxbreaksatspecials {% + \def\do##1##2% + {\def##1{\discretionary{}{\sphinxafterbreak\char`##2}{\char`##2}}}% + \sphinxbreaksbeforelist + \def\do##1##2% + {\def##1{\discretionary{\char`##2}{\sphinxafterbreak}{\char`##2}}}% + \sphinxbreaksafterlist +} + +\def\sphinx@verbatim@nolig@list {\do \`}% +% Some characters . , ; ? ! / are neither pygmentized nor "tex-escaped". +% This macro makes them "active" and they will insert potential linebreaks. +% Not compatible with math mode (cf \sphinxunactivateextras, which uses +% these lists to make sure activated characters get de-activated). +\newcommand*\sphinxbreaksbeforeactivelist {}% none +\newcommand*\sphinxbreaksafteractivelist {\do\.\do\,\do\;\do\?\do\!\do\/} +\newcommand*\sphinxbreaksviaactive {% + \def\do##1{\lccode`\~`##1% + \lowercase{\def~}{\discretionary{}{\sphinxafterbreak\char`##1}{\char`##1}}% + \catcode`##1\active}% + \sphinxbreaksbeforeactivelist + \def\do##1{\lccode`\~`##1% + \lowercase{\def~}{\discretionary{\char`##1}{\sphinxafterbreak}{\char`##1}}% + \catcode`##1\active}% + \sphinxbreaksafteractivelist + \lccode`\~`\~ + % visit_desc_name will insert non TeX-escaped ~ in the source + \let~\spx@verbatim@space +} + +% If the linebreak is at a space, the latter will be displayed as visible +% space at end of first line, and a continuation symbol starts next line. +\def\spx@verbatim@space {% + \nobreak\hskip\z@skip + \discretionary{\copy\sphinxvisiblespacebox}{\sphinxafterbreak} + {\kern\fontdimen2\font}% +}% + +% if the available space on page is less than \literalblockneedspace, insert pagebreak +\newcommand{\sphinxliteralblockneedspace}{5\baselineskip} +\newcommand{\sphinxliteralblockwithoutcaptionneedspace}{1.5\baselineskip} +% The title (caption) is specified from outside as macro \sphinxVerbatimTitle. +% \sphinxVerbatimTitle is reset to empty after each use of Verbatim. +\let\sphinxVerbatimTitle\@empty +% This box to typeset the caption before framed.sty multiple passes for framing. +\newbox\sphinxVerbatim@TitleBox +% This box to measure contents if nested as inner \MakeFramed requires then +% minipage encapsulation but too long contents then break outer \MakeFramed +\newbox\sphinxVerbatim@ContentsBox +% Holder macro for labels of literal blocks. Set-up by LaTeX writer. +\newcommand*\sphinxLiteralBlockLabel {} +\newcommand*\sphinxSetupCaptionForVerbatim [1] +{% + \sphinxvspacefixafterfrenchlists + \needspace{\sphinxliteralblockneedspace}% +% insert a \label via \sphinxLiteralBlockLabel +% reset to normal the color for the literal block caption + \def\sphinxVerbatimTitle + {\py@NormalColor\sphinxcaption{\sphinxLiteralBlockLabel #1}}% +} +\newcommand*\sphinxSetupCodeBlockInFootnote {% + \fvset{fontsize=\footnotesize}\let\caption\sphinxfigcaption + \sphinxverbatimwithminipagetrue % reduces vertical spaces + % we counteract (this is in a group) the \@normalsize from \caption + \let\normalsize\footnotesize\let\@parboxrestore\relax + \def\spx@abovecaptionskip{\sphinxverbatimsmallskipamount}% +} +\newcommand*{\sphinxverbatimsmallskipamount}{\smallskipamount} +% serves to implement line highlighting +% +% HTML interprets the argument of :emphasize-lines: as referring to effective +% line numbers in output (i.e. first line is always associated with number 1 +% even though the actual printed line number, or the original line number in +% the source may differ, due to setting of :lineno-start:). This is why we do +% not use here \c@FancyVerbLine, but resort to \FV@CodeLineNo, for PDF output +% to follow same rules as HTML. +\newcommand\sphinxFancyVerbFormatLine[1]{% + \expandafter\sphinx@verbatim@checkifhl\expandafter{\the\FV@CodeLineNo}% + \ifin@ + \sphinxVerbatimHighlightLine{#1}% + \else + \sphinxVerbatimFormatLine{#1}% + \fi +}% +% This complicates matters for the LongVerbatim environment added at 9.1.0: we +% need a dedicated variant, working in sync with mark-up from the LaTeX writer +% for initialization/reset of \sphinxverbatimfirstnumber. We could extend +% this to be used with legacy Verbatim (used code-blocks of up to 500 code +% lines), but to minimize risks of overlooked consequences we, for time being, +% keep the legacy code as is. +\newcommand\sphinxLongVerbatimFancyVerbFormatLine[1]{% + \expandafter\sphinx@verbatim@checkifhl\expandafter{% + \the\numexpr\c@FancyVerbLine - \sphinxverbatimfirstnumber + \@ne + }% + \ifin@ + \sphinxVerbatimHighlightLine{#1}% + \else + \sphinxVerbatimFormatLine{#1}% + \fi +}% +\let\spx@original@set@color\set@color +\newcommand\sphinxVerbatimHighlightLine[1]{% +% This is morally a \colorbox (with a \fboxsep which would be 0pt) +% but some issues of potential colour disappearance at pagebreaks +% require workaround such as the one done here. + \leavevmode + % MEMO: usage of original \colorbox would insert a \set@color here + % and this then places a "color pop" at the end of the \box\z@. + % But this could pair erroneously with an unmatched "color push" + % as #1 is maybe only a part (already hboxed) of a codeline + % if (default) verbatimwrapslines=true + % (cf \spx@verb@@PreProcessLine; refs: #8686) + % MEMO: formerly we did something with \fboxsep in relation to the LaTeX + % bug graphics/4524 for \colorbox, but as we don't use \colorbox... + \setbox\z@\hb@xt@\linewidth{\FV@ObeyTabs{\strut#1}\hss}% + % MEMO: \colorbox would lead to \color{sphinxVerbatimHighlightColor} + % plus \color@block, which results in doubled (a color.sty feature) + % color command send to device driver and more importantly has + % a "color pop" which will be after \box\z@. We avoid that for reasons + % mentioned above. + {% + \def\set@color{\let\set@color\spx@original@set@color}% + % will only set \current@color and delay the \set@color to \color@block + % as this all happens inside fancyvrb nested \hbox'es. + \color{sphinxVerbatimHighlightColor}% + % will use \current@color and pop it **before** \box\z@ + \color@block{\wd\z@}{\ht\z@}{\dp\z@}\box\z@ + }% + % we added a group only for \FV@RightListNumber not be influenced by the + % \current@color, if \fvset has been used to set numbers to the right. +}% +% MEMO: if verbatimwrapslines is set to true (which is default) the #1 here is +% already a box, and the \FV@ObeyTabs here can not modify it. The real action +% happens in \spx@verb@@PreProcessLine. +\newcommand\sphinxVerbatimFormatLine[1]{\FV@ObeyTabs{\strut #1}}% +% The next two macros are a deep hack of fancyvrb.sty core line processing in +% order to wrap too long lines, either at spaces and natural break-points, +% (soft wrap) or optionally at any character (hard wrap). This requires deep +% hack to work around the \hbox'es wrappers of fancyvrb.sty as they would +% prevent page breaks. Formerly Sphinx obtained wrapping by inserting the +% material into a vertical box (which was later again boxed -- twice -- by +% fancyvrb thinking it was a single line...) but this was incompatible with +% allowing page breaks (refs: #8686). +% We use core TeX techniques to pre-process a paragraph then recover its +% constituents lines (as boxes, not as tokens) and hand them over to original +% fancyvrb line process. It is mandatory to update \FV@ProcessLine and +% \@tempboxa globally to get fancyvrb internals into working to our +% satisfaction. +% This will get disrupted if anything adding vertical penalties or glues +% is activated via some \vadjust from inside the Pygmentized code lines. +\def\spx@verb@@ProcessLines{% + \unskip + \unpenalty + \setbox\spx@tempboxb\lastbox +\ifvoid\spx@tempboxb\else + {\spx@verb@@ProcessLines}% + \FV@ProcessLine{\box\spx@tempboxb}% + \global\let\FV@ProcessLine\FV@ProcessLine + \global\setbox\@tempboxa=\box\@tempboxa + \aftergroup\spx@verb@@InhibitLineNumber +\fi +}% +\def\spx@verb@@InhibitLineNumber{% + \let\FV@LeftListNumber\relax + \let\FV@RightListNumber\relax +}% +% This will replace fancyvrb's \FV@@PreProcessLine +% Instead of boxing \FV@Line (which contains the Pygmentized line tokens), we +% first typeset it in a vertical box of the suitable width (taking into +% account nested lists) to activate the TeX built-in paragraph builder, then +% we recover individual lines as horizontal boxes and feed them to fancyvrb +% native line processing (which may add line numbers). The interline +% penalties and vertical glue to maintain baseline distance will be added +% again by this process so in recursive \spx@verb@@ProcessLines which starts +% from bottom and makes its way up to first part of the wrapped line we do not +% need to worry about them. An additional initial measuring step is needed if +% user issued verbatimforcewraps=true, which elaborates on the same technique. +% If hard wraps get activated, they get implemented via hacked \PYG macros. +\def\spx@verb@@PreProcessLine{% + \FV@StepLineNo + \FV@Gobble + \def\spx@verb@FV@Line{\FV@Line}% + \ifspx@opt@verbatimforcewraps + \spx@verb@DecideIfWillDoForceWrap + \fi +% MEMO: \everypar{} was issued earlier (and due to \@setminipage +% would have been only \@minipagefalse\everypar{} otherwise). + \setbox\spx@tempboxa=\vtop{\hsize\linewidth + \raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ + \doublehyphendemerits\z@\finalhyphendemerits\z@ + \FV@ObeyTabs{\strut\spx@verb@FV@Line\strut}% +% MEMO: since LaTeX 2021-06-01, there might be some hooks executed at +% start and end of paragraphs (in future: PDF tagging), but we need an +% explicit \par here for that. Else the kernel hooks at start of paragraph +% are executed but not the ones at its end. + \par + }% + \setbox\spx@tempboxa=\vtop{\unvbox\spx@tempboxa + \setbox\spx@tempboxb\lastbox + {\spx@verb@@ProcessLines}% + \FV@ProcessLine{\box\spx@tempboxb}% + \global\let\FV@ProcessLine\FV@ProcessLine + \global\setbox\@tempboxa=\box\@tempboxa + }% + \unvbox\spx@tempboxa +}% +% +% The normal line wrapping allows breaks at spaces and ascii non +% letters, non digits. The \raggedright above means there will be +% an overfilled line only if some non-breakable "word" was +% encountered, which is longer than a line (it is moved always to +% be on its own on a new line). +% +% The "forced" line wrapping will parse the tokens to add potential +% breakpoints at each character. As some strings are highlighted, +% we have to apply the highlighting character per character, which +% requires to manipulate the output of the Pygments LaTeXFormatter. +% +% Doing this at latex level is complicated. The contents should +% be as expected: i.e. some active characters from +% \sphinxbreaksviaactive, some Pygments character escapes such as +% \PYGZdl{}, and the highlighting \PYG macro with always 2 +% arguments. No other macros should be there, except perhaps +% zero-parameter macros. In particular: +% - the texcomments Pygments option must be set to False +% +% With pdflatex, Unicode input gives multi-bytes characters +% where the first byte is active. We support the "utf8" macros +% only. "utf8x" is not supported. +% +% The highlighting macro \PYG will be applied character per +% character. Highlighting via a colored background gives thus a +% chain of small colored boxes which may cause some artefact in +% some pdf viewers. Can't do anything here if we do want the line +% break to be possible. +% +% First a measurement step is done of what would the standard line +% wrapping give (i.e line breaks only at spaces and non-letter, +% non-digit ascii characters), cf TeX by Topic for the basic +% dissecting technique: TeX unfortunately when building a vertical +% box does not store in an accessible way what was the maximal +% line-width during paragraph building. +% +% MEMO: in future use perhaps rather \RawNoindent/\RawParEnd, but +% ltpara (LaTeX 2021-06-01) is not yet in final form (June 2022). +% +% Avoid LaTeX 2021 alteration of \@@par which potentially could break our +% measurement step (typically if the para/after hook is configured to use +% \vspace). Of course, breakage could happen only from user or package +% adding things to basic Sphinx latex. And perhaps spring LaTeX 2021 will +% provide a non-hooked \@@par, but this should work anyway and can't be +% beaten for speed. +\ltx@ifundefined{tex_par:D} +% We could use \@ifl@t@r\fmtversion{2020/02/02}{use \tex_par:D}{use \@@par}. + {\let\spx@par\@@par}% \@@par is then expected to be TeX's original \par + {\expandafter\let\expandafter\spx@par\csname tex_par:D\endcsname} +% More hesitation for avoiding the at-start-of-par hooks for our +% measurement : 1. with old LaTeX, we can not avoid hooks from everyhook +% or similar packages, 2. and perhaps the hooks add stuff which we should +% actually measure. Ideally, hooks are for inserting things in margin +% which do not change spacing. Most everything else in fact should not be +% executed in our scratch box for measurement, such as counter stepping. +\ltx@ifundefined{tex_everypar:D} + {\let\spx@everypar\everypar} + {\expandafter\let\expandafter\spx@everypar\csname tex_everypar:D\endcsname} +% +% If the max width exceeds the linewidth by more than verbatimmaxoverfull +% character widths, or if the min width plus verbatimmaxunderfull character +% widths is inferior to linewidth, then we apply the "force wrapping" with +% potential line break at each character, else we don't. +\long\def\spx@verb@DecideIfWillDoForceWrap{% + \global\let\spx@verb@maxwidth\z@ + \global\let\spx@verb@minwidth\linewidth + \setbox\spx@tempboxa + \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ + \doublehyphendemerits\z@\finalhyphendemerits\z@ +% Avoid TeX reporting Overfull \hbox'es during this measuring phase. Setting +% \hbadness to \@M to avoid Underfull reports is unneeded due to \raggedright. + \hfuzz\maxdimen + \spx@everypar{}\noindent\FV@ObeyTabs{\strut\FV@Line\strut}\spx@par + \spx@verb@getwidths}% + \ifdim\spx@verb@maxwidth> + \dimexpr\linewidth+\spx@opt@verbatimmaxoverfull\fontcharwd\font`X \relax +% The \expandafter is due to \spx@verb@wrapPYG requiring to "see" the TeX tokens +% from the pygmentize output. + \def\spx@verb@FV@Line{\expandafter\spx@verb@wrapPYG\FV@Line\spx@verb@wrapPYG}% + \else + \ifdim\spx@verb@minwidth< + \dimexpr\linewidth-\spx@opt@verbatimmaxunderfull\fontcharwd\font`X \relax + \def\spx@verb@FV@Line{\expandafter\spx@verb@wrapPYG\FV@Line\spx@verb@wrapPYG}% + \fi + \fi +}% +% auxiliary paragraph dissector to get max and min widths +% but minwidth must not take into account the last line +\def\spx@verb@getwidths {% + \unskip\unpenalty + \setbox\spx@tempboxb\lastbox + \ifvoid\spx@tempboxb + \else + \setbox\spx@tempboxb\hbox{\unhbox\spx@tempboxb}% + \ifdim\spx@verb@maxwidth<\wd\spx@tempboxb + \xdef\spx@verb@maxwidth{\number\wd\spx@tempboxb sp}% + \fi + \expandafter\spx@verb@getwidths@loop + \fi +}% +\def\spx@verb@getwidths@loop {% + \unskip\unpenalty + \setbox\spx@tempboxb\lastbox + \ifvoid\spx@tempboxb + \else + \setbox\spx@tempboxb\hbox{\unhbox\spx@tempboxb}% + \ifdim\spx@verb@maxwidth<\wd\spx@tempboxb + \xdef\spx@verb@maxwidth{\number\wd\spx@tempboxb sp}% + \fi + \ifdim\spx@verb@minwidth>\wd\spx@tempboxb + \xdef\spx@verb@minwidth{\number\wd\spx@tempboxb sp}% + \fi + \expandafter\spx@verb@getwidths@loop + \fi +}% +% auxiliary macros to implement "cut long line even in middle of word" +% MEMO: it is important that this is does not rely on any specific \PYG +% meaning, it only relies on its presence in the mark-up, not its meaning. +\catcode`Z=3 % safe delimiter +\def\spx@verb@wrapPYG{% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@i +}% +\def\spx@verb@wrapPYG@i{% + \ifx\spx@nexttoken\spx@verb@wrapPYG\let\next=\@gobble\else + \ifx\spx@nexttoken\PYG\let\next=\spx@verb@wrapPYG@PYG@onebyone\else + \discretionary{}{\sphinxafterbreak}{}% + \let\next\spx@verb@wrapPYG@ii + \fi\fi + \next +}% +% Let's recognize active characters. We don't support utf8x only utf8. +% And here #1 should not have picked up (non empty) braced contents +\long\def\spx@verb@wrapPYG@ii#1{% + \ifcat\noexpand~\noexpand#1\relax% active character + \expandafter\spx@verb@wrapPYG@active + \else % non-active character, control sequence such as \PYGZdl, or empty + \expandafter\spx@verb@wrapPYG@one + \fi {#1}% +}% +\long\def\spx@verb@wrapPYG@active#1{% +% Let's hope expansion of active character does not really require arguments, +% as we certainly don't want to go into expanding upfront token stream anyway. + \expandafter\spx@verb@wrapPYG@iii#1{}{}{}{}{}{}{}{}{}Z#1% +}% +\long\def\spx@verb@wrapPYG@iii#1#2Z{% + \ifx\UTFviii@four@octets#1\let\next=\spx@verb@wrapPYG@four\else + \ifx\UTFviii@three@octets#1\let\next=\spx@verb@wrapPYG@three\else + \ifx\UTFviii@two@octets#1\let\next=\spx@verb@wrapPYG@two\else + \let\next=\spx@verb@wrapPYG@one + \fi\fi\fi + \next +}% +\long\def\spx@verb@wrapPYG@one #1{#1\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@two #1#2{#1#2\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@three #1#2#3{#1#2#3\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@four #1#2#3#4{#1#2#3#4\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +% Replace \PYG by itself applied one character at a time! This way breakpoints +% can be inserted. +\def\spx@verb@wrapPYG@PYG@onebyone#1#2#3{% #1 = \PYG, #2 = highlight spec, #3 = tokens + \def\spx@verb@wrapPYG@PYG@spec{{#2}}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i#3Z% +}% +\def\spx@verb@wrapPYG@PYG@i{% + \ifx\spx@nexttokenZ\let\next=\spx@verb@wrapPYG@PYG@done\else + \discretionary{}{\sphinxafterbreak}{}% + \let\next\spx@verb@wrapPYG@PYG@ii + \fi + \next +}% +\def\spx@verb@wrapPYG@PYG@doneZ{\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@PYG@ii#1{% + \ifcat\noexpand~\noexpand#1\relax% active character + \expandafter\spx@verb@wrapPYG@PYG@active + \else % non-active character, control sequence such as \PYGZdl, or empty + \expandafter\spx@verb@wrapPYG@PYG@one + \fi {#1}% +}% +\long\def\spx@verb@wrapPYG@PYG@active#1{% +% Let's hope expansion of active character does not really require arguments, +% as we certainly don't want to go into expanding upfront token stream anyway. + \expandafter\spx@verb@wrapPYG@PYG@iii#1{}{}{}{}{}{}{}{}{}Z#1% +}% +\long\def\spx@verb@wrapPYG@PYG@iii#1#2Z{% + \ifx\UTFviii@four@octets#1\let\next=\spx@verb@wrapPYG@PYG@four\else + \ifx\UTFviii@three@octets#1\let\next=\spx@verb@wrapPYG@PYG@three\else + \ifx\UTFviii@two@octets#1\let\next=\spx@verb@wrapPYG@PYG@two\else + \let\next=\spx@verb@wrapPYG@PYG@one + \fi\fi\fi + \next +}% +\long\def\spx@verb@wrapPYG@PYG@one#1{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\long\def\spx@verb@wrapPYG@PYG@two#1#2{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1#2}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\long\def\spx@verb@wrapPYG@PYG@three#1#2#3{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1#2#3}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\long\def\spx@verb@wrapPYG@PYG@four#1#2#3#4{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1#2#3#4}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\catcode`Z 11 % +% +\g@addto@macro\FV@SetupFont{% + \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% + \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% +}% +% +% For matters of 9.1.0 LongVerbatim, we extract from original Verbatim various +% pieces. Also, @Before and @After assignments are made global, to support an +% optional bottom caption position also with LongVerbatim, and one needs to +% always set them, as they are not undone anymore at end of scope. +\def\sphinxverbatim@preparetitle@none{% + \sphinxvspacefixafterfrenchlists + \parskip\z@skip + \vskip\sphinxverbatimsmallskipamount + % there was no caption. Check if nevertheless a label was set. + \ifx\sphinxLiteralBlockLabel\empty\else + % we require some space to be sure hyperlink target from \phantomsection + % will not be separated from upcoming verbatim by a page break + \needspace{\sphinxliteralblockwithoutcaptionneedspace}% + \phantomsection\sphinxLiteralBlockLabel + \fi + \global\let\sphinxVerbatim@Before\@empty + \global\let\sphinxVerbatim@After\@empty +}% +\def\sphinxverbatim@preparetitle@top{% + \vskip\spx@abovecaptionskip + \gdef\sphinxVerbatim@Before + {\sphinxVerbatim@Title\nointerlineskip + \kern\dimexpr-\dp\strutbox+\sphinxbelowcaptionspace + % MEMO: prior to 7.4.0 a test was done for presence or + % not of a frame and if not top padding was removed if + % no background color. A background color is now always + % assumed, so this got removed. + % caption package adds \abovecaptionskip vspace, remove it + \spx@ifcaptionpackage{-\abovecaptionskip}{}\relax}% + \global\let\sphinxVerbatim@After\@empty +}% +\def\sphinxverbatim@preparetitle@bottom{% + \vskip\sphinxverbatimsmallskipamount + \global\let\sphinxVerbatim@Before\@empty + \gdef\sphinxVerbatim@After + {\nointerlineskip\kern\dimexpr\dp\strutbox + % MEMO: 7.4.0 removes here too an optional removal of bottom padding + \spx@ifcaptionpackage{-\abovecaptionskip}{}\relax + \sphinxVerbatim@Title}% +}% +\def\sphinxverbatim@preparetitle@setbox{% + \def\@captype{literalblock}% + \capstart + % \sphinxVerbatimTitle must reset color + \global\setbox\sphinxVerbatim@TitleBox + \hbox{\begin{minipage}{\linewidth}% + % caption package may detect wrongly if top or bottom, so we help it + \spx@ifcaptionpackage + {\caption@setposition{\spx@opt@literalblockcappos}}{}% + \sphinxVerbatimTitle + \end{minipage}}% +}% +\def\sphinxverbatim@preparetitle{% + % first, let's check if there is a caption + \ifx\sphinxVerbatimTitle\@empty + \sphinxverbatim@preparetitle@none + \else + \parskip\z@skip + \if t\spx@opt@literalblockcappos + \sphinxverbatim@preparetitle@top + \else + \sphinxverbatim@preparetitle@bottom + \fi + \sphinxverbatim@preparetitle@setbox + \fi +}% +\def\sphinxverbatim@prepareframecommands{% + % the "FrameCommand"'s are also responsible to attach the "Title". + \let\FrameCommand \sphinxVerbatim@FrameCommand + % those will also check status of the pre_box-decoration-break option + \let\FirstFrameCommand\sphinxVerbatim@FirstFrameCommand + \let\MidFrameCommand \sphinxVerbatim@MidFrameCommand + \let\LastFrameCommand \sphinxVerbatim@LastFrameCommand + % + \ifspx@opt@verbatimhintsturnover\else + \let\sphinxVerbatim@Continued\@empty + \let\sphinxVerbatim@Continues\@empty + \fi +}% +\def\sphinxverbatim@hackfancyvrb{% + \ifspx@opt@verbatimwrapslines + % deep hack into fancyvrb's internal processing of input lines + \let\FV@@PreProcessLine\spx@verb@@PreProcessLine + % space character will allow line breaks + \let\FV@Space\spx@verbatim@space + % allow breaks at special characters using \PYG... macros. + \sphinxbreaksatspecials + % breaks at punctuation characters . , ; ? ! and / (needs catcode activation) + \fvset{codes*=\sphinxbreaksviaactive}% + \fi + \let\FancyVerbFormatLine\sphinxFancyVerbFormatLine +}% +\def\sphinxverbatim@Verbatim{% + % workaround to fancyvrb's check of current list depth + \def\@toodeep {\advance\@listdepth\@ne}% + % The list environment is needed to control perfectly the vertical space. + % Note: \OuterFrameSep used by framed.sty is later set to \topsep hence 0pt. + % - if caption: distance from last text baseline to caption baseline is + % A+(B-F)+\ht\strutbox, A = \abovecaptionskip (default 10pt), B = + % \baselineskip, F is the framed.sty \FrameHeightAdjust macro, default 6pt. + % Formula valid for F < 10pt. + % - distance of baseline of caption to top of frame is like for tables: + % \sphinxbelowcaptionspace (=0.5\baselineskip) + % - if no caption: distance of last text baseline to code frame is S+(B-F), + % with S = \sphinxverbatimtopskip (=\smallskip) + % - and distance from bottom of frame to next text baseline is + % \baselineskip+\parskip. + % The \trivlist is used to avoid possible "too deeply nested" error. + \itemsep \z@skip + \topsep \z@skip + \partopsep \z@skip + % trivlist will set \parsep to \parskip (which itself is set to zero above) + % \leftmargin will be set to zero by trivlist + \rightmargin\z@ + \parindent \z@% becomes \itemindent. Default zero, but perhaps overwritten. + \trivlist\item\relax + \ifspx@inframed\setbox\sphinxVerbatim@ContentsBox\vbox\bgroup + \@setminipage\hsize\linewidth + % use bulk of minipage paragraph shape restores (this is needed + % in indented contexts, at least for some) + \textwidth\hsize \columnwidth\hsize \@totalleftmargin\z@ + \leftskip\z@skip \rightskip\z@skip \@rightskip\z@skip + \else + \ifsphinxverbatimwithminipage\noindent\begin{minipage}{\linewidth}\fi + \MakeFramed {% adapted over from framed.sty's snugshade environment + \advance\hsize-\width\@totalleftmargin\z@\linewidth\hsize\@setminipage + }% + \fi + % For grid placement from \strut's in \FancyVerbFormatLine + \lineskip\z@skip + % active comma should not be overwritten by \@noligs + \ifspx@opt@verbatimwrapslines + \let\verbatim@nolig@list \sphinx@verbatim@nolig@list + \fi + % optimization: as codelines will be handled inside boxes, \everypar is + % never reset, and it issues \@minipagefalse repeatedly (from \@setminipage). + % As fancyvrb Verbatim will do \@minipagefalse itself, let's simplify things. + \everypar{}% + \color@begingroup % protect against color leaks (upstream framed.sty bug) + \ifspx@pre@withtextcolor\color{VerbatimTextColor}\fi % mostly shadowed by + % Pygments highlighting anyhow + \spx@pre@TeXextras + % will fetch its optional arguments if any + \OriginalVerbatim +}% +\def\sphinxverbatim@EndVerbatim{% + \endOriginalVerbatim + \color@endgroup % matches the \color@begingroup + \ifspx@inframed + \egroup % finish \sphinxVerbatim@ContentsBox vbox + \nobreak % update page totals +%%%% +% MEMO (2022/07/09, while preparing 5.1.0 LaTeX CSS-style sphinxsetup options) +% This test will systematically cause to abandon framing if the code-block +% is near bottom of a warning-type notice which TeX has not yet decided whether +% it fits on current page and which is near bottom of page. Indeed the +% \pagetotal will already be very near \pagegoal. This is probably a not +% intended behaviour, and perhaps the whole thing should be removed? Indeed +% the result is surprising then because the notice will be split, code-block +% will be on page 2 and will have no background-color, no border. + \ifdim\dimexpr + \ht\sphinxVerbatim@ContentsBox+ + \dp\sphinxVerbatim@ContentsBox+ + \ifx\sphinxVerbatimTitle\@empty\else % added at 9.1.0 (now global @TitleBox) + \ht\sphinxVerbatim@TitleBox+ + \dp\sphinxVerbatim@TitleBox+ + \fi + % 6.2.0 uses here the dimen registers from sphinxpackageboxes.sty, + % they got setup by \spx@verb@boxes@fcolorbox@setup + \spx@boxes@padding@top+ + \spx@boxes@padding@bottom+ + \ifspx@opt@verbatimwithframe \spx@boxes@border@top+ + \spx@boxes@border@bottom+\fi + % try to account for external frame parameters + % MEMO: this is because the sphinxheavybox (for warning admonitions) + % environment sets \FrameSep and \FrameRule + % TODO: fix this bad implicit dependency + \FrameSep+\FrameRule+ + % Usage here of 2 baseline distances is empirical. + % In border case where code-block fits barely in remaining space, + % it gets framed and looks good but the outer frame may continue + % on top of next page and give (if no contents after code-block) + % an empty framed line, as testing showed. + 2\baselineskip+ + % now add all to accumulated page totals and compare to \pagegoal + \pagetotal+\pagedepth>\pagegoal + % long contents: do not \MakeFramed. Do make a caption (either before or + % after) if title exists. Continuation hints across pagebreaks dropped. + % FIXME? a bottom caption may end up isolated at top of next page + % (no problem with a top caption, which is default) + \spx@opt@verbatimwithframefalse + % MEMO: next line has an effect only if Title does exist. + \def\sphinxVerbatim@Title{\noindent\box\sphinxVerbatim@TitleBox\par}% + \sphinxVerbatim@Before + \noindent\unvbox\sphinxVerbatim@ContentsBox\par + \sphinxVerbatim@After + \else + % short enough contents: use \MakeFramed. As it is nested, this requires + % minipage encapsulation. + \noindent\begin{minipage}{\linewidth}% + \MakeFramed {% Use it now with the fetched contents + \advance\hsize-\width\@totalleftmargin\z@\linewidth\hsize\@setminipage + }% + \unvbox\sphinxVerbatim@ContentsBox + % the \@minipagefalse is superfluous, actually. + \par\unskip\@minipagefalse\endMakeFramed + \end{minipage}% + \fi + \else % non-nested \MakeFramed + \par\unskip\@minipagefalse\endMakeFramed % from framed.sty snugshade + \ifsphinxverbatimwithminipage\end{minipage}\fi + \fi + \endtrivlist +}% +\newenvironment{sphinxVerbatim}{% + \sphinxverbatim@preparetitle + \sphinxverbatim@prepareframecommands + % initialization for \spx@boxes@fcolorbox from sphinxpackageboxes.sty + % it will take into account status of verbatimwithframe Boolean + \spx@verb@boxes@fcolorbox@setup + \sphinxverbatim@hackfancyvrb + \VerbatimEnvironment + \sphinxverbatim@Verbatim +}% +{% + \sphinxverbatim@EndVerbatim + \global\let\sphinxLiteralBlockLabel\@empty + \global\let\sphinxVerbatimTitle\@empty +} +\def\sphinxlongverbatim@preparefirstframecommands{% + \def\FrameCommand {% + \spx@boxes@fcolorbox@setup@openbottom + \spx@boxes@padding@bottom\z@ + \spx@verb@FrameCommand\sphinxVerbatim@Before\@empty + }% + \let\FirstFrameCommand\sphinxVerbatim@FirstFrameCommand + \let\MidFrameCommand \sphinxVerbatim@MidFrameCommand + \def\LastFrameCommand {% + \spx@boxes@fcolorbox@setup@openbottom + \spx@boxes@padding@bottom\z@ + \spx@verb@FrameCommand\@empty\@empty + }% + \ifspx@opt@verbatimhintsturnover\else + \let\sphinxVerbatim@Continued\@empty + \let\sphinxVerbatim@Continues\@empty + \fi +}% +\newenvironment{sphinxLongVerbatimFirst}{% + \sphinxverbatim@preparetitle + \sphinxlongverbatim@preparefirstframecommands + \spx@verb@boxes@fcolorbox@setup + \sphinxverbatim@hackfancyvrb + \let\FancyVerbFormatLine\sphinxLongVerbatimFancyVerbFormatLine + \VerbatimEnvironment + \sphinxverbatim@Verbatim +}% +{% + \sphinxverbatim@EndVerbatim +} +\def\sphinxLongVerbatimStitch + {\vspace{-\dimexpr\baselineskip-\FrameHeightAdjust\relax}} +\def\sphinxlongverbatim@preparemiddleframecommands{% + \def\FrameCommand {% + \spx@boxes@fcolorbox@setup@openboth + \spx@boxes@padding@top\z@ + \spx@boxes@padding@bottom\z@ + \spx@verb@FrameCommand\sphinxLongVerbatimStitch + \@empty + }% + \def\FirstFrameCommand {% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@openboth + \else + \spx@boxes@fcolorbox@setup@opentop + \fi + \spx@boxes@padding@top\z@ + \spx@verb@FrameCommand\sphinxLongVerbatimStitch + \sphinxVerbatim@Continues + }% + \let\MidFrameCommand \sphinxVerbatim@MidFrameCommand + \def\LastFrameCommand {% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@openboth + \else + \spx@boxes@fcolorbox@setup@openbottom + \fi + \spx@boxes@padding@bottom\z@ + \spx@verb@FrameCommand\sphinxVerbatim@Continued\@empty + }% + % + \ifspx@opt@verbatimhintsturnover\else + \let\sphinxVerbatim@Continued\@empty + \let\sphinxVerbatim@Continues\@empty + \fi +}% +\newenvironment{sphinxLongVerbatimMiddle}{% + \parskip\z@skip + \sphinxlongverbatim@preparemiddleframecommands + \spx@verb@boxes@fcolorbox@setup + \sphinxverbatim@hackfancyvrb + \let\FancyVerbFormatLine\sphinxLongVerbatimFancyVerbFormatLine + \VerbatimEnvironment + \sphinxverbatim@Verbatim +}% +{% + \sphinxverbatim@EndVerbatim +} +\def\sphinxlongverbatim@preparelastframecommands{% + \def\FrameCommand {% + \spx@boxes@fcolorbox@setup@opentop + \spx@boxes@padding@top\z@ + \spx@verb@FrameCommand\sphinxLongVerbatimStitch + \sphinxVerbatim@After + }% + \def\FirstFrameCommand {% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@openboth + \else + \spx@boxes@fcolorbox@setup@opentop + \fi + \spx@boxes@padding@bottom\z@ + \spx@verb@FrameCommand\sphinxLongVerbatimStitch + \sphinxVerbatim@Continues + }% + \let\MidFrameCommand \sphinxVerbatim@MidFrameCommand + \def\LastFrameCommand {% + \ifspx@pre@border@open + \spx@boxes@fcolorbox@setup@opentop + \fi + \spx@verb@FrameCommand\sphinxVerbatim@Continued\sphinxVerbatim@After + }% + % + \ifspx@opt@verbatimhintsturnover\else + \let\sphinxVerbatim@Continued\@empty + \let\sphinxVerbatim@Continues\@empty + \fi +}% +\newenvironment{sphinxLongVerbatimLast}{% + \parskip\z@skip + \sphinxlongverbatim@preparelastframecommands + \spx@verb@boxes@fcolorbox@setup + \sphinxverbatim@hackfancyvrb + \let\FancyVerbFormatLine\sphinxLongVerbatimFancyVerbFormatLine + \VerbatimEnvironment + \sphinxverbatim@Verbatim +}% +{% + \sphinxverbatim@EndVerbatim + \global\let\sphinxLiteralBlockLabel\@empty + \global\let\sphinxVerbatimTitle\@empty +} +\newenvironment {sphinxVerbatimNoFrame} + {\spx@opt@verbatimwithframefalse + \VerbatimEnvironment + \begin{sphinxVerbatim}} + {\end{sphinxVerbatim}} +\newenvironment {sphinxVerbatimintable} + {% don't use a frame if in a table cell + \spx@opt@verbatimwithframefalse + \sphinxverbatimwithminipagetrue + % the literal block caption uses \sphinxcaption which is wrapper of \caption, + % but \caption must be modified because longtable redefines it to work only + % for the own table caption, and tabulary has multiple passes + \let\caption\sphinxfigcaption + % reduce above caption skip + \def\spx@abovecaptionskip{\sphinxverbatimsmallskipamount}% + \VerbatimEnvironment + \begin{sphinxVerbatim}} + {\end{sphinxVerbatim}} + + +%% PARSED LITERALS +% allow long lines to wrap like they do in code-blocks + +% this should be kept in sync with definitions in sphinx.util.texescape +\newcommand*\sphinxbreaksattexescapedchars{% + \def\do##1##2% put potential break point before character + {\def##1{\discretionary{}{\sphinxafterbreak\char`##2}{\char`##2}}}% + \do\{\{\do\textless\<\do\#\#\do\%\%\do\$\$% {, <, #, %, $ + \def\do##1##2% put potential break point after character + {\def##1{\discretionary{\char`##2}{\sphinxafterbreak}{\char`##2}}}% + \do\_\_\do\}\}\do\textasciicircum\^\do\&\&% _, }, ^, &, + \do\textgreater\>\do\textasciitilde\~% >, ~ + \do\textbackslash\\% \ +} +\newcommand*\sphinxbreaksviaactiveinparsedliteral{% + \sphinxbreaksviaactive % by default handles . , ; ? ! / + \lccode`\~`\~ % + % update \dospecials as it is used by \url + % but deactivation will already have been done hence this is unneeded: + % \expandafter\def\expandafter\dospecials\expandafter{\dospecials + % \sphinxbreaksbeforeactivelist\sphinxbreaksafteractivelist\do\-}% +} +\newcommand*\sphinxbreaksatspaceinparsedliteral{% + \lccode`~32 \lowercase{\let~}\spx@verbatim@space\lccode`\~`\~ +} +\newcommand*{\sphinxunactivateextras}{\let\do\@makeother + \sphinxbreaksbeforeactivelist\sphinxbreaksafteractivelist}% +% the \catcode13=5\relax (deactivate end of input lines) is left to callers +\newcommand*{\sphinxunactivateextrasandspace}{\catcode32=10\relax + \sphinxunactivateextras}% +% alltt uses a monospace font and linebreaks at dashes (which are escaped +% to \sphinxhyphen{} which expands to -\kern\z@) are inhibited with pdflatex. +% Not with xelatex (cf \defaultfontfeatures in latex writer), so: +\newcommand*{\sphinxhypheninparsedliteral}{\sphinxhyphennobreak} +% now for the modified alltt environment +\newenvironment{sphinxalltt} +{% at start of next line to workaround Emacs/AUCTeX issue with this file +\begin{alltt}% + \ifspx@opt@parsedliteralwraps + \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% + \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% + \let\sphinxhyphen\sphinxhypheninparsedliteral + \sphinxbreaksattexescapedchars + \sphinxbreaksviaactiveinparsedliteral + \sphinxbreaksatspaceinparsedliteral +% alltt takes care of the ' as derivative ("prime") in math mode + \everymath\expandafter{\the\everymath\sphinxunactivateextrasandspace + \catcode`\<=12\catcode`\>=12\catcode`\^=7\catcode`\_=8 }% +% not sure if displayed math (align,...) can end up in parsed-literal, anyway + \everydisplay\expandafter{\the\everydisplay + \catcode13=5 \sphinxunactivateextrasandspace + \catcode`\<=12\catcode`\>=12\catcode`\^=7\catcode`\_=8 }% + \fi } +{\end{alltt}} + + +%% INLINE MARK-UP +% + +% Protect \href's first argument in contexts such as sphinxalltt (or +% \sphinxcode). Sphinx uses \#, \%, \& ... always inside \sphinxhref. +\protected\def\sphinxhref#1#2{{% + \sphinxunactivateextrasandspace % never do \scantokens with active space! +% for the \endlinechar business, https://github.com/latex3/latex2e/issues/286 + \endlinechar\m@ne\everyeof{{\endlinechar13 #2}}% keep catcode regime for #2 + \scantokens{\href{#1}}% normalise it for #1 during \href expansion +}} +% Same for \url. And also \nolinkurl for coherence. +\protected\def\sphinxurl#1{{% + \sphinxunactivateextrasandspace\everyeof{}% (<- precaution for \scantokens) + \endlinechar\m@ne\scantokens{\url{#1}}% +}} +\protected\def\sphinxnolinkurl#1{{% + \sphinxunactivateextrasandspace\everyeof{}% + \endlinechar\m@ne\scantokens{\nolinkurl{#1}}% +}} + +% \sphinxupquote +% to obtain straight quotes we execute \@noligs as patched by upquote, and +% \scantokens is needed in cases where it would be too late for the macro to +% first set catcodes and then fetch its argument. We also make the contents +% breakable at non-escaped . , ; ? ! / using \sphinxbreaksviaactive, +% and also at \ character (which is escaped to \textbackslash{}). +\protected\def\sphinxtextbackslashbreakbefore + {\discretionary{}{\sphinxafterbreak\sphinx@textbackslash}{\sphinx@textbackslash}} +\protected\def\sphinxtextbackslashbreakafter + {\discretionary{\sphinx@textbackslash}{\sphinxafterbreak}{\sphinx@textbackslash}} +\let\sphinxtextbackslash\sphinxtextbackslashbreakafter +% - is escaped to \sphinxhyphen{} and this default ensures no linebreak +% behaviour (also with a non monospace font, or with xelatex) +\newcommand*{\sphinxhyphenininlineliteral}{\sphinxhyphennobreak} +% the macro must be protected if it ends up used in moving arguments, +% in 'alltt' \@noligs is done already, and the \scantokens must be avoided. +\protected\def\sphinxupquote#1{{\def\@tempa{alltt}% + \ifx\@tempa\@currenvir\else + \let\sphinxhyphen\sphinxhyphenininlineliteral + \ifspx@opt@inlineliteralwraps + % break at . , ; ? ! / + % and also at ~ which will be handled like are spaces in verbatim + \sphinxbreaksviaactive + % but for this we need to set this box which is empty by default: + % MEMO: it looks suboptimal to redo this each time but this is + % to obey a \sphinxsetup via raw LaTeX to set verbatimvisiblespace, + % a possibility which however will be used by 0% of Sphinx users... + \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% + % break also at \ + \setbox8=\hbox{\textbackslash}% + \def\sphinx@textbackslash{\copy8}% + \let\textbackslash\sphinxtextbackslash + % by default, no continuation symbol on next line but may be added + \let\sphinxafterbreak\sphinxafterbreakofinlineliteral + % do not overwrite the comma set-up + \let\verbatim@nolig@list\sphinx@literal@nolig@list + \fi + % fix a space-gobbling issue due to LaTeX's original \do@noligs +% TODO: using \@noligs as patched by upquote.sty is now unneeded because +% either ` and ' are escaped (non-unicode engines) or they don't build +% ligatures (unicode engines). Thus remove this and unify handling of `, <, >, +% ' and - with the characters . , ; ? ! / as handled via +% \sphinxbreaksviaactive. +% Hence \sphinx@do@noligs will be removed, or rather replaced with code +% inserting discretionaries, as they allow a continuation symbol on start of +% next line to achieve common design with code-blocks. +% TODO: do the above TODO! +% Extend \sphinxunactivateextras for \sphinxhref as the latter may +% actually be in the scope of \sphinxupquote and does a \scantokens +% of its own. + \expandafter\def\expandafter\sphinxunactivateextras\expandafter + {\sphinxunactivateextras\verbatim@nolig@list}% + \let\do@noligs\sphinx@do@noligs + \@noligs\endlinechar\m@ne\everyeof{}% (<- in case inside \sphinxhref) + \expandafter\scantokens + \fi {{#1}}}}% extra brace pair to fix end-space gobbling issue... +\def\sphinx@do@noligs #1{\catcode`#1\active\begingroup\lccode`\~`#1\relax + \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1 }}} +\def\sphinx@literal@nolig@list {\do\`\do\<\do\>\do\'\do\-}% +\let\sphinxafterbreakofinlineliteral\empty + + +\endinput diff --git a/build/latex/sphinxlatexnumfig.sty b/build/latex/sphinxlatexnumfig.sty new file mode 100644 index 0000000..22fcbb0 --- /dev/null +++ b/build/latex/sphinxlatexnumfig.sty @@ -0,0 +1,135 @@ +%% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexnumfig}[2024/07/31 v8.1.0 numbering] + +% Requires: remreset (old LaTeX only) +% relates to numfig and numfig_secnum_depth configuration variables + +% LaTeX 2018-04-01 and later provides \@removefromreset +\ltx@ifundefined{@removefromreset} + {\RequirePackage{remreset}} + {}% avoid warning +% Everything is delayed to \begin{document} to allow hyperref patches into +% \newcounter to solve duplicate label problems for internal hyperlinks to +% code listings (literalblock counter). User or extension re-definitions of +% \theliteralblock, et al., thus have also to be delayed. (changed at 3.5.0) +\AtBeginDocument{% +\ltx@ifundefined{c@chapter} + {\newcounter{literalblock}}% + {\newcounter{literalblock}[chapter]% + \def\theliteralblock{\ifnum\c@chapter>\z@\arabic{chapter}.\fi + \arabic{literalblock}}% + }% +\ifspx@opt@nonumfigreset + \ltx@ifundefined{c@chapter}{}{% + \@removefromreset{figure}{chapter}% + \@removefromreset{table}{chapter}% + \@removefromreset{literalblock}{chapter}% + \ifspx@opt@mathnumfig + \@removefromreset{equation}{chapter}% + \fi + }% + \def\thefigure{\arabic{figure}}% + \def\thetable {\arabic{table}}% + \def\theliteralblock{\arabic{literalblock}}% + \ifspx@opt@mathnumfig + \def\theequation{\arabic{equation}}% + \fi +\else +% See apologetic comments on TeX wizardry at bottom of file. +% The reason for this one is to catch case where there will be only +% the number with no prefix from enclosing sectioning (can happen +% with latex_toplevel_sectioning='part'). +\def\spx@preAthefigure{\expandafter\spx@magicsep@s\romannumeral-`0} +\let\spx@preBthefigure\@empty +% \ifspx@opt@usespart % <-- LaTeX writer could pass such a 'usespart' boolean +% % as sphinx.sty package option +% If document uses \part, (triggered in Sphinx by latex_toplevel_sectioning) +% LaTeX core per default does not reset chapter or section +% counters at each part. +% But if we modify this, we need to redefine \thechapter, \thesection to +% include the part number and this will cause problems in table of contents +% because of too wide numbering. Simplest is to do nothing. +% \fi +\ifnum\spx@opt@numfigreset>0 + \ltx@ifundefined{c@chapter} + {} + {\g@addto@macro\spx@preAthefigure{\ifnum\c@chapter>\z@\arabic{chapter}\spx@magicsep}% + \g@addto@macro\spx@preBthefigure{\fi}}% +\fi +\ifnum\spx@opt@numfigreset>1 + \@addtoreset{figure}{section}% + \@addtoreset{table}{section}% + \@addtoreset{literalblock}{section}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{section}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@section>\z@\arabic{section}\spx@magicsep}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>2 + \@addtoreset{figure}{subsection}% + \@addtoreset{table}{subsection}% + \@addtoreset{literalblock}{subsection}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subsection}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsection>\z@\arabic{subsection}\spx@magicsep}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>3 + \@addtoreset{figure}{subsubsection}% + \@addtoreset{table}{subsubsection}% + \@addtoreset{literalblock}{subsubsection}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subsubsection}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubsection>\z@\arabic{subsubsection}\spx@magicsep}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>4 + \@addtoreset{figure}{paragraph}% + \@addtoreset{table}{paragraph}% + \@addtoreset{literalblock}{paragraph}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{paragraph}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subparagraph>\z@\arabic{subparagraph}\spx@magicsep}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>5 + \@addtoreset{figure}{subparagraph}% + \@addtoreset{table}{subparagraph}% + \@addtoreset{literalblock}{subparagraph}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subparagraph}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubparagraph>\z@\arabic{subsubparagraph}\spx@magicsep}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\expandafter\g@addto@macro +\expandafter\spx@preAthefigure\expandafter{\spx@preBthefigure}% +\let\thefigure\spx@preAthefigure +\let\thetable\spx@preAthefigure +\let\theliteralblock\spx@preAthefigure +\g@addto@macro\thefigure{\arabic{figure}}% +\g@addto@macro\thetable{\arabic{table}}% +\g@addto@macro\theliteralblock{\arabic{literalblock}}% + \ifspx@opt@mathnumfig + \let\theequation\spx@preAthefigure + \g@addto@macro\theequation{E}% + \fi +\fi +}% end of big \AtBeginDocument + +% Sorry for TeX wizardry here. We need to keep expandability. Explaining +% the mechanism is not really feasible to non TeX-experts, but the idea +% is to force next `\ifnum` conditional so we can check what comes next. +% All cases are accounted for (i.e. not an equation, or an equation at top +% level, or an equation in some section at some depth). +\def\spx@magicsep{\expandafter\spx@magicsep@i\romannumeral-`0} +\def\spx@magicsep@i#1{\if#1E\spx@opt@mathnumsep\arabic{equation}\else.#1\fi} +% +\def\spx@magicsep@s#1{\if#1E\arabic{equation}\else#1\fi} +\endinput diff --git a/build/latex/sphinxlatexobjects.sty b/build/latex/sphinxlatexobjects.sty new file mode 100644 index 0000000..2a05dd6 --- /dev/null +++ b/build/latex/sphinxlatexobjects.sty @@ -0,0 +1,386 @@ +%% MODULE RELEASE DATA AND OBJECT DESCRIPTIONS +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexobjects}[2025/06/06 documentation environments] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - environments +% +% - fulllineitems +% - productionlist +% - optionlist +% - DUlineblock (also "lineblock") +% +% - macros +% +% - \DUrole +% - various legacy support macros related to author and release +% data of documented objects and modules. + +% \moduleauthor{name}{email} +\newcommand{\moduleauthor}[2]{} + +% \sectionauthor{name}{email} +\newcommand{\sectionauthor}[2]{} + +% Allow the release number to be specified independently of the +% \date{}. This allows the date to reflect the document's date and +% release to specify the release that is documented. +% +\newcommand{\py@release}{\releasename\space\version} +\newcommand{\version}{}% part of \py@release, used by title page and headers +% \releaseinfo is used on titlepage (sphinxmanual.cls, sphinxhowto.cls) +\newcommand{\releaseinfo}{} +\newcommand{\setreleaseinfo}[1]{\renewcommand{\releaseinfo}{#1}} +% this is inserted via template and #1=release config variable +\newcommand{\release}[1]{\renewcommand{\version}{#1}} +% this is defined by template to 'releasename' latex_elements key +\newcommand{\releasename}{} +% Fix issue in case release and releasename deliberately left blank +\newcommand{\sphinxheadercomma}{, }% used in fancyhdr header definition +\newcommand{\sphinxifemptyorblank}[1]{% +% test after one expansion of macro #1 if contents is empty or spaces + \if&\expandafter\@firstofone\detokenize\expandafter{#1}&% + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}% +\AtBeginDocument {% + \sphinxifemptyorblank{\releasename} + {\sphinxifemptyorblank{\version}{\let\sphinxheadercomma\empty}{}} + {}% +}% + +% Allow specification of the author's address separately from the +% author's name. This can be used to format them differently, which +% is a good thing. +% +\newcommand{\py@authoraddress}{} +\newcommand{\authoraddress}[1]{\renewcommand{\py@authoraddress}{#1}} + +% {fulllineitems} is the main environment for object descriptions. +% +% With 4.0.0 \pysigline (and \pysiglinewithargsret), used in a fulllineitems +% environment the #1 will already be of the width which is computed here, i.e. +% the available width on line, so the \makebox becomes a bit superfluous +\newcommand{\py@itemnewline}[1]{% macro used as \makelabel in fulllineitems +% Memo: this presupposes \itemindent is 0pt + \kern\labelsep % because \@labels core latex box does \hskip-\labelsep + \makebox[\dimexpr\linewidth+\labelwidth\relax][l]{#1}% + \kern-\labelsep % because at end of \@labels box there is \hskip\labelsep +} + +\newenvironment{fulllineitems}{% + \begin{list}{}{\labelwidth \leftmargin + \rightmargin \z@ \topsep -\parskip \partopsep \parskip + \itemsep -\parsep + \let\makelabel=\py@itemnewline}% +}{\end{list}} + +% Signatures, possibly multi-line +% +% For legacy reasons Sphinx uses LaTeX \list and \item's for signatures +% This is delicate: +% - the actual item label is not typeset immediately by \item but later as part +% of the \everypar which will be triggered by either next paragraph or a manual +% \leavevmode, or if nothing in-between by the next \item, +% - \begingroup \item[foo] \endgroup leads to errors, +% - vertical space depends on \parskip and \itemsep values in somewhat +% subtle manners. +% +% Since the 2022/01/13 version things are simpler as \parskip is simply set +% to zero during execution of \pysigline/\pysiglinewithargsret +% +% Parameter for separation via \itemsep of multiple signatures with common desc +\newlength\sphinxsignaturesep +\setlength\sphinxsignaturesep{\smallskipamount} +% latex.py outputs mark-up like this: +% \pysigstartsignatures \pysigstopsignatures +\newcommand{\pysigstartsignatures}{% + % store current \parskip and \itemsep + \edef\pysig@restore@itemsep@and@parskip{% + \itemsep\the\itemsep\relax + \parskip\the\parskip\relax + }% + % set them to control the spacing between signatures sharing common desc + \parskip\z@skip + \itemsep\sphinxsignaturesep +} +\newcommand{\pysigstopsignatures}{% +% 1) encourage a pagebreak in an attempt to try to avoid last +% signature ending up separated from description (due to voodoo next) +\penalty-100 +% 2) some voodoo to separate last signature from description in a manner +% robust with respect to the latter being itself a LaTeX list object +\leavevmode\par\kern-\baselineskip\item[\strut] +% + \leavevmode + % it is important \leavevmode was issued before the \parskip reset, and + % it is also needed for the case of an object desc itself a LaTeX \list + % now restore \itemsep and \parskip + \pysig@restore@itemsep@and@parskip +} +% Each signature is rendered as NAME[TPLIST](ARGLIST) where the +% size of is parametrized by \sphinxsignaturelistskip (0pt by default). +\newlength\sphinxsignaturelistskip +\setlength\sphinxsignaturelistskip{0pt} +\newcommand{\pysigtypelistopen}{\hskip\sphinxsignaturelistskip\sphinxcode{[}} +\newcommand{\pysigtypelistclose}{\sphinxcode{]}} +\newcommand{\pysigarglistopen}{\hskip\sphinxsignaturelistskip\sphinxcode{(}} +\newcommand{\pysigarglistclose}{\sphinxcode{)}} +% +% Use a \parbox to accommodate long argument list in signatures +% LaTeX did not imagine that an \item label could need multi-line rendering +\newlength{\py@argswidth} +\newcommand{\py@sigparams}[2]{% + % The \py@argswidth has been computed in \pysiglinewithargsret to make the + % argument list use full available width + \parbox[t]{\py@argswidth}{\raggedright #1\pysigarglistclose#2\strut}% + % final strut is to help get correct vertical separation +} +\newcommand{\py@sigparamswithtypelist}[3]{% + % similar to \py@sigparams but with different delimiters and an additional + % type parameters list given as #1, the argument list as #2 and the return + % annotation as #3 + \parbox[t]{\py@argswidth}{% + \raggedright #1\pysigtypelistclose% + \pysigarglistopen#2\pysigarglistclose% + #3\strut}% +} + +\newcommand{\pysigline}[1]{% + % as \py@argswidth is available, we use it but no "args" here + % the \relax\relax is because \py@argswidth is a "skip" variable + % this will make the label occupy the full available linewidth + \py@argswidth=\dimexpr\linewidth+\labelwidth\relax\relax + \item[{\parbox[t]{\py@argswidth}{\raggedright #1\strut}}] + \pysigadjustitemsep +} +\newcommand{\pysiglinewithargsret}[3]{% + % #1 may contain a footnote (especially with latex_show_urls='footnote' + % and some intersphinx added hyperlinking). Here we want to measure + % a width but not typeset such a footnote (else #13619). + % Miraculously a sphinxpackagefootnote.sty tabulary compatibility + % layer employing the amsmath \ifmeasuring@ can be used here to let + % a footnote influence the actual width up to opening brace but not + % actually get typeset at this stage... + % MEMO: "argswidth" is misleading here, this code measures the name + % not the arguments. + \settowidth{\py@argswidth}{\measuring@true#1\pysigarglistopen}% + \py@argswidth=\dimexpr\linewidth+\labelwidth-\py@argswidth\relax\relax + \item[{#1\pysigarglistopen\py@sigparams{#2}{#3}\strut}] + \pysigadjustitemsep +} +\newcommand{\pysiglinewithargsretwithtypelist}[4]{% + % same comment as in \pysiglinewithargsret + \settowidth{\py@argswidth}{\measuring@true#1\pysigtypelistopen}% + \py@argswidth=\dimexpr\linewidth+\labelwidth-\py@argswidth\relax\relax + \item[{#1\pysigtypelistopen\py@sigparamswithtypelist{#2}{#3}{#4}\strut}] + \pysigadjustitemsep +} + +\def\sphinxoptionalextraspace{0.5mm} +\newcommand{\pysigwithonelineperarg}[3]{% + % render each argument on its own line + \item[#1\pysigarglistopen\strut] + \leavevmode\par\nopagebreak + % this relies on \pysigstartsignatures having set \parskip to zero + \begingroup + \let\sphinxparamcomma\sphinxparamcommaoneperline + \def\sphinxoptionalhook{\ifvmode\else\kern\sphinxoptionalextraspace\relax\fi}% + % The very first \sphinxparam should not emit a \par hence a complication + % with a group and global definition here as it may occur in a \sphinxoptional + \global\let\spx@sphinxparam\sphinxparam + \gdef\sphinxparam{\gdef\sphinxparam{\par\spx@sphinxparam}\spx@sphinxparam}% + #2\par + \endgroup + \global\let\sphinxparam\spx@sphinxparam + % fulllineitems sets \labelwidth to be like \leftmargin + \nopagebreak\noindent\kern-\labelwidth\pysigarglistclose{#3} + \pysigadjustitemsep +} +\newcommand{\pysigwithonelineperargwithonelinepertparg}[4]{ + % #1 = name, #2 = typelist, #3 = arglist, #4 = retann + % render each type parameter and argument on its own line + \item[#1\pysigtypelistopen\strut] + \leavevmode\par\nopagebreak + \begingroup + \let\sphinxparamcomma\sphinxparamcommaoneperline + % \sphinxtypeparam is treated similarly to \sphinxparam but since + % \sphinxoptional is not accepted in a type parameters list, we do + % not need the hook or the global definition + \let\spx@sphinxtypeparam\sphinxtypeparam + \def\sphinxtypeparam{\def\sphinxtypeparam{\par\spx@sphinxtypeparam}\spx@sphinxtypeparam}% + #2\par + \endgroup + \nopagebreak\noindent\kern-\labelwidth\pysigtypelistclose% + % render the rest of the signature like in \pysigwithonelineperarg + \pysigarglistopen\strut\par\nopagebreak + \begingroup + \let\sphinxparamcomma\sphinxparamcommaoneperline + \def\sphinxoptionalhook{\ifvmode\else\kern\sphinxoptionalextraspace\relax\fi}% + \global\let\spx@sphinxparam\sphinxparam + \gdef\sphinxparam{\gdef\sphinxparam{\par\spx@sphinxparam}\spx@sphinxparam}% + #3\par + \endgroup + \global\let\sphinxparam\spx@sphinxparam + \nopagebreak\noindent\kern-\labelwidth\pysigarglistclose{#4} + \pysigadjustitemsep +} +\newcommand{\pysiglinewithargsretwithonelinepertparg}[4]{ + % #1 = name, #2 = typelist, #3 = arglist, #4 = retann + % render each type parameter on its own line but the arguments list inline + \item[#1\pysigtypelistopen\strut] + \leavevmode\par\nopagebreak + \begingroup + \let\sphinxparamcomma\sphinxparamcommaoneperline + % \sphinxtypeparam is treated similarly to \sphinxparam but since + % \sphinxoptional is not accepted in a type parameters list, we do + % not need the hook or the global definition + \let\spx@sphinxtypeparam\sphinxtypeparam + \def\sphinxtypeparam{\def\sphinxtypeparam{\par\spx@sphinxtypeparam}\spx@sphinxtypeparam}% + #2\par + \endgroup + \nopagebreak\noindent\kern-\labelwidth\pysigtypelistclose% + % render the arguments list on one line + \pysigarglistopen#3\pysigarglistclose#4\strut + \pysigadjustitemsep +} +\newcommand{\pysigwithonelineperargwithtypelist}[4]{ + % #1 = name, #2 = typelist, #3 = arglist, #4 = retann + % render the type parameters list on one line, but each argument is rendered on its own line + % for \measuring@true see comment in \pysiglinewithargsret + \settowidth{\py@argswidth}{\measuring@true#1\pysigtypelistopen}% + \py@argswidth=\dimexpr\linewidth+\labelwidth-\py@argswidth\relax\relax + \item[{#1\pysigtypelistopen\parbox[t]{\py@argswidth}{% + \raggedright #2\pysigtypelistclose\pysigarglistopen\strut}\strut}] + % render the rest of the signature like in \pysigwithonelineperarg + \begingroup + \let\sphinxparamcomma\sphinxparamcommaoneperline + \def\sphinxoptionalhook{\ifvmode\else\kern\sphinxoptionalextraspace\relax\fi}% + \global\let\spx@sphinxparam\sphinxparam + \gdef\sphinxparam{\gdef\sphinxparam{\par\spx@sphinxparam}\spx@sphinxparam}% + #3\par + \endgroup + \global\let\sphinxparam\spx@sphinxparam + \nopagebreak\noindent\kern-\labelwidth\pysigarglistclose{#4} + \pysigadjustitemsep +} +\newcommand{\pysigadjustitemsep}{% + % adjust \itemsep to control the separation with the next signature + % sharing common description + \ifsphinxsigismultiline + % inside a multiline signature, no extra vertical spacing + % ("multiline" here does not refer to possibly long + % list of arguments, but to a cpp domain feature) + \itemsep\z@skip + \else + \itemsep\sphinxsignaturesep + \fi +} +\newif\ifsphinxsigismultiline +\newcommand{\pysigstartmultiline}{\sphinxsigismultilinetrue}% +\newcommand{\pysigstopmultiline}{\sphinxsigismultilinefalse\itemsep\sphinxsignaturesep}% + +% Production lists +% This simply outputs the lines as is, in monospace font. Refers #13326. +% (the left padding for multi-line alignment is from the nodes themselves, +% and latex is configured below to obey such horizontal whitespace). +% +% - The legacy code used longtable and hardcoded the separator as ::= +% via dedicated macros defined by the environment itself. +% - Here the separator is part of the node. Any extra LaTeX mark-up would +% have to originate from the writer itself to decorate it. +% - The legacy code used strangely \parindent and \indent. Possibly +% (unchecked) due to an earlier tabular usage, but a longtable does not +% work in paragraph mode, so \parindent was without effect and +% \indent only caused some extra blank line above display. +% - The table had some whitespace on its left, which we imitate here via +% \parindent usage (which works in our context...). +% +\newenvironment{productionlist}{% + \bigskip % imitate close enough legacy vertical whitespace, which was + % visibly excessive + \ttfamily % needed for space tokens to have same width as letters + \parindent1em % width of a "quad", font-dependent, usually circa width of 2 + % letters + \obeylines % line in = line out + \parskip\z@skip % prevent the parskip vertical whitespace between lines, + % which are technically to LaTeX now each its own paragraph + \@vobeyspaces % obey whitespace + % now a technicality to, only locally to this environment, prevent the + % suppression of indentation of first line, if it comes right after + % \section. Cf package indentfirst from which the code is borrowed. + \let\@afterindentfalse\@afterindenttrue\@afterindenttrue +}{% + \par % does not hurt... +} + +% Definition lists; requested by AMK for HOWTO documents. Probably useful +% elsewhere as well, so keep in in the general style support. +% +\newenvironment{definitions}{% + \begin{description}% + \def\term##1{\item[{##1}]\mbox{}\\*[0mm]}% +}{% + \end{description}% +} + +%% FROM DOCTUTILS LATEX WRITER +% +% The following is stuff copied from docutils' latex writer. +% +\newcommand{\optionlistlabel}[1]{\normalfont\bfseries #1 \hfill}% \bf deprecated +\newenvironment{optionlist}[1] +{\begin{list}{} + {\setlength{\labelwidth}{#1}% + \setlength{\rightmargin}{1cm}% + \setlength{\leftmargin}{\rightmargin}% + \addtolength{\leftmargin}{\labelwidth}% + \addtolength{\leftmargin}{\labelsep}% + \renewcommand{\makelabel}{\optionlistlabel}}% +}{\end{list}} + +\newlength{\lineblockindentation} +\setlength{\lineblockindentation}{2.5em} +\newenvironment{lineblock}[1] +{\begin{list}{} + {\setlength{\partopsep}{\parskip}% + \addtolength{\partopsep}{\baselineskip}% + \topsep0pt\itemsep0.15\baselineskip\parsep0pt + \leftmargin#1\relax}% + \raggedright} +{\end{list}} + +% From docutils.writers.latex2e +% inline markup (custom roles) +% \DUrole{#1}{#2} tries \DUrole#1{#2} +\providecommand*{\DUrole}[2]{% + \ifcsname DUrole\detokenize{#1}\endcsname + \csname DUrole\detokenize{#1}\endcsname{#2}% + \else% backwards compatibility: try \docutilsrole#1{#2} + \ifcsname docutilsrole\detokenize{#1}\endcsname + \csname docutilsrole\detokenize{#1}\endcsname{#2}% + \else + #2% + \fi + \fi +} + +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1\else\newlength{#1}\setlength{#1}{#2}\fi +} + +\DUprovidelength{\DUlineblockindent}{2.5em} +\ifdefined\DUlineblock\else + \newenvironment{DUlineblock}[1]{% + \list{}{\setlength{\partopsep}{\parskip}% + \addtolength{\partopsep}{\baselineskip}% + \setlength{\topsep}{0pt}% + \setlength{\itemsep}{0.15\baselineskip}% + \setlength{\parsep}{0pt}% + \setlength{\leftmargin}{#1}}% + \raggedright + } + {\endlist} +\fi + +\endinput diff --git a/build/latex/sphinxlatexshadowbox.sty b/build/latex/sphinxlatexshadowbox.sty new file mode 100644 index 0000000..53a3338 --- /dev/null +++ b/build/latex/sphinxlatexshadowbox.sty @@ -0,0 +1,178 @@ +%% TOPIC AND CONTENTS BOXES +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexshadowbox}[2024/07/28 v8.1.0 sphinxShadowBox] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - Environments: sphinxtopic, sphinxcontents, and sphinxsidebar. +% +% These wrappers replace at 8.1.0 former direct use of sphinxShadowBox +% environment which did not allow separate styling. +% +% - Commands: \sphinxstyletopictitle, \sphinxstylecontentstitle, and +% \sphinxstylesidebartitle. +% +% At 8.1.0 they default to use \sphinxdotitlerow whose definiion is done in +% sphinxlatexadmonitions.sty. There is also \sphinxstylesidebarsubtitle +% which does not use \sphinxdotitlerow. +% +% Dependencies (they do not need to be defined at time of loading): +% +% - of course the various colour and dimension options handled via sphinx.sty +% - dimension register \spx@image@maxheight from sphinxlatexgraphics.sty +% - \savenotes/\spewnotes from sphinxpackagefootnote.sty +% - \ifspx@inframed defined in sphinx.sty +% - \sphinxdotitlerow from sphinxlatexadmonitions.sty +% - \spx@boxes@fcolorbox@setup from sphinxpackageboxes.sty +% +\RequirePackage{framed} +% Those are required either before or after by sphinx.sty anyhow, but for +% clarity we list them here: +\RequirePackage{sphinxlatexgraphics} +\RequirePackage{sphinxpackagefootnote} +\RequirePackage{sphinxlatexadmonitions} +\RequirePackage{sphinxpackageboxes} + +% At 5.1.0 the code formerly here in a definition of \spx@ShadowFBox has been +% refactored to hand over to a more powerful \spx@boxes@fcolorbox provided by +% file sphinxpackageboxes.sty, it can draw rounded corners and add a background +% color. + +% At 6.2.0, \spx@ShadowFBox is so much simplified that it is now not +% separately defined but directly incorporated into the \FrameCommand +% definition done by sphinxShadowBox environment below. + +% Use framed.sty \MakeFramed/\endMakeFramed to allow page breaks for topic +% boxes. Originally Sphinx used \shadowbox from fancybox.sty but it did not +% allow pagebreaks (which was problematic for "contents" directive if there +% are many subsections). +% +% Docutils does not allow topic to be nested within topics or other body +% elements. But the LaTeX code here does allow it: +% +% - a topic inside another topic would be rendered in a minipage (thus not +% allowing pagebreaks). Its external frame would adapt perfectly to +% the *current (smaller) width for text*. +% +% - a topic inside (nested) lists or quote environments would have its frame +% take the *full width* of the page, but its text contents on the other hand +% would obey exactly the current indentation plus inner separation. This is +% in contrast with the framing used for literal blocks, also based, but in a +% more sophisticated way on usage of \MakeFramed/\endMakeFramed, and +% adjusting to current text indentation. +% +% At 8.1.0, sphinxShadowBox takes an optional argument #1 and uses it as +% \spx@boxes@fcolorbox@setup{#1} rather than \spx@boxes@fcolorbox@setup{topic}. +% Some hesitation whether to move this line to newly added sphinxtopic, +% sphinxcontents and sphinxsidebar environmments. But anyhow the environment +% also requires later knowing a few more things: sphinxTextColor and +% spx@@texextras. +% +% The #1 defaulting to topic must be such that all parameters expected by +% \spx@boxes@fcolorbox@setup actually do exist, see CSS options in sphinx.sty +% which is what defines them for contents, topic, and sidebar. +% +% Fortunately the #1 is not needed in \end{sphinxShadowBox} so we don't have +% to work around a LaTeX conception bug that such #1 can not be used as is in +% the definition of the \end part of an environment. +% +% MEMO: the "shadow" is not really drawn directly by this environment but +% indirectly via the configuration which is passed over to \spx@boxes@fcolorbox, +% which is the macro creating frame and (perhaps but not necessarily) a shadow. +\newenvironment{sphinxShadowBox}[1][topic]% + {% + \spx@boxes@fcolorbox@setup{#1}% + % we will use the dimen registers from sphinxpackageboxes.sty which now hold + % the values from options related to topic/contents + % MEMO: \spx@boxes@fcolorbox creates an \hbox but does not quit vertical + % mode; but in context of framed.sty's \FrameCommand TeX is already + % in restricted horizontal mode, so no need for a \leavevmode here. + \def\FrameCommand {\spx@boxes@fcolorbox}% + % 6.2.0 adds support for div.topic_box-decoration-break=slice. + % (it is yet undecided if slice style should inhibit a bottom shadow) + \@nameuse{ifspx@#1@border@open}% + \def\FirstFrameCommand + {\spx@boxes@fcolorbox@setup@openbottom\FrameCommand}% + \def\MidFrameCommand + {\spx@boxes@fcolorbox@setup@openboth \FrameCommand}% + \def\LastFrameCommand + {\spx@boxes@fcolorbox@setup@opentop \FrameCommand}% + \fi + \advance\spx@image@maxheight + -\dimexpr\spx@boxes@border@top+\spx@boxes@border@bottom + +\spx@boxes@padding@top+\spx@boxes@padding@bottom + +\ifdim\spx@boxes@shadow@yoffset<\z@-\fi\spx@boxes@shadow@yoffset + +\baselineskip\relax + % configure framed.sty not to add extra vertical spacing + \ltx@ifundefined{OuterFrameSep}{}{\OuterFrameSep\z@skip}% + % the \trivlist will add the vertical spacing on top and bottom which is + % typical of center environment as used in Sphinx <= 1.4.1 + % the \noindent has the effet of an extra blank line on top, to + % imitate closely the layout from Sphinx <= 1.4.1; the \FrameHeightAdjust + % will put top part of frame on this baseline. + \def\FrameHeightAdjust {\baselineskip}% + % use package footnote to handle footnotes + \savenotes + \trivlist\item\noindent + % use a minipage if we are already inside a framed environment + \ifspx@inframed\begin{minipage}{\linewidth}\fi + \MakeFramed {\spx@inframedtrue + % framed.sty puts into "\width" the added width (padding+border widths) + % adjust \hsize to what the contents must use + \advance\hsize-\width + % adjust LaTeX parameters to behave properly in indented/quoted contexts + \FrameRestore + % typeset the contents as in a minipage (Sphinx <= 1.4.1 used a minipage and + % itemize/enumerate are therein typeset more tightly, we want to keep + % that). We copy-paste from LaTeX source code but don't do a real minipage. + \@pboxswfalse + \let\@listdepth\@mplistdepth \@mplistdepth\z@ + \@minipagerestore + \@setminipage + }% + \color@begingroup % workaround upstream framed.sty bug + \@nameuse{ifspx@#1@withtextcolor}% + \color{sphinx#1TextColor}% + \fi + \@nameuse{spx@#1@TeXextras}% + }% + {% insert the "endminipage" code + \par\unskip + \color@endgroup % matches the \color@begingroup + \@minipagefalse + \endMakeFramed + \ifspx@inframed\end{minipage}\fi + \endtrivlist + % output the stored footnotes + \spewnotes + } + +% 8.1.0 +\newenvironment{sphinxtopic} + {\begin{sphinxShadowBox}[topic]}{\end{sphinxShadowBox}} +\newenvironment{sphinxcontents} + {\begin{sphinxShadowBox}[contents]}{\end{sphinxShadowBox}} +% Arguably sphinxsidebar should rather use a wrapfig or similar environment +% but this is so dysfunctional in LaTeX (except for self-written documents) +% so we prefer to not venture into such a potential quagmire and keep the +% legacy rendering using a full width display. +\newenvironment{sphinxsidebar} + {\begin{sphinxShadowBox}[sidebar]}{\end{sphinxShadowBox}} + +% TODO: decide if this should be in sphinxlatexstyletext.sty rather +% +% 8.1.0 styles topic/contents/sidebar with a title row, too. +% Prior to 8.1.0, definitions use \protected\def but there does not seem +% to be any reason so back to \newcommand. +\newcommand*\sphinxstyletopictitle[1]{\sphinxdotitlerow{topic}{#1}} +\newcommand*\sphinxstylecontentstitle[1]{\sphinxdotitlerow{contents}{#1}} +\newcommand*\sphinxstylesidebartitle[1]{\sphinxdotitlerow{sidebar}{#1}} +% No default color background for subtitle. The contents next are injected by +% LaTeX writer after a blank line in source hence will start a new paragrpah. +% The \sphinxAtStartPar here is only for coherence with other text paragraphs, +% but does not have serious necessity (its general role is to allow hyphenation +% for first word in narrow table cells). +\newcommand*\sphinxstylesidebarsubtitle[1]{\sphinxAtStartPar\textbf{#1}} + +\endinput diff --git a/build/latex/sphinxlatexstyleheadings.sty b/build/latex/sphinxlatexstyleheadings.sty new file mode 100644 index 0000000..08773c0 --- /dev/null +++ b/build/latex/sphinxlatexstyleheadings.sty @@ -0,0 +1,91 @@ +%% TITLES +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexstyleheadings}[2023/02/11 headings] + +\RequirePackage[nobottomtitles*]{titlesec} +% tests showed that this setting guarantees \section title has +% 3 lines of text following it on same page if near bottom. +\renewcommand\bottomtitlespace{6\baselineskip} +% the default setting of 0.2\textheight is about 11\baselineskip +% (for 10pt letterpaper documents) and may create large voids. + +\@ifpackagelater{titlesec}{2016/03/15}% + {\@ifpackagelater{titlesec}{2016/03/21}% + {}% + {\newif\ifsphinx@ttlpatch@ok + \IfFileExists{etoolbox.sty}{% + \RequirePackage{etoolbox}% + \patchcmd{\ttlh@hang}{\parindent\z@}{\parindent\z@\leavevmode}% + {\sphinx@ttlpatch@oktrue}{}% + \ifsphinx@ttlpatch@ok + \patchcmd{\ttlh@hang}{\noindent}{}{}{\sphinx@ttlpatch@okfalse}% + \fi + }{}% + \ifsphinx@ttlpatch@ok + \typeout{^^J Package Sphinx Info: ^^J + **** titlesec 2.10.1 successfully patched for bugfix ****^^J}% + \else + \AtEndDocument{\PackageWarningNoLine{sphinx}{^^J% +******** titlesec 2.10.1 has a bug, (section numbers disappear) ......|^^J% +******** and Sphinx could not patch it, perhaps because your local ...|^^J% +******** copy is already fixed without a changed release date. .......|^^J% +******** If not, you must update titlesec! ...........................|}}% + \sphinxbuildwarning{badtitlesec}% + \fi + }% + }{} + +% Augment the sectioning commands used to get our own font family in place, +% and reset some internal data items (\titleformat from titlesec package) +\titleformat{\section}{\Large\py@HeaderFamily}% + {\py@TitleColor\thesection}{0.5em}{\py@TitleColor} +\titleformat{\subsection}{\large\py@HeaderFamily}% + {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor} +% \normalsize added as work-around to a lualatex-ja upstream problem +% https://osdn.net/projects/luatex-ja/ticket/47321 +\titleformat{\subsubsection}{\normalsize\py@HeaderFamily}% + {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor} +% By default paragraphs (and subsubsections) will not be numbered because +% sphinxmanual.cls and sphinxhowto.cls set secnumdepth to 2 +\titleformat{\paragraph}{\normalsize\py@HeaderFamily}% + {\py@TitleColor\theparagraph}{0.5em}{\py@TitleColor} +\titleformat{\subparagraph}{\normalsize\py@HeaderFamily}% + {\py@TitleColor\thesubparagraph}{0.5em}{\py@TitleColor} + +% Since Sphinx 1.5, users should use HeaderFamily key to 'sphinxsetup' rather +% than defining their own \py@HeaderFamily command (which is still possible). +% Memo: \py@HeaderFamily is also used by \maketitle as defined in +% sphinxmanual.cls/sphinxhowto.cls +\newcommand{\py@HeaderFamily}{\spx@opt@HeaderFamily} + +% This sets up the fancy chapter headings that make the documents look +% at least a little better than the usual LaTeX output. +\@ifpackagewith{fncychap}{Bjarne}{ + \ChNameVar {\raggedleft\normalsize \py@HeaderFamily} + \ChNumVar {\raggedleft\Large \py@HeaderFamily} + \ChTitleVar{\raggedleft\Large \py@HeaderFamily} + % This creates (numbered) chapter heads without the leading \vspace*{}: + \def\@makechapterhead#1{% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \if@mainmatter + \DOCH + \fi + \fi + \interlinepenalty\@M + \if@mainmatter + \DOTI{#1}% + \else% + \DOTIS{#1}% + \fi + }} +}{}% <-- "false" clause of \@ifpackagewith + +% fix fncychap's bug which uses prematurely the \textwidth value +\@ifpackagewith{fncychap}{Bjornstrup} + {\AtBeginDocument{\mylen\textwidth\advance\mylen-2\myhi}}% + {}% <-- "false" clause of \@ifpackagewith + + +\endinput diff --git a/build/latex/sphinxlatexstylepage.sty b/build/latex/sphinxlatexstylepage.sty new file mode 100644 index 0000000..53f9e48 --- /dev/null +++ b/build/latex/sphinxlatexstylepage.sty @@ -0,0 +1,73 @@ +%% PAGE STYLING +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexstylepage}[2021/01/27 page styling] + +% Separate paragraphs by space by default. +\RequirePackage{parskip} + +% Style parameters and macros used by most documents here +\raggedbottom +\sloppy +\hbadness = 5000 % don't print trivial gripes + +% Require package fancyhdr except under memoir class +\@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}} +% Use \pagestyle{normal} as the primary pagestyle for text. +% Redefine the 'normal' header/footer style when using "fancyhdr" package: +\@ifpackageloaded{fancyhdr}{% + \ltx@ifundefined{c@chapter} + {% no \chapter, "howto" (non-Japanese) docclass + \fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[C]{{\py@HeaderFamily\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} + } + % Same as 'plain', this way we can use it in template + % FIXME: shouldn't this have a running header with Name and Release like 'manual'? + \fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[C]{{\py@HeaderFamily\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} + } + }% + {% classes with \chapter command + \fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[RO]{{\py@HeaderFamily\thepage}} + \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} + \fancyhead[RO]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \if@twoside + \fancyfoot[LE]{{\py@HeaderFamily\thepage}} + \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} + \fancyhead[LE]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \fi + \renewcommand{\headrulewidth}{0.4pt} + \renewcommand{\footrulewidth}{0.4pt} + % define chaptermark with \@chappos when \@chappos is available for Japanese + \ltx@ifundefined{@chappos}{} + {\def\chaptermark##1{\markboth{\@chapapp\space\thechapter\space\@chappos\space ##1}{}}} + } + % Update the plain style so we get the page number & footer line, + % but not a chapter or section title. This is to keep the first + % page of a chapter `clean.' + \fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[RO]{{\py@HeaderFamily\thepage}} + \if@twoside\fancyfoot[LE]{{\py@HeaderFamily\thepage}}\fi + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} + } + } + } + {% no fancyhdr: memoir class + % Provide default for 'normal' style simply as an alias of 'plain' style + % This way we can use \pagestyle{normal} in LaTeX template + \def\ps@normal{\ps@plain} + % Users of memoir class are invited to redefine 'normal' style in preamble + } + + +\endinput diff --git a/build/latex/sphinxlatexstyletext.sty b/build/latex/sphinxlatexstyletext.sty new file mode 100644 index 0000000..b6408cf --- /dev/null +++ b/build/latex/sphinxlatexstyletext.sty @@ -0,0 +1,149 @@ +%% TEXT STYLING +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatexstyletext}[2025/05/24 v9.0.0 text styling] + +% 7.4.0 has moved all that is related to admonitions to sphinxlatexadmonitions.sty +% 8.1.0 has moved topic/contents/sidebar to sphinxlatexshadowbox.sty +% Most everything left here consists of macros which are part of the latex markup +% produced by the Sphinx LaTeX writer. + +% Some custom font markup commands. +\protected\def\sphinxstrong#1{\textbf{#1}} +\protected\def\sphinxcode#1{\texttt{#1}} +\protected\def\sphinxbfcode#1{\textbf{\sphinxcode{#1}}} +\protected\def\sphinxemail#1{\textsf{#1}} +\protected\def\sphinxtablecontinued#1{\textsf{#1}} +\protected\def\sphinxtitleref#1{\emph{#1}} +\protected\def\sphinxmenuselection#1{\emph{#1}} +\protected\def\sphinxguilabel#1{\emph{#1}} +\protected\def\sphinxkeyboard#1{\sphinxcode{#1}} +\protected\def\sphinxaccelerator#1{\underline{#1}} +\protected\def\sphinxcrossref#1{\emph{#1}} +\protected\def\sphinxtermref#1{\emph{#1}} +\protected\def\sphinxsamedocref#1{\emph{#1}} +\protected\def\sphinxparam#1{\emph{#1}} +\protected\def\sphinxtypeparam#1{\emph{#1}} +% \optional is used for ``[, arg]``, i.e. desc_optional nodes. +\long\protected\def\sphinxoptional#1{% + {\sphinxoptionalhook\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}} +\let\sphinxoptionalhook\empty + +% additional customizable styling +\def\sphinxstyleindexentry #1{\texttt{#1}} +\def\sphinxstyleindexextra #1{ (\emph{#1})} +\def\sphinxstyleindexpageref #1{, \pageref{#1}} +\def\sphinxstyleindexpagemain#1{\textbf{#1}} +\def\spxentry{\@backslashchar spxentry}% let to \sphinxstyleindexentry in index +\def\spxextra{\@backslashchar spxextra}% let to \sphinxstyleindexextra in index +\def\sphinxstyleindexlettergroup #1% + {{\Large\sffamily#1}\nopagebreak\vspace{1mm}} +\def\sphinxstyleindexlettergroupDefault #1% + {{\Large\sffamily\sphinxnonalphabeticalgroupname}\nopagebreak\vspace{1mm}} +\protected\def\sphinxstyleothertitle #1{\textbf{#1}} +% \text.. commands do not allow multiple paragraphs +% attention, this one is not self-delimiting +\protected\def\sphinxstyletheadfamily {\sffamily} +\protected\def\sphinxstyleemphasis #1{\emph{#1}} +\protected\def\sphinxstyleliteralemphasis#1{\emph{\sphinxcode{#1}}} +\protected\def\sphinxstylestrong #1{\textbf{#1}} +\protected\def\sphinxstyleliteralstrong#1{\sphinxbfcode{#1}} +\protected\def\sphinxstyleabbreviation #1{\textsc{#1}} +\protected\def\sphinxstyleliteralintitle#1{\sphinxcode{#1}} +\newcommand*\sphinxstylecodecontinued[1]{{\footnotesize(#1)}}% +\newcommand*\sphinxstylecodecontinues[1]{{\footnotesize(#1)}}% +% figure legend comes after caption and may contain arbitrary body elements +\newenvironment{sphinxlegend}{\par\small}{\par} +% reduce hyperref "Token not allowed in a PDF string" warnings on PDF builds +\AtBeginDocument{\pdfstringdefDisableCommands{% +% all "protected" macros possibly ending up in section titles should be here +% next four were added so that URLs and internal links in titles can be allowed + \let\sphinxurl \@firstofone + \let\sphinxnolinkurl\@firstofone + \let\sphinxhref \@secondoftwo + \def\hyperref[#1]#2{#2}% for PDF bookmark to ignore #1 + \let\sphinxstyleemphasis \@firstofone + \let\sphinxstyleliteralemphasis \@firstofone + \let\sphinxstylestrong \@firstofone + \let\sphinxstyleliteralstrong \@firstofone + \let\sphinxstyleabbreviation \@firstofone + \let\sphinxstyleliteralintitle \@firstofone + \let\sphinxupquote \@firstofone + \let\sphinxstrong \@firstofone + \let\sphinxcode \@firstofone + \let\sphinxbfcode \@firstofone + \let\sphinxemail \@firstofone + \let\sphinxcrossref \@firstofone + \let\sphinxtermref \@firstofone + \let\sphinxsamedocref\@firstofone + \let\sphinxhyphen\sphinxhyphenforbookmarks + \def\PYG#1#2{#2}% (can not yet appear in section titles, but perhaps in future) +}} + +% Special characters +% +\def\sphinxparamcomma{, }% by default separate parameters with comma + space +% If the signature is rendered with one line per param, this wil be used +% instead (this \texttt makes the comma slightly more distinctive). +\def\sphinxparamcommaoneperline{\texttt{,}} +% +% The \kern\z@ is to prevent en-dash and em-dash TeX ligatures. +% A linebreak can occur after the dash in regular text (this is +% normal behaviour of "-" in TeX, it is not related to \kern\z@). +% +% Parsed-literals and inline literals also use the \sphinxhyphen +% but linebreaks there are prevented due to monospace font family. +% (xelatex needs a special addition, cf. sphinxlatexliterals.sty) +% +% Inside code-blocks, dashes are escaped via another macro, from +% Pygments latex output (search for \PYGZhy in sphinxlatexliterals.sty), +% and are configured to allow linebreaks despite the monospace font. +% (the #1 swallows the {} from \sphinxhyphen{} mark-up) +\protected\def\sphinxhyphen#1{-\kern\z@} +\protected\def\sphinxhyphennobreak#1{\mbox{-}} +% The {} from texescape mark-up is kept, else -- gives en-dash in PDF bookmark +\def\sphinxhyphenforbookmarks{-} + +% For curly braces inside \index macro +\def\sphinxleftcurlybrace{\{} +\def\sphinxrightcurlybrace{\}} + +% Declare Unicode characters used by linux tree command to pdflatex utf8/utf8x +\def\spx@bd#1#2{% + \leavevmode + \begingroup + \ifx\spx@bd@height \@undefined\def\spx@bd@height{\baselineskip}\fi + \ifx\spx@bd@width \@undefined\setbox0\hbox{0}\def\spx@bd@width{\wd0 }\fi + \ifx\spx@bd@thickness\@undefined\def\spx@bd@thickness{.6\p@}\fi + \ifx\spx@bd@lower \@undefined\def\spx@bd@lower{\dp\strutbox}\fi + \lower\spx@bd@lower#1{#2}% + \endgroup +}% +\@namedef{sphinx@u2500}% BOX DRAWINGS LIGHT HORIZONTAL + {\spx@bd{\vbox to\spx@bd@height} + {\vss\hrule\@height\spx@bd@thickness + \@width\spx@bd@width\vss}}% +\@namedef{sphinx@u2502}% BOX DRAWINGS LIGHT VERTICAL + {\spx@bd{\hb@xt@\spx@bd@width} + {\hss\vrule\@height\spx@bd@height + \@width \spx@bd@thickness\hss}}% +\@namedef{sphinx@u2514}% BOX DRAWINGS LIGHT UP AND RIGHT + {\spx@bd{\hb@xt@\spx@bd@width} + {\hss\raise.5\spx@bd@height + \hb@xt@\z@{\hss\vrule\@height.5\spx@bd@height + \@width \spx@bd@thickness\hss}% + \vbox to\spx@bd@height{\vss\hrule\@height\spx@bd@thickness + \@width.5\spx@bd@width\vss}}}% +\@namedef{sphinx@u251C}% BOX DRAWINGS LIGHT VERTICAL AND RIGHT + {\spx@bd{\hb@xt@\spx@bd@width} + {\hss + \hb@xt@\z@{\hss\vrule\@height\spx@bd@height + \@width \spx@bd@thickness\hss}% + \vbox to\spx@bd@height{\vss\hrule\@height\spx@bd@thickness + \@width.5\spx@bd@width\vss}}}% +\protected\def\sphinxunichar#1{\@nameuse{sphinx@u#1}}% + +% Tell TeX about pathological hyphenation cases: +\hyphenation{Base-HTTP-Re-quest-Hand-ler} + +\endinput diff --git a/build/latex/sphinxlatextables.sty b/build/latex/sphinxlatextables.sty new file mode 100644 index 0000000..61ff67f --- /dev/null +++ b/build/latex/sphinxlatextables.sty @@ -0,0 +1,1365 @@ +%% TABLES (WITH SUPPORT FOR MERGED CELLS OF GENERAL CONTENTS) +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxlatextables}[2025/12/30 v9.1.0 tables]% + +% Provides support for this output mark-up from Sphinx latex writer +% and table templates: +% +% - the tabulary and longtable environments from the eponymous packages +% - the varwidth environment +% - the >{} etc mark-up possible in tabularcolumns is from array package +% which is loaded by longtable and tabulary +% - \X, \Y, T column types; others (L, C, R, J) are from tabulary package +% - \sphinxaftertopcaption +% - \sphinxatlongtableend +% - \sphinxatlongtablestart +% - \sphinxattableend +% - \sphinxattablestart +% - \sphinxcapstartof +% - \sphinxcolwidth +% - \sphinxlongtablecapskipadjust +% - \sphinxmultirow +% - \sphinxstartmulticolumn +% - \sphinxstopmulticolumn +% - \sphinxtablestrut +% - \sphinxthecaptionisattop +% - \sphinxthelongtablecaptionisattop +% - \sphinxhline +% - \sphinxcline +% - \sphinxvlinecrossing +% - \sphinxfixclines +% - \sphinxtoprule +% - \sphinxmidrule +% - \sphinxbottomrule +% - \sphinxtableatstartofbodyhook +% - \sphinxtableafterendhook +% - \sphinxthistablewithglobalstyle +% - \sphinxthistablewithbooktabsstyle +% - \sphinxthistablewithborderlessstyle +% - \sphinxthistablewithstandardstyle +% - \sphinxthistablewithcolorrowsstyle +% - \sphinxthistablewithnocolorrowsstyle +% - \sphinxthistablewithvlinesstyle +% - \sphinxthistablewithnovlinesstyle +% - \sphinxbeforeendvarwidth + +% At 9.0, ALL table cell contents are wrapped into a varwidth environment. +% This helps solve issues such as #3447, #8828, and helps use tabulary +% in many more cases hence obtain better looking tables. +\def\sphinxbeforeendvarwidth{\par\vskip-\baselineskip\hbox{\strut}} +% MEMO: Mark-up uses the above macro right before all \end{varwdith} so that +% if the cell in a row extends lower than the others, its last line acquires +% standard "depth". Else it may lack any depth if without descenders such as +% "p" or "q" letters and the horizontal line or color panel will look strange. +% It originates in PR #3435 from 2017 which solved *many* table issues for +% merged cells (and injected the varwidth technique now at 9.0 applied to +% all cells). The original used \vbox{\hbox{\strut}} but that \vbox appears +% to do nothing, and it was decided after some testing (July 2025) to remove +% it, the original rationale for it being now lost. + +% These conditionals added at 9.0 for nested tables not to break row colors +% (#13635). Nested tables are only partially supported by Sphinx LaTeX. +% The method here is with no changes to neither writer nor templates. +\newif\ifspx@intable +\newif\ifspx@thistableisnested +% Try to allow nested tables in a longtable. But tabulary causes problems. +\newif\ifspx@longtable +% +% Also provides user command (see docs) +% - \sphixncolorblend +% (Sphinx 7.4.0 now requires xcolor, so \sphinxcolorblend does not check +% its availability anymore) +% +% Executes \RequirePackage for: +% +% - tabulary +% - longtable +% - varwidth +% - colortbl +% - booktabs if 'booktabs' in latex_table_style +% +% Extends tabulary and longtable via patches and custom macros to support +% merged cells possibly containing code-blocks in complex tables + +\RequirePackage{tabulary} +% tabulary has a bug with its re-definition of \multicolumn in its first pass +% which is not \long. But now Sphinx does not use LaTeX's \multicolumn but its +% own macro. Hence we don't even need to patch tabulary. +% +% X or S (Sphinx) may have meanings if some table package is loaded hence +% \X was chosen to avoid possibility of conflict +\newcolumntype{\X}[2]{p{\dimexpr + (\linewidth-\spx@arrayrulewidth)*#1/#2-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{\Y}[1]{p{\dimexpr + #1\dimexpr\linewidth-\spx@arrayrulewidth\relax-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +% \spx@arrayrulewidth is used internally and its meaning will be set according +% to the table type; no extra user code should modify it. In particular any +% \setlength{\spx@arrayrulewidth}{...} may break all of LaTeX... (really...) +\def\spx@arrayrulewidth{\arrayrulewidth}% 5.3.0, to be adjusted by each table +% using here T (for Tabulary) feels less of a problem than the X could be +\newcolumntype{T}{J}% +% For tables allowing pagebreaks +\RequirePackage{longtable} +% User interface to set-up whitespace before and after tables: +\newcommand*\sphinxtablepre {0pt}% +\newcommand*\sphinxtablepost{\medskipamount}% +% Space from caption baseline to top of table or frame of literal-block +\newcommand*\sphinxbelowcaptionspace{.5\sphinxbaselineskip}% +% as one can not use \baselineskip from inside longtable (it is zero there) +% we need \sphinxbaselineskip, which defaults to \baselineskip +\def\sphinxbaselineskip{\baselineskip}% +% The following is to ensure that, whether tabular(y) or longtable: +% - if a caption is on top of table: +% a) the space between its last baseline and the top rule of table is +% exactly \sphinxbelowcaptionspace +% b) the space from last baseline of previous text to first baseline of +% caption is exactly \parskip+\baselineskip+ height of a strut. +% c) the caption text will wrap at width \LTcapwidth (4in) +% - make sure this works also if "caption" package is loaded by user +% (with its width or margin option taking place of \LTcapwidth role) +% TODO: obtain same for caption of literal block: a) & c) DONE, b) TO BE DONE +% +% To modify space below such top caption, adjust \sphinxbelowcaptionspace +% To add or remove space above such top caption, adjust \sphinxtablepre: +% notice that \abovecaptionskip, \belowcaptionskip, \LTpre are **ignored** +% A. Table with longtable +\def\sphinxatlongtablestart + {\par + \vskip\parskip + \vskip\dimexpr\sphinxtablepre\relax % adjust vertical position + \vbox{}% get correct baseline from above + \LTpre\z@skip\LTpost\z@skip % set to zero longtable's own skips + \edef\sphinxbaselineskip{\dimexpr\the\dimexpr\baselineskip\relax\relax}% + \spx@inframedtrue % message to sphinxheavybox + \spx@table@setnestedflags + \spx@longtabletrue +} +% Compatibility with caption package +\def\sphinxthelongtablecaptionisattop{% + \spx@ifcaptionpackage{\noalign{\vskip-\belowcaptionskip}}{}% +}% +% Achieves exactly \sphinxbelowcaptionspace below longtable caption +\def\sphinxlongtablecapskipadjust + {\dimexpr-\dp\strutbox + -\spx@ifcaptionpackage{\abovecaptionskip}{\sphinxbaselineskip}% + +\sphinxbelowcaptionspace\relax}% +\def\sphinxatlongtableend{\@nobreakfalse % latex3/latex2e#173 + \prevdepth\z@\vskip\sphinxtablepost\relax}% +% B. Table with tabular or tabulary +\def\sphinxattablestart{\par + \ifvmode % guard against being nested in a table cell + \vskip\dimexpr\sphinxtablepre\relax + \fi + \spx@inframedtrue % message to sphinxheavybox + \spx@table@setnestedflags + }% +% MEMO: this happens inside a savenotes environment and hence flags +% are reset on exit of it. +\def\spx@table@setnestedflags{% Issue #13635 + \ifspx@intable + \let\spx@table@resetcolortbl\spx@nestedtable@resetcolortbl + \spx@thistableisnestedtrue + \else + \spx@intabletrue + \fi + }% +\def\sphinxattableend{% + \@nobreakfalse % <- probably unneeded as this is not a longtable + \ifvmode % guard against being nested in a table cell + \prevdepth\z@\vskip\sphinxtablepost\relax + \fi +}% +% This is used by tabular and tabulary templates +\newcommand*\sphinxcapstartof[1]{% + \vskip\parskip + \vbox{}% force baselineskip for good positioning by capstart of hyperanchor + % hyperref puts the anchor 6pt above this baseline; in case of caption + % this baseline will be \ht\strutbox above first baseline of caption + \def\@captype{#1}% + \capstart +% move back vertically, as tabular (or its caption) will compensate + \vskip-\baselineskip\vskip-\parskip +}% +\def\sphinxthecaptionisattop{% locate it after \sphinxcapstartof + \spx@ifcaptionpackage + {\caption@setposition{t}% + \vskip\baselineskip\vskip\parskip % undo those from \sphinxcapstartof + \vskip-\belowcaptionskip % anticipate caption package skip + % caption package uses a \vbox, not a \vtop, so "single line" case + % gives different result from "multi-line" without this: + \nointerlineskip + }% + {}% +}% +\def\sphinxthecaptionisatbottom{% (not finalized; for template usage) + \spx@ifcaptionpackage{\caption@setposition{b}}{}% +}% +% The aim of \sphinxcaption is to apply to tabular(y) the maximal width +% of caption as done by longtable +\def\sphinxtablecapwidth{\LTcapwidth}% +\newcommand\sphinxcaption{\@dblarg\spx@caption}% +\long\def\spx@caption[#1]#2{% + \noindent\hb@xt@\linewidth{\hss + \vtop{\@tempdima\dimexpr\sphinxtablecapwidth\relax +% don't exceed linewidth for the caption width + \ifdim\@tempdima>\linewidth\hsize\linewidth\else\hsize\@tempdima\fi +% longtable ignores \abovecaptionskip/\belowcaptionskip, so do the same here + \abovecaptionskip\sphinxabovecaptionskip % \z@skip + \belowcaptionskip\sphinxbelowcaptionskip % \z@skip + \caption[{#1}]% + {\strut\ignorespaces#2\ifhmode\unskip\@finalstrut\strutbox\fi}% + }\hss}% + \par\prevdepth\dp\strutbox +}% +\def\sphinxabovecaptionskip{\z@skip}% Do not use! Flagged for removal +\def\sphinxbelowcaptionskip{\z@skip}% Do not use! Flagged for removal +% This wrapper of \abovecaptionskip is used in sphinxVerbatim for top +% caption, and with another value in sphinxVerbatimintable +% TODO: To unify space above caption of a code-block with the one above +% caption of a table/longtable, \abovecaptionskip must not be used +% This auxiliary will get renamed and receive a different meaning +% in future. +\def\spx@abovecaptionskip{\abovecaptionskip}% +% Achieve \sphinxbelowcaptionspace below a caption located above a tabular +% or a tabulary +\newcommand\sphinxaftertopcaption +{% + \spx@ifcaptionpackage + {\par\prevdepth\dp\strutbox\nobreak\vskip-\abovecaptionskip}{\nobreak}% + \vskip\dimexpr\sphinxbelowcaptionspace\relax + \vskip-\baselineskip\vskip-\parskip +}% +% varwidth is crucial for our handling of general contents in merged cells +\RequirePackage{varwidth} +% but addition of a compatibility patch with hyperref is needed +% (tested with varwidth v 0.92 Mar 2009) +\AtBeginDocument {% + \let\@@vwid@Hy@raisedlink\Hy@raisedlink + \long\def\@vwid@Hy@raisedlink#1{\@vwid@wrap{\@@vwid@Hy@raisedlink{#1}}}% + \edef\@vwid@setup{% + \let\noexpand\Hy@raisedlink\noexpand\@vwid@Hy@raisedlink % HYPERREF ! + \unexpanded\expandafter{\@vwid@setup}}% +}% + +% NOTA BENE: since the multicolumn and multirow code was written Sphinx +% decided to prefix non public internal macros by \spx@ and in fact all +% such macros here should now be prefixed by \spx@table@, but doing the +% update is delayed to later. (written at 5.3.0) + +%%%%%%%%%%%%%%%%%%%%% +% --- MULTICOLUMN --- +% standard LaTeX's \multicolumn +% 1. does not allow verbatim contents, +% 2. interacts very poorly with tabulary. +% +% It is needed to write own macros for Sphinx: to allow code-blocks in merged +% cells rendered by tabular/longtable, and to allow multi-column cells with +% paragraphs to be taken into account sanely by tabulary algorithm for column +% widths. +% +% This requires quite a bit of hacking. First, in Sphinx, the multi-column +% contents will *always* be wrapped in a varwidth environment. The issue +% becomes to pass it the correct target width. We must trick tabulary into +% believing the multicolumn is simply separate columns, else tabulary does not +% incorporate the contents in its algorithm. But then we must clear the +% vertical rules... +% +% configuration of tabulary +\setlength{\tymin}{3\fontcharwd\font`0 }% minimal width of "squeezed" columns +\setlength{\tymax}{3000pt}% allow enough room for paragraphs to "compete" +% +% MEMO: tabulary initially renders cell contents "horizontally" to measure +% them and compare their relative importance. Its goal is to choose the +% column width so that, roughly, all columns will look about evenly +% filled. "Horizontal" rendering is incompatible with many LaTeX +% structures such as lists, so prior to Sphinx 9.0 cells with such +% "problematic" contents caused Sphinx to use tabular not tabulary; the +% tabular would then render each column in absence of :widths: option or +% tabularcolumns directive the same width equal to available text width +% divided by number of columns. At 9.0, "problematic" contents is +% wrapped into a "varwidth" environment, as was already done formerly +% for merged cells, and this avoids tabulary causing errors such as +% "incompatible with LR mode"; \sphinxcolwidth is used which sets +% the initial horizontal width for "varwidth". In the first tabulary +% pass, \sphinxcolwidth is configured (by us) to use \tymax. +% +% During testing, it was determined that the former 10000pt setting for +% \tymax would cause "Dimension too large" TeX error if two columns or +% more had cells containing admonitions (such contents does not allow +% "varwidth" to reduce the width automatically). So we use now 3000pt +% which allows up to 5 such columns while being large enough for +% tabulary algorithm to give good results for cells containing a few +% dozen words. The tabulary default of 2\textwidth proves to be too +% small for that. +% +% we need access to tabulary's final computed width. \@tempdima is too volatile +% to hope it has kept tabulary's value when \sphinxcolwidth needs it. +\newdimen\sphinx@TY@tablewidth +\def\tabulary{% + \def\TY@final{\sphinx@TY@tablewidth\@tempdima\tabular}% + \let\endTY@final\endtabular + \TY@tabular}% +% next hack is needed only if user has set latex_use_latex_multicolumn to True: +% it fixes tabulary's bug with \multicolumn defined "short" in first pass. (if +% upstream tabulary adds a \long, our extra one causes no harm) +\def\sphinx@tempa #1\def\multicolumn#2#3#4#5#6#7#8#9\sphinx@tempa + {\def\TY@tab{#1\long\def\multicolumn####1####2####3{\multispan####1\relax}#9}}% +\expandafter\sphinx@tempa\TY@tab\sphinx@tempa +% +% TN. 1: as \omit is never executed, Sphinx multicolumn does not need to worry +% like standard multicolumn about |l| vs l|. On the other hand it assumes +% columns are separated by a | ... (if not it will add extraneous +% \arrayrulewidth space for each column separation in its estimate of available +% width). +% +% Update at 5.3.0: code uses \spx@arrayrulewidth which is kept in sync with the +% table column specification (aka preamble): +% - no | in preamble: \spx@arrayrulewidth -> \z@ +% - at least a | in the preamble: \spx@arrayrulewidth -> \arrayrulewidth +% This is used for computation of merged cells widths. Mixed preambles using +% at least a | but not using it for all columns (as can be obtained via the +% tabularcolumns directive) may cause some merged cells contents to be slightly +% shifted to the left as they assume merged columns are | separated where in +% fact they perhaps are not. +% +% TN. 1b: as Sphinx multicolumn uses neither \omit nor \span, it can not +% (easily) get rid of extra macros from >{...} or <{...} between columns. At +% least, it has been made compatible with colortbl's \columncolor. +% +% TN. 2: tabulary's second pass is handled like tabular/longtable's single +% pass, with the difference that we hacked \TY@final to set in +% \sphinx@TY@tablewidth the final target width as computed by tabulary. This is +% needed only to handle columns with a "horizontal" specifier: "p" type columns +% (inclusive of tabulary's LJRC) holds the target column width in the +% \linewidth dimension. +% +% TN. 3: use of \begin{sphinxmulticolumn}...\end{sphinxmulticolumn} mark-up +% would need some hacking around the fact that groups can not span across table +% cells (the code does inserts & tokens, see TN1b). It was decided to keep it +% simple with \sphinxstartmulticolumn...\sphinxstopmulticolumn. +% +% **** ATTENTION: Sphinx does generate at least some nested tables in LaTeX +% **** TODO: clarify if next paragraph means we must raise an +% **** if LaTeX writer detects a merged cell inside nested table. +% MEMO about nesting: if sphinxmulticolumn is encountered in a nested tabular +% inside a tabulary it will think to be at top level in the tabulary. +% +% 5.3.0 adds a check for multirow as single-row multi-column will allow a row +% colour but multi-row multi-column should not. +% Attention that this assumes \sphinxstartmulticolumn is always followed +% in latex mark-up either by \sphinxmultirow or \begin (from \begin{varwidth}). +\def\sphinxstartmulticolumn#1#2{% + \ifx\sphinxmultirow#2% + \gdef\spx@table@hackCT@inmergedcell{\spx@table@hackCT@nocolor}% + \else + \global\let\spx@table@hackCT@inmergedcell\spx@@table@hackCT@inmergedcell + \fi + \sphinx@startmulticolumn{#1}#2% +}% +\def\sphinx@startmulticolumn{% + \ifx\equation$% $ tabulary's first pass + \expandafter\sphinx@TYI@start@multicolumn + \else % either not tabulary or tabulary's second pass + \expandafter\sphinx@start@multicolumn + \fi +}% +\def\sphinxstopmulticolumn{% + \ifx\equation$% $ tabulary's first pass + \expandafter\sphinx@TYI@stop@multicolumn + \else % either not tabulary or tabulary's second pass + \ignorespaces + \fi +}% +\def\sphinx@TYI@start@multicolumn#1{% + % use \gdef always to avoid stack space build up + \gdef\sphinx@tempa{#1}\begingroup\setbox\z@\hbox\bgroup +}% +\def\sphinx@TYI@stop@multicolumn{\egroup % varwidth was used with \tymax + \xdef\sphinx@tempb{\the\dimexpr\wd\z@/\sphinx@tempa}% per column width + \endgroup + \expandafter\sphinx@TYI@multispan\expandafter{\sphinx@tempa}% +}% +\def\sphinx@TYI@multispan #1{% + \kern\sphinx@tempb\ignorespaces % the per column occupied width + \ifnum#1>\@ne % repeat, taking into account subtleties of TeX's & ... + \expandafter\sphinx@TYI@multispan@next\expandafter{\the\numexpr#1-\@ne\expandafter}% + \fi +}% +\def\sphinx@TYI@multispan@next{&\relax\sphinx@TYI@multispan}% +% +% Now the branch handling either the second pass of tabulary or the single pass +% of tabular/longtable. This is the delicate part where we gather the +% dimensions from the p columns either set-up by tabulary or by user p column +% or Sphinx \X, \Y columns. The difficulty is that to get the said width, the +% template must be inserted (other hacks would be horribly complicated except +% if we rewrote crucial parts of LaTeX's \@array !) and we can not do +% \omit\span like standard \multicolumn's easy approach. Thus we must cancel +% the \vrule separators. Also, perhaps the column specifier is of the l, c, r +% type, then we attempt an ad hoc rescue to give varwidth a reasonable target +% width. +\def\sphinx@start@multicolumn#1{% + \gdef\sphinx@multiwidth{0pt}\gdef\sphinx@tempa{#1}\sphinx@multispan{#1}% +}% +\def\sphinx@multispan #1{% + \ifnum#1=\@ne\expandafter\sphinx@multispan@end + \else\expandafter\sphinx@multispan@next + \fi {#1}% +}% +\def\sphinx@multispan@next #1{% + % trick to recognize L, C, R, J or p, m, b type columns + \ifdim\baselineskip>\z@ + \gdef\sphinx@tempb{\linewidth}% + \else + % if in an l, r, c type column, try and hope for the best + \xdef\sphinx@tempb{\the\dimexpr(\ifx\TY@final\@undefined\linewidth\else + \sphinx@TY@tablewidth\fi-\spx@arrayrulewidth)/\sphinx@tempa + -\tw@\tabcolsep-\spx@arrayrulewidth\relax}% + \fi + \noindent\kern\sphinx@tempb\relax + \xdef\sphinx@multiwidth + {\the\dimexpr\sphinx@multiwidth+\sphinx@tempb+\tw@\tabcolsep+\spx@arrayrulewidth}% + \spx@table@hackCT@fixcolorpanel + % silence a | column separator in our merged cell + \spx@table@hackCT@inhibitvline + % prevent column colours to interfere with our multi-column but allow row + % colour (we can't obey a \cellcolor as it has not be seen yet at this stage) + \spx@table@hackCT@inmergedcell&\relax + % repeat + \expandafter\sphinx@multispan\expandafter{\the\numexpr#1-\@ne}% +}% +\def\sphinx@multispan@end#1{% + % first, trace back our steps horizontally + \noindent\kern-\dimexpr\sphinx@multiwidth\relax + % and now we set the final computed width for the varwidth environment + \ifdim\baselineskip>\z@ + \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+\linewidth}% + \else + \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+ + (\ifx\TY@final\@undefined\linewidth\else + \sphinx@TY@tablewidth\fi-\spx@arrayrulewidth)/\sphinx@tempa + -\tw@\tabcolsep-\spx@arrayrulewidth\relax}% + \fi + % last cell of the multi-column + \aftergroup\spx@table@hackCT@fixcolorpanel + \aftergroup\spx@table@hackCT@inmergedcell +}% +\newcommand*\sphinxcolwidth[2]{% + % this dimension will always be used for varwidth, and serves as maximum + % width for cells whose contents are wrapped in varwidth environment. + \ifnum#1>\@ne % multi-column (and possibly also multi-row) + % we wrote our own multicolumn code especially to handle that (and allow + % verbatim contents) + \ifx\equation$%$ + \tymax % first pass of tabulary (cf MEMO above regarding nesting) + \else % the \@gobble thing is for compatibility with standard \multicolumn + \sphinx@multiwidth\@gobble{#1/#2}% + \fi + \else % single column multirow + \ifx\TY@final\@undefined % not a tabulary. + \ifdim\baselineskip>\z@ + % in a p{..} type column, \linewidth is the target box width + \linewidth + \else + % l, c, r columns. Do our best. + \dimexpr(\linewidth-\spx@arrayrulewidth)/#2- + \tw@\tabcolsep-\spx@arrayrulewidth\relax + \fi + \else % in tabulary + \ifx\equation$%$% first pass + \tymax % it is set to a big value so that paragraphs can express themselves + \else + % second pass. + \ifdim\baselineskip>\z@ + \linewidth % in a L, R, C, J column or a p, \X, \Y ... + \else + % we have hacked \TY@final to put in \sphinx@TY@tablewidth the table width + \dimexpr(\sphinx@TY@tablewidth-\spx@arrayrulewidth)/#2- + \tw@\tabcolsep-\spx@arrayrulewidth\relax + \fi + \fi + \fi + \fi +}% +% fallback default in case user has set latex_use_latex_multicolumn to True: +% \sphinxcolwidth will use this only inside LaTeX's standard \multicolumn +\def\sphinx@multiwidth #1#2{\dimexpr % #1 to gobble the \@gobble (!) + (\ifx\TY@final\@undefined\linewidth\else\sphinx@TY@tablewidth\fi + -\spx@arrayrulewidth)*#2-\tw@\tabcolsep-\spx@arrayrulewidth\relax}% + +% \spx@table@hackCT@inhibitvline +% packages like colortbl add group levels, we need to "climb back up" to be +% able to hack the \vline and also the colortbl inserted tokens. The hack +% sets the \arrayrulewidth to \z@ to inhibit a | separator at right end +% of the cell, if present (our code does not use \omit so can not avoid the +% \vline insertion, but setting its width to zero makes it do nothing). +% Some subtlety with colour panels must be taken care of. +\def\spx@table@hackCT@inhibitvline{\ifnum\currentgrouptype=6\relax + \kern\spx@arrayrulewidth % will be compensated by extra colour panel left overhang + \arrayrulewidth\z@% trick to inhibit the {\vrule width \arrayrulewidth} + \else\aftergroup\spx@table@hackCT@inhibitvline\fi}% + +% hacking around colour matters +% Sphinx 1.6 comment: +% It turns out \CT@row@color is not expanded contrarily to \CT@column@color +% during LaTeX+colortbl preamble preparation, hence it would be possible for +% \CT@setup to discard only the column color and choose to obey or not +% row color and cell color. It would even be possible to propagate cell color +% to row color for the duration of the Sphinx multicolumn... the (provisional?) +% choice has been made to cancel the colortbl colours for the multicolumn +% duration. +% Sphinx 5.3.0 comment: +% - colortbl has no mechanism to disable colour background in a given cell: +% \cellcolor triggers one more \color, but has no possibility to revert +% a previously emitted \color, only to override it via an additional \color +% - prior to 5.3.0, Sphinx did not officially support colour in tables, +% but it did have a mechanism to protect merged cells from being partly +% covered by colour panels at various places. At 5.3.0 this mechanism +% is relaxed a bit to allow row colour for a single-row merged cell. +% +% fixcolorpanel +\def\spx@table@hackCT@fixcolorpanel{\ifnum\currentgrouptype=6\relax + \edef\spx@table@leftcolorpanelextra + % \edef as \arrayrulewidth will be set to \z@ next, + % hence also \spx@arrayrulewidth... + {\sphinxcolorpanelextraoverhang+\the\spx@arrayrulewidth}% + \else\aftergroup\spx@table@hackCT@fixcolorpanel\fi}% +% +% inmergedcell +% \spx@table@hackCT@inmergedcell will be locally set to either this +% \spx@@table@hackCT@inmergedcell or to \spx@table@hackCT@nocolor +% "\let\spx@original@CT@setup\CT@setup" is done after loading colortbl +\def\spx@@table@hackCT@inmergedcell{\ifnum\currentgrouptype=6\relax + \let\CT@setup\spx@CT@setup@inmergedcell + \else\aftergroup\spx@@table@hackCT@inmergedcell\fi +}% +\newif\ifspx@table@inmergedcell +\def\spx@CT@setup@inmergedcell #1\endgroup{% + % - obey only row color and disable effect of \sphinxcolorblend + % - turn on the inmergedcell boolean to signal to \CT@row@color + \spx@original@CT@setup + \spx@table@inmergedcelltrue % needed by \CT@row@color + % deactivate effect of \sphinxcolorblend if it happened at all + \ifdefined\blendcolors\blendcolors{}\fi + \CT@row@color + \CT@do@color + \global\let\CT@cell@color\relax + \endgroup +}% +% +% nocolor +\def\spx@table@hackCT@nocolor{\ifnum\currentgrouptype=6\relax +% sadly \CT@column@color is possibly already expanded so we can't +% simply do \let\CT@column@color\relax etc... +% admittedly we could perhaps hack \CT@color but well + \let\CT@setup\spx@CT@setup@nocolor + \else\aftergroup\spx@table@hackCT@nocolor\fi +} +\def\spx@CT@setup@nocolor#1\endgroup{% + \global\let\CT@cell@color\relax + % the above fix was added at 5.3.0 + % formerly a \cellcolor added by a raw latex directive in the merged cell + % would have caused colour to apply to the *next* cell after the merged + % one; we don't support \cellcolor from merged cells contents anyhow. + \endgroup} +% +% norowcolor +\def\spx@table@hackCT@norowcolor{% +% a bit easier although merged cells complicate the matter as they do need +% to keep the rowcolor; and we can't know yet if we are in a merged cell + \ifnum\currentgrouptype=6\relax + \ifx\CT@row@color\relax + \else + \let\spx@saved@CT@row@color\CT@row@color + \def\CT@row@color{% + \ifspx@table@inmergedcell\expandafter\spx@saved@CT@row@color\fi + }% + \fi + \else\aftergroup\spx@table@hackCT@norowcolor\fi +} +% +% \sphinxcolorblend +\def\spx@table@hackCT@colorblend{% + \ifnum\currentgrouptype=6\relax + \expandafter\blendcolors\spx@colorblendparam + % merged cells will do a \blendcolors{} to cancel the effet + % we can not know here yet if in merged cell as the boolean + % \ifspx@table@inmergedcell is not yet updated + \else + \aftergroup\spx@table@hackCT@colorblend + \fi +} +\def\sphinxcolorblend#1{\gdef\spx@colorblendparam{{#1}}\spx@table@hackCT@colorblend} + + +%%%%%%%%%%%%%%%%%% +% --- MULTIROW --- +% standard \multirow +% 1. does not allow verbatim contents, +% 2. does not allow blank lines in its argument, +% 3. its * specifier means to typeset "horizontally" which is very +% bad for paragraph content. 2016 version has = specifier but it +% must be used with p type columns only, else results are bad, +% 4. it requires manual intervention if the contents is too long to fit +% in the asked-for number of rows. +% 5. colour panels (either from \rowcolor or \columncolor) will hide +% the bottom part of multirow text, hence manual tuning is needed +% to put the multirow insertion at the _bottom_. +% +% The Sphinx solution consists in always having contents wrapped +% in a varwidth environment so that it makes sense to estimate how many +% lines it will occupy, and then ensure by insertion of suitable struts +% that the table rows have the needed height. The needed mark-up is done +% by LaTeX writer, which has its own id for the merged cells. +% +% The colour issue is "solved" by clearing colour panels in all cells, +% whether or not the multirow is single-column or multi-column. +% +% MEMO at 5.3.0: to allow a multirow cell in a single column to react to +% \columncolor correctly, it seems only way is that the contents +% are inserted by bottom cell (this is mentioned in multirow.sty doc, too). +% Sphinx could at Python level "move" the contents to that cell. But the +% mechanism used here via \sphinxtablestrut to enlarge rows to make room for +% the contents if needed becomes more challenging yet, because \sphinxtablestrut +% mark-up will be parsed by TeX *before* it sees the contents of the merged +% cell.. So it seems the best way would be to actually store the contents into +% some owned-by-Sphinx box storage which needs to be globally allocated to +% that usage ; then we need multiple such boxes, say at least 5 to cover +% 99% or use case. Or perhaps some trick with storing in a \vbox and recovering +% via some \vsplit but this becomes complicated... perhaps in future. +% +% In passing we obtain baseline alignments across rows (only if +% \arraystretch is 1, as LaTeX's does not obey \arraystretch in "p" +% multi-line contents, only first and last line...) +% +% TODO: examine the situation with \arraystretch > 1. The \extrarowheight +% is hopeless for multirow anyhow, it makes baseline alignment strictly +% impossible. +\newcommand\sphinxmultirow[2]{\begingroup + % #1 = nb of spanned rows, #2 = Sphinx id of "cell", #3 = contents + % but let's fetch #3 in a way allowing verbatim contents ! + \def\sphinx@nbofrows{#1}\def\sphinx@cellid{#2}% + \afterassignment\sphinx@multirow\let\next= +}% +\def\sphinx@multirow {% + \setbox\z@\hbox\bgroup\aftergroup\sphinx@@multirow\strut +}% +\def\sphinx@@multirow {% +% MEMO: we could check status of \CT@cell@color here, but unfortunately we +% can't know the exact height which will be covered by the cells in total +% (it may be more than our \box\z@ dimensions). We could use an \fcolorbox +% wrapper on \box\z@ but this will not extend precisely to the bottom rule. +% +% Only solution if we want to obey a raw \cellcolor, or a \columncolor, seems +% to delay unboxing the gathered contents as part of the bottom row with +% a suitable vertical adjustment... +% + % The contents, which is a varwidth environment, has been captured in + % \box0 (a \hbox). + % We have with \sphinx@cellid an assigned unique id. The goal is to give + % about the same height to all the involved rows. + % For this Sphinx will insert a \sphinxtablestrut{cell_id} mark-up + % in LaTeX file and the expansion of the latter will do the suitable thing. + \dimen@\dp\z@ + \dimen\tw@\ht\@arstrutbox + \advance\dimen@\dimen\tw@ + \advance\dimen\tw@\dp\@arstrutbox + \count@=\dimen@ % type conversion dim -> int + \count\tw@=\dimen\tw@ + \divide\count@\count\tw@ % TeX division truncates + \advance\dimen@-\count@\dimen\tw@ + % 1300sp is about 0.02pt. For comparison a rule default width is 0.4pt. + % (note that if \count@ holds 0, surely \dimen@>1300sp) + \ifdim\dimen@>1300sp \advance\count@\@ne \fi + % now \count@ holds the count L of needed "lines" + % and \sphinx@nbofrows holds the number N of rows + % we have L >= 1 and N >= 1 + % if L is a multiple of N, ... clear what to do ! + % else write L = qN + r, 1 <= r < N and we will + % arrange for each row to have enough space for: + % q+1 "lines" in each of the first r rows + % q "lines" in each of the (N-r) bottom rows + % for a total of (q+1) * r + q * (N-r) = q * N + r = L + % It is possible that q == 0. + \count\tw@\count@ + % the TeX division truncates + \divide\count\tw@\sphinx@nbofrows\relax + \count4\count\tw@ % q + \multiply\count\tw@\sphinx@nbofrows\relax + \advance\count@-\count\tw@ % r + \expandafter\xdef\csname sphinx@tablestrut_\sphinx@cellid\endcsname + {\noexpand\sphinx@tablestrut{\the\count4}{\the\count@}{\sphinx@cellid}}% + \dp\z@\z@ + % this will use the real height if it is >\ht\@arstrutbox + \sphinxtablestrut{\sphinx@cellid}\box\z@ + \endgroup % group was opened in \sphinxmultirow +}% +\newcommand*\sphinxtablestrut[1]{% + % #1 is a "cell_id", i.e. the id of a merged group of table cells + \csname sphinx@tablestrut_#1\endcsname +}% +% LaTeX typesets the table row by row, hence each execution can do +% an update for the next row. +\newcommand*\sphinx@tablestrut[3]{\begingroup + % #1 = q, #2 = (initially) r, #3 = cell_id, q+1 lines in first r rows + % if #2 = 0, create space for max(q,1) table lines + % if #2 > 0, create space for q+1 lines and decrement #2 + \leavevmode + \count@#1\relax + \ifnum#2=\z@ + \ifnum\count@=\z@\count@\@ne\fi + \else + % next row will be with a #2 decremented by one + \expandafter\xdef\csname sphinx@tablestrut_#3\endcsname + {\noexpand\sphinx@tablestrut{#1}{\the\numexpr#2-\@ne}{#3}}% + \advance\count@\@ne + \fi + \vrule\@height\ht\@arstrutbox + \@depth\dimexpr\count@\ht\@arstrutbox+\count@\dp\@arstrutbox-\ht\@arstrutbox\relax + \@width\z@ + \endgroup + % we need this to avoid colour panels hiding bottom parts of multirow text + \spx@table@hackCT@nocolor +}% + +%%%%%%%%%%%%%%%%%% +% --- STYLING --- +% + +% +% Support for colour in table +% +% Core LaTeX package (very old, part of texlive-latex-base on Debian distr.) +% providing \columncolor, \rowcolor, \cellcolor and \arrayrulecolor. +\RequirePackage{colortbl} +\let\spx@original@CT@setup\CT@setup + +% LaTeX's \cline has **strong** deficiencies +% ****************************************** +% We work around them via an added \sphinxfixclines{number of columns} in the +% table mark-up, and also extra mark-up \sphinxvlinecrossing{col no} for +% crossings not contiguous to any cline. To fix the gap at left extremity of a +% \cline, we redefine the core LaTeX \c@line because this avoids adjoining a +% small square with potential PDF viewer anti-aliasing issues. We waited +% after loading colortbl because it also redefines \c@line for it to obey the +% colour set by \arrayrulecolor. +% MEMO: booktabs package does *not* redefine \@cline so we are safe here. +\def\@cline#1-#2\@nil{% + \omit + \@multicnt#1% + \advance\@multispan\m@ne + \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi + \@multicnt#2% + \advance\@multicnt-#1% + \advance\@multispan\@ne + {\CT@arc@ +% start of Sphinx modification + \ifnum#1>\@ne\kern-\spx@arrayrulewidth\fi% fix gap at join with vertical lines +% end of Sphinx modification +% Comments: +% +% If we had the information whether the previous column ended with a | or +% not, we could decide what to do here. Alternatively the mark-up could +% use either original \cline or the one modified as here depending on case. +% One wonders why LaTeX does not provide itself the alternative as a +% complement to \cline, to use on case by case basis. +% Here we handle both at same time via using the \spx@arrayrulewidth which +% will be \z@ if no | at all so will induce here nothing. +% +% As a result Sphinx basically supports well only tables having either all +% columns |-separated, or no | at all, as it uses \spx@arrayrrulewidth in +% all columns (here and in multicolumn code). +% +% We also considered a method not modifying \c@line but it requires too +% much extra mark-up from Python LaTeX writer and/or extra LaTeX coding. +% back to LaTeX+colortbl code + \leaders\hrule\@height\arrayrulewidth\hfill}% + \cr +% the last one will need to be compensated, this is job of \sphinxclines + \noalign{\nobreak\vskip-\arrayrulewidth}% +} +\def\spx@table@fixvlinejoin{% + {\CT@arc@ % this is the color command set up by \arrayrulecolor + \vrule\@height\arrayrulewidth +% side remark: LaTeX has only a single \arrayrulewidth for all kinds +% for cell borders in table, horizontal or vertical... + \@depth\z@ + \@width\spx@arrayrulewidth + }% +} +% Sphinx LaTeX writer issues one such for each vertical line separating two +% contiguous multirow cells; i.e. those crossings which can are not already +% taken care of by our modified at left extremity \cline. +% One could imagine a more \...crossingS (plural) receiving a comma delimited +% list, which would simplify the mark-up but this would complexify both the +% Python and the LaTeX coding. +\def\sphinxtablevlinecrossing#1{% + \sphinxtabledecrementrownum + \omit + \@multispan{#1}% + \hfill + \spx@table@fixvlinejoin + \cr + \noalign{\nobreak\vskip-\arrayrulewidth}% +} +% This "fixclines" is also needed if no \sphinxcline emitted and is useful +% even in extreme case with no \sphinxvlinecrossing either, to give correct +% height to multirow extending across all table width assuming other rows are +% separated generally by an \hline, so as to keep coherent line spacing. +% +% It is designed to work ok even if no | separators are in the table (because +% \spx@table@fixvlinejoin uses \spx@arrayrulewidth which is \z@ in that case). +\def\sphinxtablefixclines#1{% #1 is the number of columns of the table + \sphinxtabledecrementrownum + \omit + \spx@table@fixvlinejoin% unneeded if first \cline started at column 1 but does + % not hurt; fills small gap at left-bordered table + \@multispan{#1}% + \hfill + \spx@table@fixvlinejoin% fill small gap at right-bordered table + \cr + % this final one does NO \vskip-\arrayrulewidth... that's the whole point + \noalign{\nobreak}% +} +%%%% end of \cline workarounds + +% +% - passing option "table" to xcolor also loads colortbl but we needed to +% load color or xcolor prior to the handling of the options +% +% - the \rowcolors command from [table]{xcolor} has various problems: +% +% * it is rigid and does not out-of-the-box allow a more complex scheme +% such as colorA+colorB+colorC+colorB+colorC+colorB+colorC... suitable to +% distinguish a header row. +% +% * its code does not export the used colour, an information which we may +% need for example to colourize the rule via \arrayrulecolor in the +% appropriate manner, for example to colourize the booktabs induced vertical +% whitespace to avoid gaps (if one wants to). +% +% * incompatibility with tabulary: the output depends on parity of total +% number of rows! +% +% * problems with longtable: the caption will receive a background colour +% panel, if we do not deactivate the \rowcolors action during definition of +% the headers and footers; this requires extra mark-up. Besides if we +% deactivate using \hiderowcolors during header and footer formation, the +% parity of the body rows is shifted, \rownum is even, not odd, at first body +% row. And setting \rownum at start of first body row is too late for +% influencing the colour. +% +% * it has a global impact and must be reset at each table. We can not +% issue it only once and it provides no public interface (without @) to +% cancel its effect conveniently (\hiderowcolors can only be used from +% *inside* a table.) +% +% * its core mechanism which increments the row count is triggered +% if a \cline is encountered... so this offsets the alternating colours... +% ... or not if there are two \cline's in the row... +% (as we will use same mechanism we have to correct this increment). +% +% So we need our own code. + +% Provide \rownum and rownum LaTeX counter (code copied from colortbl v1.0f) +\ltx@ifundefined{rownum}{% + \ltx@ifundefined{c@rownum}% + {\newcount\rownum\let\c@rownum\rownum}% + {\let\rownum\c@rownum}% + }% +{\let\c@rownum\rownum} +\providecommand\therownum{\arabic{rownum}} + +% extra overhang for color panels to avoid visual artifacts in pdf viewers +% (particularly if borderless) +\def\sphinxcolorpanelextraoverhang{0.1pt} +\def\spx@table@leftcolorpanelextra {\sphinxcolorpanelextraoverhang} +\def\spx@table@rightcolorpanelextra{\sphinxcolorpanelextraoverhang} +% the macro to which \CT@row@color will be set for coloured rows, serves both +% in header and body, the colours must have been defined at time of use +\def\spx@table@CT@row@color{\ifspx@table@inmergedcell + \CT@color{sphinxTableMergeColor}% + \else + \CT@color{sphinxTableRowColor}% + \fi + \@tempdimb\dimexpr\col@sep+\spx@table@leftcolorpanelextra\relax + \@tempdimc\dimexpr\col@sep+\spx@table@rightcolorpanelextra\relax + }% +% used by itself this will influence a single row if \CT@everycr is the +% colortbl one, to influences all rows the \CT@everycr must be modified (see +% below) +\def\sphinxrowcolorON {\global\let\CT@row@color\spx@table@CT@row@color}% +% this one turns off row colours until the next \sphinxrowcolorON +\def\sphinxrowcolorOFF{\global\let\CT@row@color\relax}% +% this one inhibits the row colour in one cell only (can be used as +% >{\sphinxnorowcolor} for turning off row colours in a given column) +\def\sphinxnorowcolor{\spx@table@hackCT@norowcolor}% + +% \sphinxtoprule (or rather \sphinxtabletoprulehook) will be modified by +% the colorrows class to execute this one: +\def\spx@table@@toprule@rowcolorON{% + \noalign{% + % Because of tabulary 2-pass system, the colour set-up at end of table + % would contaminate the header colours at start of table, so must reset + % them here. We want all header rows to obey same colours, so we don't + % use original \CT@everycr which sets \CT@row@color to \relax. + \global\CT@everycr{\the\everycr}% + \global\sphinxcolorlet{sphinxTableRowColor}{sphinxTableRowColorHeader}% + \global\sphinxcolorlet{sphinxTableMergeColor}{\sphinxTableMergeColorHeader}% + \sphinxrowcolorON + }% +}% + +% \sphinxtableatstartofbodyhook will be modified by colorrows class to +% execute this one; it starts the alternating colours and triggers increment +% or \rownum count at each new row (the xcolor base method for \rowcolors) +\def\spx@table@@startbodycolorrows{% + \noalign{% + \global\CT@everycr{% Nota Bene: in a longtable with \hline the \everycr is + % done two extra times! but 2 is even, so this is ok + \noalign{\global\advance\rownum\@ne % the xcolor \rowcolors base trick +% MEMO: colortbl \CT@row@color is expanded *after* the cell contents have been +% gathered and measured, so it can't be used to expose e.g. the colour to the +% cell contents macro code. Of course if it is known how the colour is chosen +% the procedure could be done from inside the cell. Simpler to expose the colour +% in a public name sphinxTableRowColor at start of the row in this \noalign. + \sphinxSwitchCaseRowColor\rownum + }% + \the\everycr + }% + \ifspx@thistableisnested + % Attention that tabulary does two passes so we need to push the + % initial rownum and, after the first pass, we must reset it! + % Fortunately Sphinx LaTeX writer makes parent table tabular or + % longtable if a nested table is a tabulary. So we don't need to + % worry about distinguishing if this or parent is tabulary. + \ifx\TY@final\@undefined % tabular + \spx@gpush@rownum + \else + \ifx\equation$% tabulary, first pass + \spx@gpush@rownum + \else % tabulary, second pass + \spx@gpop@rownum % reset \rownum + \spx@gpush@rownum% and push it again. + \fi + \fi + % To make nested tables stand out in a color row, we toggle the parity. + % TODO: Double-check if compatible with method for color of header + % row. + % TODO: Perhaps better to use specific colors for nested tables? + % This would mean though adding new sphinxsetup parameters + % and extending the documentation... + \ifodd\rownum\global\rownum\z@\else\global\rownum\@ne\fi + \else + \global\rownum\@ne + \fi + \sphinxSwitchCaseRowColor\rownum % set up color for the first body row + \sphinxrowcolorON % has been done from \sphinxtoprule location but let's do + % it again in case \sphinxtabletoprulehook has been used + % to inhibit colours in the header rows + }% end of noalign contents +} +% set the colours according to row parity; a priori #1 is \rownum, but +% the macro has been designed to be usable in user level added code +\def\sphinxSwitchCaseRowColor#1{% + \ifodd#1\relax + \global\sphinxcolorlet{sphinxTableRowColor}{sphinxTableRowColorOdd}% + \global\sphinxcolorlet{sphinxTableMergeColor}{\sphinxTableMergeColorOdd}% + \else + \global\sphinxcolorlet{sphinxTableRowColor}{sphinxTableRowColorEven}% + \global\sphinxcolorlet{sphinxTableMergeColor}{\sphinxTableMergeColorEven}% + \fi +} + +% each \cline or \cmidrule (booktabs) consumes one \cr, offsetting the \rownum +% parity; so this macro serves to compensate and must be added to each such +% \cline or \cmidrule (see below) +\def\spx@table@@decrementrownum{\noalign{\global\advance\rownum\m@ne}} +\let\sphinxtabledecrementrownum\@empty + +% \sphinxtableafterendhook will be modified by colorrows class to execute +% this after the table. +\def\spx@table@resetcolortbl{% + \sphinxrowcolorOFF + \spx@table@reset@CT@everycr +% this last bit is done in order for the \sphinxbottomrule from the "foot" +% part of the longtable template to be able to use same code as the +% \sphinxbottomrule at end of table body; see \sphinxbooktabsspecialbottomrule. + \global\rownum\z@ + \global\let\spx@rownum@stack\@empty +} +% Most of \spx@table@resetcolortbl must be avoided if the table is nested. +% Besides the sphinxTableRowColor must be reset because it has been +% redefined by the cells of the nested table. So this is the alternative +% macro which is executed on exit of nested table. +\def\spx@nestedtable@resetcolortbl{% + \ifx\spx@rownum@stack\@empty\else +% The stack can be empty if this is executed on exit of a nested table, +% and the parent table has received the "nocolorrows" class, but globally +% colorrows are activated (default). So we protected against that case. + \spx@gpop@rownum + \fi + \sphinxSwitchCaseRowColor\rownum +} +\def\spx@table@reset@CT@everycr{% +% we should probably be more cautious and not hard-code here the colortbl +% set-up. + \global\CT@everycr{\noalign{\global\let\CT@row@color\relax}\the\everycr}% +} +\let\spx@rownum@stack\@empty +\def\spx@gpush@rownum{\xdef\spx@rownum@stack{\the\rownum.\spx@rownum@stack}}% +\def\spx@gpop@rownum{\afterassignment\spx@gpop@rownum@i + \global\rownum=\spx@rownum@stack\relax} +\def\spx@gpop@rownum@i.#1\relax{\gdef\spx@rownum@stack{#1}} + +% At last the style macros \sphinxthistablewithstandardstyle etc... + +% They are executed before the table environments in a scope limiting +% wrapper "savenotes" environment. +% +% 0) colour support is enacted via adding code to three hooks: +% - \sphinxtabletoprulehook (implicit from \sphinxtoprule expansion) +% - \sphinxtableatstartofbodyhook (explicit from table templates) +% - \sphinxtableafterendhook (explicit from table templates) +% additionally special adjustment must be made in \sphinxcline +% +\def\sphinxtoprule{\spx@toprule\sphinxtabletoprulehook} +% \spx@toprule is what is defined by the standard, booktabs and borderless +% styles. +% The colorrows class will prepend \spx@table@toprule@rowcolorON into +% \sphinxtabletoprulehook which a priori is \@empty but can contain user added +% extra code, and is executed after \spx@toprule. +\let\sphinxtabletoprulehook \@empty +\let\sphinxtableatstartofbodyhook\@empty +\let\sphinxtableafterendhook \@empty +% +% 1) we manage these three hooks in a way allowing a custom user extra wrapper +% environment from a container class to use them as entry point for some +% custom code. The container code is done first, prior to table templates. +% So, the style macros will *prepend* the needed color-code to the existing +% custom user code, so the custom user code can override them. The custom +% user code should not redefine any of the 3 \sphinxtable...hook macros via a +% \global\def, but their contents can use \gdef. In fact they probably need +% to for the first two hooks which are executed from inside the table and +% a priori need their code to be in a \noalign which limits scope. +% +% 2) the table templates and LaTeX writer code make it so that only +% one of either +% \sphinxthistablewithcolorrowsstyle, +% or \sphinxthistablewithnocolorrowsstyle +% will be inserted explicitly depending on local :class: for table. +% The global 'colorrows' style in latex_table_style translates at bottom +% of this file into code for inserting \sphinxthistablewithcolorrowsstyle +% at end of \sphinxthistablewithglobalstyle. So it is impossible +% to have first \sphinxthistablewithnocolorrowsstyle, then +% \sphinxthistablewithcolorrowsstyle. Nevertheless we have written +% the code so that in this case colorrows would indeed activate (except +% if it was already executed before as it self-annihilates). + +% standard style +\def\sphinxthistablewithstandardstyle{% + % Those two are produced by the latex writer + \def\sphinxhline {\hline}% + % \sphinxtabledecrementrownum is a no-op which is redefined by colorrows + % to correct the \rownum increment induced by \cline in colorrows regime + \def\sphinxcline {\sphinxtabledecrementrownum\cline}% + % LaTeX's \cline needs fixing + \let\sphinxvlinecrossing\sphinxtablevlinecrossing + \let\sphinxfixclines \sphinxtablefixclines + % Those three are inserted by the table templates + \def\spx@toprule {\hline}% + \def\sphinxmidrule {\hline}% + \def\sphinxbottomrule {\hline}% + % Do not tamper with this internal + \def\spx@arrayrulewidth{\arrayrulewidth}% +} + +% booktabs style +% The \@xcmidrule patch below will do beyond its main stuff +% \sphinxadjustcmidrulebelowsep +% Indeed the poor booktabs spacing with \cmidrule (if \sphinxbooktabscmidrule +% defined below is overwritten to use it) is quite awful. Do +% \let\sphinxadjustcmidrulebelowsep\empty +% if you prefer booktabs defaults. +\def\sphinxadjustcmidrulebelowsep{\belowrulesep=\aboverulesep} +\AtBeginDocument{% patch booktabs to avoid extra vertical space from + % consecutive \sphinxcline, if defined to use \cmidrule + \ifdefined\@xcmidrule + \let\spx@original@@xcmidrule\@xcmidrule + \def\@xcmidrule{\sphinxadjustcmidrulebelowsep + % if we don't do that, two \sphinxcline in the same row + % will cause the second short rule to be shifted down + \ifx\@tempa\sphinxcline\let\@tempa\cmidrule\fi + \spx@original@@xcmidrule}% + \fi +} +% wrappers to allow customization, e.g. via a container class +% the top, mid, bottom definitions are in fact overwritten (later, below) +% byt more complex ones needed to handle booktabs+colorrows context +\def\sphinxbooktabstoprule {\toprule} +\def\sphinxbooktabsmidrule {\midrule} +\def\sphinxbooktabsbottomrule{\bottomrule} +% +\let\sphinxbooktabscmidrule \@gobble % i.e. draw no short rules at all! +% You can redefine this to use \cmidrule with various options, such +% as \cmidrule(lr), but: +% Attention, if you want this to use \cmidrule (or \cline) you must, +% if the table uses row colours, +% also include the \sphinxtabledecrementrownum token like e.g. this +% \def\sphinxbooktabscmidrule{\sphinxtabledecrementrownum\cmidrule(lr)} +% and it must be first due to internals of the \cmidrule usage of \futurelet. + +\def\sphinxthistablewithbooktabsstyle{% + \let\sphinxhline\@empty % there is no wrapper macro here so if you want to change that + % you will have to redefine \sphinxthistablewithbooktabsstyle + \def\sphinxcline {\sphinxbooktabscmidrule}% defaults to give \@gobble + \let\sphinxvlinecrossing\@gobble % no | in a booktabs-style table ! + \let\sphinxfixclines \@gobble % should not be used with booktabs + \cmidrule + \def\spx@toprule {\sphinxbooktabstoprule}% + \def\sphinxmidrule {\sphinxbooktabsmidrule}% + \def\sphinxbottomrule{\sphinxbooktabsbottomrule}% + \def\spx@arrayrulewidth{\z@}% +} +\AtBeginDocument{\@ifpackageloaded{booktabs}% + {}% + {\def\sphinxthistablewithbooktabsstyle{% + \PackageWarning{sphinx}{% +Add \string\usepackage{booktabs} to the preamble to allow\MessageBreak +local use of booktabs table style}% + \sphinxbuildwarning{booktabs}% + \sphinxthistablewithstandardstyle + }}% +}% + +% borderless style +\def\sphinxthistablewithborderlessstyle{% + \sphinxthistablewithnohlines + \def\spx@arrayrulewidth{\z@}% +}% +\def\sphinxthistablewithnohlines{% + \let\sphinxhline \@empty + \let\sphinxcline \@gobble + \let\sphinxvlinecrossing\@gobble + \let\sphinxfixclines \@gobble + \let\spx@toprule \@empty + \let\sphinxmidrule \@empty + \let\sphinxbottomrule \@empty +}% +\def\sphinxthistabularywithnohlinesifinlongtable{% + \ifspx@longtable\sphinxthistablewithnohlines\fi +}% + +% colorrows style +% +\let\sphinxifthistablewithcolorrowsTF\@secondoftwo +\def\sphinxthistablewithcolorrowsstyle{% + \let\sphinxifthistablewithcolorrowsTF\@firstoftwo +% this is defined to auto-silence itself (in the surrounding scope-limiting +% environment) after one execution ("colorrows" can never follow "nocolorrows") + \let\sphinxthistablewithcolorrowsstyle\@empty +% + \let\spx@table@toprule@rowcolorON \spx@table@@toprule@rowcolorON + \let\spx@table@startbodycolorrows \spx@table@@startbodycolorrows + \let\sphinxtabledecrementrownum \spx@table@@decrementrownum +% Is it the best choice to "prepend" to existing code there? + \spx@prepend\spx@table@toprule@rowcolorON\to\sphinxtabletoprulehook + \spx@prepend\spx@table@startbodycolorrows\to\sphinxtableatstartofbodyhook +% +% this one is not set to \@empty by nocolorrows, because it looks harmless +% to execute it always, as it simply resets to standard colortbl state after +% the table [^1]; so we don't need an @@ version for this one. +% .. [1]: which is bad if nested in another table. This is taken care of +% at level of \sphinxattablestart and \sphinxatlongtablestart. + \spx@prepend\spx@table@resetcolortbl\to\sphinxtableafterendhook +} +\def\spx@prepend#1\to#2{% attention about using this only with #2 "storage macro" +% MEMO: #1 is prepended with no expansion, i.e. "as is". + \toks@{#1}% + \toks@\expandafter\expandafter\expandafter{\expandafter\the\expandafter\toks@#2}% + \edef#2{\the\toks@}% +}% + +\def\sphinxthistablewithnocolorrowsstyle{% + \let\sphinxifthistablewithcolorrowsTF\@secondoftwo +% rather than trying to remove the code added by 'colorrows' style, we +% simply make it no-op, without even checking if really it was activated. + \let\spx@table@toprule@rowcolorON\@empty + \let\spx@table@startbodycolorrows\@empty + \let\sphinxtabledecrementrownum \@empty +% we don't worry about \sphinxtableafterendhook as the \spx@table@resetcolortbl +% done at end can not do harm [^1]; and we could also have not bothered with the +% \sphinxtabledecrementrownum as its \rownum decrement, if active, is harmless +% in non-colorrows context. +% .. [1]: if nested in another table it is modified to do no harm. +} + +% (not so easy) implementation of the booktabscolorgaps option. This option +% defaults to true and is not officially documented, as already colorrows is +% only opt-in, so it is there only as a "turn-off" switch, but if nobody +% complains in next few months, it will probably be removed altogether at +% 6.0.0. The reason it exists is because of longtable aspeces described +% below. +% +% As it is used via \sphinxsetup booktabscolorgaps status is not known here +% and may change locally. So it must be implemented via delayed or +% conditional code. +% +% We do not know the order of execution of \sphinxthistablewithbooktabsstyle +% versus \sphinxthistablewithcolorrows: if booktabs is global option it +% will be executed first; but if colorrows is global option and not booktabs +% then colorrows will be executed first via \sphinxthistablewithglobalstyle +% +% Modifying things from locations such as \sphinxtabletoprulehook which are +% executed within the table is not convenient as it must use \global +% but then we would have to undo this after the table. +% +% So what we do is to prepare booktabs specific macros to incorporate +% a conditional to check the colorrows status. We must each time check +% both if colorrows is activated and if colorgaps is. We do this via +% macros without @ so they can be used easily in customization code. +% When and if booktabscolorgaps option is removed, we can then replace +% \sphinxifbooktabswithcolorgapsTF by \sphinxifthistablewithcolorrowsTF +\def\sphinxifbooktabswithcolorgapsTF{% + \if1\ifspx@opt@booktabscolorgaps + \sphinxifthistablewithcolorrowsTF{1}{0}% + \else0\fi + \expandafter\@firstoftwo + \else\expandafter\@secondoftwo + \fi +} +% as this is done without "@" it can be relatively easily be overwritten +% by user in customization code +\def\sphinxbooktabstoprule{% + \sphinxifbooktabswithcolorgapsTF + {\sphinxbooktabsspecialtoprule}% + {\toprule}% +}% +\def\sphinxbooktabscolorgapsoverhang{0.1pt}% avoid pixel/rounding effects +% auxiliary fork +\long\def\spx@table@crazyfork + #1\endfirsthead\endhead\sphinxtableatstartofbodyhook#2#3\@nil{#2} +% we fetch the next token to check if there is a header or not +% this is a bit fragile as it relies on the table templates +% and it assumes this token #1 is never braced... +% let's make this \long in case #1 is \par (should not be) +\long\def\sphinxbooktabsspecialtoprule\sphinxtabletoprulehook#1{% + \specialrule{\heavyrulewidth}{\abovetopsep}{\z@}% + % this macro contains colour init code (and defines sphinxTableRowColor) + \sphinxtabletoprulehook + % unfortunately colortbl provides no way to save/restore the + % \arrayrulecolor status, we have to code it ourselves + \noalign{\global\let\spx@@saved@CT@arc@\CT@arc@ +% \@declaredcolor is not \long. Although #1 can probably never be \par with +% our templates, let's be cautious and not use the creazyfork inside the \color + \spx@table@crazyfork +% this crazy code checks if #1 is one of \endfirsthead, \endhead or +% \sphinxtableatstartofbodyhook, as criterion for table with no header + #1\endhead\sphinxtableatstartofbodyhook\@secondoftwo + \endfirsthead#1\sphinxtableatstartofbodyhook\@secondoftwo + \endfirsthead\endhead#1\@secondoftwo + \endfirsthead\endhead\sphinxtableatstartofbodyhook\@firstoftwo + \@nil + {\gdef\CT@arc@{\color{sphinxTableRowColor}}}% + {\gdef\CT@arc@{\color{sphinxTableRowColorOdd}}}% + }% end of \noalign + % \specialrule uses \noalign itself + \specialrule{\dimexpr\belowrulesep+\sphinxbooktabscolorgapsoverhang\relax}% + {\z@}{-\sphinxbooktabscolorgapsoverhang}% + \noalign{\global\let\CT@arc@\spx@@saved@CT@arc@}% + #1% let's not forget to re-insert this #1 in token stream + % fortunately longtable's \endfirsthead/\endhead are not delimiters but + % are really tokens awaiting expansion... +}% +\def\sphinxbooktabsmidrule{% + \sphinxifbooktabswithcolorgapsTF + {\sphinxbooktabsspecialmidrule}% + {\midrule}% +}% +\def\sphinxbooktabsspecialmidrule{% + \noalign{\global\let\spx@@saved@CT@arc@\CT@arc@ + \gdef\CT@arc@{\color{sphinxTableRowColor}}% this is RowColorHeader + }% + \specialrule{\dimexpr\aboverulesep+\sphinxbooktabscolorgapsoverhang\relax\relax}% + {-\sphinxbooktabscolorgapsoverhang}{\z@}% + \noalign{\global\let\CT@arc@\spx@@saved@CT@arc@}% + \specialrule{\lightrulewidth}{\z@}{\z@}% + \noalign{\gdef\CT@arc@{\color{sphinxTableRowColorOdd}}}% + \specialrule{\dimexpr\belowrulesep+\sphinxbooktabscolorgapsoverhang\relax\relax}% + {\z@}{-\sphinxbooktabscolorgapsoverhang}% + \noalign{\global\let\CT@arc@\spx@@saved@CT@arc@}% +}% +\def\sphinxbooktabsbottomrule{% + \sphinxifbooktabswithcolorgapsTF + {\sphinxbooktabsspecialbottomrule}% + {\bottomrule}% +}% +% The colour here is already updated because of the \\ before so we must +% execute again the colour selection code, but this is not too complicated. +% What is annoying though is that \sphinxbottomrule in the longtable context +% appears both in the "foot" part and after the last body row. For the first +% occurrence the \rownum could be arbitrary if it had not been reset by each +% table using it via the \sphinxtableafterendhook (see above). This avoids +% having to modify the longtable template. But as \rownum is thus 0 in the +% "foot", the \sphinxSwitchCaseRowColor has to know how to handle negative +% inputs (in fact the -1 value), the Sphinx definition has no issue with that +% but any redefinition must be aware of this constraint. +\def\sphinxbooktabsspecialbottomrule{% + \noalign{\global\let\spx@@saved@CT@arc@\CT@arc@ + \sphinxSwitchCaseRowColor{\numexpr\rownum-\@ne\relax}% + \gdef\CT@arc@{\color{sphinxTableRowColor}}% + }% + \specialrule{\dimexpr\aboverulesep+\sphinxbooktabscolorgapsoverhang\relax}% + {-\sphinxbooktabscolorgapsoverhang}{\z@}% + \noalign{\global\let\CT@arc@\spx@@saved@CT@arc@}% + \specialrule{\heavyrulewidth}{\z@}{\belowbottomsep}% +}% +% +% MEMO: with longtable \sphinxtoprule, \sphinxmidrule and \sphinxbottomrule +% are evaluated at time of constructing the headers and footers as boxes +% (already typeset material and expanded macros; \sphinxbottomrule is also +% evaluated at very end of table body, i.e. "normally"). So the used colour +% to fill the booktabs gaps is decided during the headers and footers +% construction by longtable. Actually they are expanded twice: in firsthead +% then in head, respectively in foot and lastfoot. But in current design the +% header row colours are fixed, not alternating, so there is at least no +% coherence issue there. + +% The \spx@arrayrulewidth is used for some complex matters of merged +% cells size computations. +% tabularcolumns argument will override any global or local style and +% trigger the appropriate adjustment of \spx@arrayrulewidth. +% Notice that this will be bad if the table uses booktabs style +% but anyhow table with booktabs should not use any | separator. +\def\sphinxthistablewithvlinesstyle{% + \def\spx@arrayrulewidth{\arrayrulewidth}% + \let\sphinxvlinecrossing\sphinxtablevlinecrossing + \let\sphinxfixclines \sphinxtablefixclines +}% +\def\sphinxthistablewithnovlinesstyle{% + \def\spx@arrayrulewidth{\z@}% + \let\sphinxvlinecrossing\@gobble + % let's not bother to modify \sphinxfixclines, it works fine and is + % useful in standard style + no vline (only hlines and clines); + % besides, only one of vline or novline style macro is executed +}% + +% default is the standard style +\def\sphinxthistablewithglobalstyle{\sphinxthistablewithstandardstyle} + +\ifspx@opt@booktabs + \RequirePackage{booktabs} + \def\sphinxthistablewithglobalstyle{\sphinxthistablewithbooktabsstyle} +\fi +\ifspx@opt@borderless + \def\sphinxthistablewithglobalstyle{\sphinxthistablewithborderlessstyle} +\fi +% colorrows appends to the current globalstyle (standard, booktabs, or borderless) +\ifspx@opt@colorrows % let the globalstyle trigger the colorrows style on top of it + \expandafter\def\expandafter\sphinxthistablewithglobalstyle\expandafter + {\sphinxthistablewithglobalstyle + \sphinxthistablewithcolorrowsstyle + } +\fi + + +\endinput diff --git a/build/latex/sphinxmanual.cls b/build/latex/sphinxmanual.cls new file mode 100644 index 0000000..2e4b30d --- /dev/null +++ b/build/latex/sphinxmanual.cls @@ -0,0 +1,128 @@ +% +% sphinxmanual.cls for Sphinx (https://www.sphinx-doc.org/) +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{sphinxmanual}[2019/12/01 v2.3.0 Document class (Sphinx manual)] + +% chapters starting at odd pages (overridden by 'openany' document option) +\PassOptionsToClass{openright}{\sphinxdocclass} + +% 'oneside' option overriding the 'twoside' default +\newif\if@oneside +\DeclareOption{oneside}{\@onesidetrue} +% Pass remaining document options to the parent class. +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\sphinxdocclass}} +\ProcessOptions\relax + +% Defaults two-side document +\if@oneside +% nothing to do (oneside is the default) +\else +\PassOptionsToClass{twoside}{\sphinxdocclass} +\fi + +\LoadClass{\sphinxdocclass} + +% Set some sane defaults for section numbering depth and TOC depth. You can +% reset these counters in your preamble. +% +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{1} + +% Adapt \and command to the flushright context of \sphinxmaketitle, to +% avoid ragged line endings if author names do not fit all on one single line +\DeclareRobustCommand{\and}{% + \end{tabular}\kern-\tabcolsep + \allowbreak + \hskip\dimexpr1em+\tabcolsep\@plus.17fil\begin{tabular}[t]{c}% +}% +% If it is desired that each author name be on its own line, use in preamble: +%\DeclareRobustCommand{\and}{% +% \end{tabular}\kern-\tabcolsep\\\begin{tabular}[t]{c}% +%}% +% Change the title page to look a bit better, and fit in with the fncychap +% ``Bjarne'' style a bit better. +% +\newcommand{\sphinxmaketitle}{% + \let\sphinxrestorepageanchorsetting\relax + \ifHy@pageanchor\def\sphinxrestorepageanchorsetting{\Hy@pageanchortrue}\fi + \hypersetup{pageanchor=false}% avoid duplicate destination warnings + \begin{titlepage}% + \let\footnotesize\small + \let\footnoterule\relax + \noindent\rule{\textwidth}{1pt}\par + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}% + \endgroup + \begin{flushright}% + \sphinxlogo + \py@HeaderFamily + {\Huge \@title \par} + {\itshape\LARGE \py@release\releaseinfo \par} + \vfill + {\LARGE + \begin{tabular}[t]{c} + \@author + \end{tabular}\kern-\tabcolsep + \par} + \vfill\vfill + {\large + \@date \par + \vfill + \py@authoraddress \par + }% + \end{flushright}%\par + \@thanks + \end{titlepage}% + \setcounter{footnote}{0}% + \let\thanks\relax\let\maketitle\relax + %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} + \clearpage + \ifdefined\sphinxbackoftitlepage\sphinxbackoftitlepage\fi + \if@openright\cleardoublepage\else\clearpage\fi + \sphinxrestorepageanchorsetting +} + +\newcommand{\sphinxtableofcontents}{% + \pagenumbering{roman}% + \begingroup + \parskip \z@skip + \sphinxtableofcontentshook + \tableofcontents + \endgroup + % before resetting page counter, let's do the right thing. + \if@openright\cleardoublepage\else\clearpage\fi + \pagenumbering{arabic}% +} + +% This is needed to get the width of the section # area wide enough in the +% library reference. Doing it here keeps it the same for all the manuals. +% +\newcommand{\sphinxtableofcontentshook}{% + \renewcommand*\l@section{\@dottedtocline{1}{1.5em}{2.6em}}% + \renewcommand*\l@subsection{\@dottedtocline{2}{4.1em}{3.5em}}% +} + +% Fix the bibliography environment to add an entry to the Table of +% Contents. +% For a report document class this environment is a chapter. +% +\newenvironment{sphinxthebibliography}[1]{% + \if@openright\cleardoublepage\else\clearpage\fi + % \phantomsection % not needed here since TeXLive 2010's hyperref + \begin{thebibliography}{#1}% + \addcontentsline{toc}{chapter}{\bibname}}{\end{thebibliography}} + +% Same for the indices. +% The memoir class already does this, so we don't duplicate it in that case. +% +\@ifclassloaded{memoir} + {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}} + {\newenvironment{sphinxtheindex}{% + \if@openright\cleardoublepage\else\clearpage\fi + \phantomsection % needed as no chapter, section, ... created + \begin{theindex}% + \addcontentsline{toc}{chapter}{\indexname}}{\end{theindex}}} diff --git a/build/latex/sphinxmessages.sty b/build/latex/sphinxmessages.sty new file mode 100644 index 0000000..68ebffa --- /dev/null +++ b/build/latex/sphinxmessages.sty @@ -0,0 +1,21 @@ +% +% sphinxmessages.sty +% +% message resources for Sphinx +% +\ProvidesPackage{sphinxmessages}[2019/01/04 v2.0 Localized LaTeX macros (Sphinx team)] + +\renewcommand{\literalblockcontinuedname}{continued from previous page} +\renewcommand{\literalblockcontinuesname}{continues on next page} +\renewcommand{\sphinxnonalphabeticalgroupname}{Non\sphinxhyphen{}alphabetical} +\renewcommand{\sphinxsymbolsname}{Symbols} +\renewcommand{\sphinxnumbersname}{Numbers} +\def\pageautorefname{page} + +\addto\captionsenglish{\renewcommand{\figurename}{Fig.\@{} }} +\def\fnum@figure{\figurename\thefigure{}} + +\addto\captionsenglish{\renewcommand{\tablename}{Table }} +\def\fnum@table{\tablename\thetable{}} + +\addto\captionsenglish{\renewcommand{\literalblockname}{Listing}} \ No newline at end of file diff --git a/build/latex/sphinxoptionsgeometry.sty b/build/latex/sphinxoptionsgeometry.sty new file mode 100644 index 0000000..d0c59f0 --- /dev/null +++ b/build/latex/sphinxoptionsgeometry.sty @@ -0,0 +1,54 @@ +%% OPTIONS FOR GEOMETRY +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxoptionsgeometry}[2021/01/27 geometry] + +% geometry +\ifx\kanjiskip\@undefined + \PassOptionsToPackage{% + hmargin={\unexpanded{\spx@opt@hmargin}},% + vmargin={\unexpanded{\spx@opt@vmargin}},% + marginpar=\unexpanded{\spx@opt@marginpar}} + {geometry} +\else + % set text width for Japanese documents to be integer multiple of 1zw + % and text height to be integer multiple of \baselineskip + % the execution is delayed to \sphinxsetup then geometry.sty + \normalsize\normalfont + \newcommand*\sphinxtextwidthja[1]{% + \if@twocolumn\tw@\fi + \dimexpr + \numexpr\dimexpr\paperwidth-\tw@\dimexpr#1\relax\relax/ + \dimexpr\if@twocolumn\tw@\else\@ne\fi zw\relax + zw\relax}% + \newcommand*\sphinxmarginparwidthja[1]{% + \dimexpr\numexpr\dimexpr#1\relax/\dimexpr1zw\relax zw\relax}% + \newcommand*\sphinxtextlinesja[1]{% + \numexpr\@ne+\dimexpr\paperheight-\topskip-\tw@\dimexpr#1\relax\relax/ + \baselineskip\relax}% + \ifx\@jsc@uplatextrue\@undefined\else + % the way we found in order for the papersize special written by + % geometry in the dvi file to be correct in case of jsbook class + \ifnum\mag=\@m\else % do nothing special if nomag class option or 10pt + \PassOptionsToPackage{truedimen}{geometry}% + \fi + \fi + \PassOptionsToPackage{% + hmarginratio={1:1},% + textwidth=\unexpanded{\sphinxtextwidthja{\spx@opt@hmargin}},% + vmarginratio={1:1},% + lines=\unexpanded{\sphinxtextlinesja{\spx@opt@vmargin}},% + marginpar=\unexpanded{\sphinxmarginparwidthja{\spx@opt@marginpar}},% + footskip=2\baselineskip,% + }{geometry}% + \AtBeginDocument + {% update a dimension used by the jsclasses + \ifx\@jsc@uplatextrue\@undefined\else\fullwidth\textwidth\fi + % for some reason, jreport normalizes all dimensions with \@settopoint + \@ifclassloaded{jreport} + {\@settopoint\textwidth\@settopoint\textheight\@settopoint\marginparwidth} + {}% <-- "false" clause of \@ifclassloaded + }% +\fi + +\endinput diff --git a/build/latex/sphinxoptionshyperref.sty b/build/latex/sphinxoptionshyperref.sty new file mode 100644 index 0000000..caf28e8 --- /dev/null +++ b/build/latex/sphinxoptionshyperref.sty @@ -0,0 +1,35 @@ +%% Bookmarks and hyperlinks +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxoptionshyperref}[2021/01/27 hyperref] + +% to make pdf with correct encoded bookmarks in Japanese +% this should precede the hyperref package +\ifx\kanjiskip\@undefined +% for non-Japanese: make sure bookmarks are ok also with lualatex + \PassOptionsToPackage{pdfencoding=unicode}{hyperref} +\else + \RequirePackage{atbegshi} + \ifx\ucs\@undefined + \ifnum 42146=\euc"A4A2 + \AtBeginShipoutFirst{\special{pdf:tounicode EUC-UCS2}} + \else + \AtBeginShipoutFirst{\special{pdf:tounicode 90ms-RKSJ-UCS2}} + \fi + \else + \AtBeginShipoutFirst{\special{pdf:tounicode UTF8-UCS2}} + \fi +\fi + +\ifx\@jsc@uplatextrue\@undefined\else + \PassOptionsToPackage{setpagesize=false}{hyperref} +\fi + +% These options can be overridden inside 'hyperref' key +% or by later use of \hypersetup. +\PassOptionsToPackage{colorlinks,breaklinks,% + linkcolor=InnerLinkColor,filecolor=OuterLinkColor,% + menucolor=OuterLinkColor,urlcolor=OuterLinkColor,% + citecolor=InnerLinkColor}{hyperref} + +\endinput diff --git a/build/latex/sphinxpackageboxes.sty b/build/latex/sphinxpackageboxes.sty new file mode 100644 index 0000000..2345051 --- /dev/null +++ b/build/latex/sphinxpackageboxes.sty @@ -0,0 +1,827 @@ +%% COLOURED BOXES +% +% change this info string if making any custom modification +\ProvidesPackage{sphinxpackageboxes}[2024/07/01 v7.4.0 advanced colored boxes] +% 7.4.0 removes usage of some booleans "...withbackgroundcolor" and +% "...withbordercolor" as well as \spx@boxes@border dimen which was +% actually really needed nowhere. This was done in sync with changes in +% sphinx.sty, sphinxlatexadmonitions.sty and sphinxlatexliterals.sty. +% +% Optionally executes \RequirePackage for: +% +% - pict2e. Ideally we would like to use the v0.4a 2020/08/16 release of this +% package as it allows dimensional arguments to its \moveto, \lineto, etc... +% Or we could use extra package "picture". We opt for custom wrappers +% \spx@moveto, \spx@lineto, ..., working with old versions. +% +% - ellipse. This package extends pict2e with elliptical arcs. Its author +% Daan Leijen also has contributed package longfbox which is part of +% TeXLive. Had I known about it, I would perhaps have based Sphinx CSS on +% top of longfbox at least partly. But this would not have spared me all +% the work in sphinx.sty, which was a long walk until 6.2.0 version. +% Besides I don't need the breakable boxes from longfbox, as Sphinx has +% its own rather advanced layer on top of framed. I would need to check if +% some thorny color issues solved by Sphinx (and not by tcolorbox) at page +% breaks are solved by longfbox as well. (I have not tested) + +% At 6.2.0 refactoring, we do not wait for at begin document to try to load +% pict2e. Actually since 6.0.0 the default is for code-blocks to use +% rounded boxes, and the only reason since then to wait "at begin document" +% was to check if user had reverted that default and in fact pict2e was not +% needed. But with \sphinxbox, we can not know for sure even in that case +% that pict2e is not needed. And even back then it would have been possible +% to user to try to employ \sphinxsetup via raw directive in document body +% and require some rounded corners (which was thus impossible to satisfy). +% Time to be much simpler and attempt unconditionally to load pict2e +% immediately. This will also have advantage that we can use +% \@ifpackageloaded{pict2e} and not have to query and save its setting later +% at begin document. +\IfFileExists{pict2e.sty} + {\RequirePackage{pict2e}} + {\PackageWarningNoLine{sphinx}{% + The package pict2e is required for rounded boxes.\MessageBreak + It does not seem to be available on your system.\MessageBreak + Options for setting radii will be ignored% + }% + % Formerly a \sphinxbuildwarning was issued but if we did that now it + % would mean that the produced PDF will always have a red banner near its + % end about pict2e not being available if indeed it is not available, even + % if user has reverted the default and dropped rounded corners. Formerly + % the serious warning was done after having checked at begin document that + % indeed a rounded corner option had been used. As we drop the check now, + % let's be more discrete and simply duplicate the earlier warning to make + % it visible near end of compilation log and console output. + \AtEndDocument{\PackageWarningNoLine{sphinx}{% + The package pict2e is required for rounded boxes.\MessageBreak + As it does not seem to be available on your system,\MessageBreak + options setting radii have all been ignored}}% + }% + +\IfFileExists{ellipse.sty} + {\RequirePackage{ellipse}} + {\PackageWarningNoLine{sphinx}{% + The package ellipse is required for elliptical corners.\MessageBreak + It does not seem to be available on your system.\MessageBreak + All non-straight corners will use circle arcs.% + }% + \AtEndDocument{\PackageWarningNoLine{sphinx}{% + The package ellipse is required for elliptical corners.\MessageBreak + As it does not seem to be available on your system,\MessageBreak + all non-straight corners have used circle arcs.}}% + }% + +% The pict2e release v0.4b of 2020/09/30 does not allocate scratch dimen +% register \@tempdimd which ellipse package uses. Thus ellipse package is +% broken since (written on March 20, 2023). Simply allocate the register +% ourself to fix that, pending some upstream fix. +\@ifpackageloaded{ellipse}{\ifdefined\@tempdimd\else\newdimen\@tempdimd\fi}{} + +% Provides box registers \spx@tempboxa, \spx@tempboxb usable in other places +\newbox\spx@tempboxa +\newbox\spx@tempboxb + +%%%%%%%%%%%%%%%% +% Internal registers, conditionals, colors to be configured by each caller +% via a preliminary "setup" call +\newif\ifspx@boxes@withshadow +\newif\ifspx@boxes@insetshadow +%%% \newif\ifspx@boxes@withbackgroundcolor % removed at 7.4.0 +\newif\ifspx@boxes@withshadowcolor +%%% \newif\ifspx@boxes@withbordercolor % removed at 7.4.0 +\newif\ifspx@boxes@shadowinbbox +% +\newdimen\spx@boxes@border@top +\newdimen\spx@boxes@border@right +\newdimen\spx@boxes@border@bottom +\newdimen\spx@boxes@border@left +% +\newdimen\spx@boxes@padding@top +\newdimen\spx@boxes@padding@right +\newdimen\spx@boxes@padding@bottom +\newdimen\spx@boxes@padding@left +% +\newdimen\spx@boxes@shadow@xoffset +\newdimen\spx@boxes@shadow@yoffset +% +\newdimen\spx@boxes@radius@topleft@x +\newdimen\spx@boxes@radius@topright@x +\newdimen\spx@boxes@radius@bottomright@x +\newdimen\spx@boxes@radius@bottomleft@x +\newdimen\spx@boxes@radius@topleft@y +\newdimen\spx@boxes@radius@topright@y +\newdimen\spx@boxes@radius@bottomright@y +\newdimen\spx@boxes@radius@bottomleft@y +% +% These colors will be set to colors defined appropriately by caller of +% \spx@boxes@fcolorbox@setup macro +% spx@boxes@bordercolor +% spx@boxes@backgroundcolor +% spx@boxes@shadowcolor +% spx@boxes@textcolor + +%%%%%%%%%%%%%%%% +% "setup" macro +% +% It must be called prior to \spx@boxes@fcolorbox for parameters of the latter +% to be initialized. +% +% It also prepares \spx@boxes@fcolorbox to expand to one of +% \spx@boxes@fcolorbox@rectangle or \spx@boxes@fcolorbox@rounded depending on +% the configuration and availability of the pict2e package. +% +% The #1 is one of: pre, topic, warning, danger, etc.... +% +% We delay until here the parsing of radii options to extract x and y +% components. +\def\spx@boxes@setradii#1 #2 #3\@nnil#4#5{% + #4\dimexpr#1\relax + #5\dimexpr#2\relax + \ifdim#5=-\maxdimen#5#4\fi + % if one of them is zero or negative set both to zero + \ifdim#4>\z@\else#4\z@#5\z@\fi + \ifdim#5>\z@\else#4\z@#5\z@\fi +}% +% if ellipse.sty is not available ignore the second component of all radii +% specifications, use circle arcs with radius the x component +\@ifpackageloaded{ellipse} + {} + {\def\spx@boxes@setradii#1 #2 #3\@nnil#4#5{#4\dimexpr#1\relax #5#4}} + +% Using \dimexpr for maximal user input flexibility. +\def\spx@boxes@fcolorbox@setup#1{% + \spx@boxes@border@top \dimexpr\@nameuse{spx@#1@border@top}\relax + \spx@boxes@border@right \dimexpr\@nameuse{spx@#1@border@right}\relax + \spx@boxes@border@bottom\dimexpr\@nameuse{spx@#1@border@bottom}\relax + \spx@boxes@border@left \dimexpr\@nameuse{spx@#1@border@left}\relax + % + \spx@boxes@padding@top \dimexpr\@nameuse{spx@#1@padding@top}\relax + \spx@boxes@padding@right \dimexpr\@nameuse{spx@#1@padding@right}\relax + \spx@boxes@padding@bottom\dimexpr\@nameuse{spx@#1@padding@bottom}\relax + \spx@boxes@padding@left \dimexpr\@nameuse{spx@#1@padding@left}\relax + % + \edef\spx@temp{\csname spx@#1@radius@topleft\endcsname\space}% + \expandafter + \spx@boxes@setradii + \spx@temp + {-\maxdimen} + \@nnil + \spx@boxes@radius@topleft@x\spx@boxes@radius@topleft@y + \edef\spx@temp{\csname spx@#1@radius@topright\endcsname\space}% + \expandafter + \spx@boxes@setradii + \spx@temp + {-\maxdimen} + \@nnil + \spx@boxes@radius@topright@x\spx@boxes@radius@topright@y + \edef\spx@temp{\csname spx@#1@radius@bottomright\endcsname\space}% + \expandafter + \spx@boxes@setradii + \spx@temp + {-\maxdimen} + \@nnil + \spx@boxes@radius@bottomright@x\spx@boxes@radius@bottomright@y + \edef\spx@temp{\csname spx@#1@radius@bottomleft\endcsname\space}% + \expandafter + \spx@boxes@setradii + \spx@temp + {-\maxdimen} + \@nnil + \spx@boxes@radius@bottomleft@x\spx@boxes@radius@bottomleft@y + % + \@nameuse{ifspx@#1@withshadow}% + \spx@boxes@withshadowtrue + \spx@boxes@shadow@xoffset \dimexpr\@nameuse{spx@#1@shadow@xoffset}\relax + \spx@boxes@shadow@yoffset \dimexpr\@nameuse{spx@#1@shadow@yoffset}\relax + \else + \spx@boxes@withshadowfalse + \fi + % not nesting in previous to avoid TeX conditional subtleties + \@nameuse{ifspx@#1@insetshadow}% + \spx@boxes@insetshadowtrue + \else + \spx@boxes@insetshadowfalse + \fi + % + \sphinxcolorlet{spx@boxes@bordercolor}{sphinx#1BorderColor}% + % + \sphinxcolorlet{spx@boxes@backgroundcolor}{sphinx#1BgColor}% + % + \@nameuse{ifspx@#1@withshadowcolor}% + \spx@boxes@withshadowcolortrue + \sphinxcolorlet{spx@boxes@shadowcolor}{sphinx#1ShadowColor}% + \else + \spx@boxes@withshadowcolorfalse + \fi + % Display elements pre, topic, warning et al. by default do not include + % shadow in box (legacy; and only topic actually uses a shadow per default) + % This may be refactored still more in future, but this 6.2.0 extra helped + % reduce workload from code-blocks (pre), contents (topic) and admonitions. + % As this conditional is a priori false and should only be changed locally + % (by \sphinxbox), this line is actually superfluous. + \spx@boxes@shadowinbboxfalse + \spx@boxes@fcolorbox@setup@fcolorbox +} +\@ifpackageloaded{pict2e} +{% pict2e is available and loaded + \def\spx@boxes@fcolorbox@setup@fcolorbox{% + \if1% use rounded boxes only if needed (rx>0 iff ry>0) + \ifdim\spx@boxes@radius@topleft@x >\z@0\fi + \ifdim\spx@boxes@radius@topright@x >\z@0\fi + \ifdim\spx@boxes@radius@bottomright@x>\z@0\fi + \ifdim\spx@boxes@radius@bottomleft@x >\z@0\fi + 1\def\spx@boxes@fcolorbox{\spx@boxes@fcolorbox@rectangle}% + \else + \def\spx@boxes@fcolorbox{\spx@boxes@fcolorbox@rounded}% + \fi + }% end of definition of setup@fcolorbox in case of presence of pict2e +}% +{% pict2e could not be loaded, we must always use fcolorbox@rectangle + \def\spx@boxes@fcolorbox@setup@fcolorbox{% + \def\spx@boxes@fcolorbox{\spx@boxes@fcolorbox@rectangle}% + }% end of definition of setup@fcolorbox in case of absence of pict2e +}% end of "no pict2e" branch + +%%%%%%%%%%%%%%%% +% Support of box-decoration-break=slice +% +% 6.2.0 has renamed and moved this here from sphinxlatexliterals.sty, +% to facilitate supporting box-decoration-break=slice for all directives, +% not only code-block. +% +% It also modified when these post actions are executed, in order +% for openboth to be able to trigger usage of fcolorbox@rectangle. +% So now openbottom and opentop also take advantage of this possible +% optimization. +\def\spx@boxes@fcolorbox@setup@openbottom{% + \spx@boxes@border@bottom \z@ + \spx@boxes@radius@bottomright@x\z@ \spx@boxes@radius@bottomright@y\z@ + \spx@boxes@radius@bottomleft@x \z@ \spx@boxes@radius@bottomleft@y \z@ + \spx@boxes@fcolorbox@setup@fcolorbox +}% +\def\spx@boxes@fcolorbox@setup@opentop{% + \spx@boxes@border@top \z@ + \spx@boxes@radius@topright@x\z@ \spx@boxes@radius@topright@y\z@ + \spx@boxes@radius@topleft@x \z@ \spx@boxes@radius@topleft@y \z@ + \spx@boxes@fcolorbox@setup@fcolorbox +}% +\def\spx@boxes@fcolorbox@setup@openboth{% + \spx@boxes@border@top \z@ + \spx@boxes@border@bottom \z@ + \spx@boxes@radius@bottomright@x\z@ \spx@boxes@radius@bottomright@y\z@ + \spx@boxes@radius@bottomleft@x \z@ \spx@boxes@radius@bottomleft@y \z@ + \spx@boxes@radius@topright@x\z@ \spx@boxes@radius@topright@y\z@ + \spx@boxes@radius@topleft@x \z@ \spx@boxes@radius@topleft@y \z@ + \def\spx@boxes@fcolorbox{\spx@boxes@fcolorbox@rectangle}% +}% + +%%%%%%%%%%%%%%%% +% \sphinxbox (added at 6.2.0) +% +% For an inline box, possibly rounded. +\newcommand\sphinxbox[1][]{% #1 stands for the options, they are... optional! + % \leavevmode makes sure TeX switches to paragraph mode, which is necessary + % if this is first in a paragraph or a list element. The \sphinxAtStartPar + % mechanism also ensures this automatically, if not redefined, but not with + % lualatex as then it is by default doing nothing. + \leavevmode + \begingroup + \ifcsname spx@boxes@sphinxbox@isnested\endcsname + % nested boxes reset all box options to be as the \sphinxboxsetup + % defaults, before applying their specific options + \spx@boxes@sphinxbox@reset + \else + % top layer box, toggle the nested flag + \csname spx@boxes@sphinxbox@isnested\endcsname + \fi + % we do not use \sphinxboxsetup as it is a user command extending the + % "reset" storage + \setkeys{sphinxbox}{#1}% + \spx@boxes@fcolorbox@setup{box}% + \spx@boxes@shadowinbboxtrue% inline sphinx boxes include shadow in bbox + \ifspx@box@withtextcolor\color{sphinxboxTextColor}\fi + % + % MEMO: the fcolorbox@{rectangle,rounded} draw the contents (which here + % will be encapsulated as \box\z@) last, i.e. after shadow, background, + % and border and their color commands. The \reset@color from naked + % top-level \color commands in argument (which can not arise from Sphinx + % mark-up anyhow) would end up being placed via color.sty \aftergroup core + % mechanism in token stream after \spx@boxes@sphinxbox@a (which is the + % first \aftergroup) hence after the box contents with its unbalanced + % color pushes is shipped to PDF. So the missing color pop specials are + % inserted then in correct order at correct place (after the \endgroup at + % end of \spx@boxes@sphinxbox@a but this is not relevant) and do not end + % up causing havoc in push/pop pairs (and all this happens on same page). + % + % There is thus no reason here to go to the trouble to add an extra + % \color@begingroup/\color@endgroup or like pair to encapsulate the caught + % contents in order for the \box\z@ to contain as many color pop's as it + % has color pushes. But as this is subtle, this comment was added for + % future maintenance. Actually even if the contents were not drawn last, + % their (purely theoretical, as Sphinx mark-up can not create it) missing + % color pop's would not have caused trouble I guess as long as the color + % insertions for shadow, background, border are correctly balanced. + \setbox0\hbox\bgroup\aftergroup\spx@boxes@sphinxbox@a + \afterassignment\spx@box@TeXextras + \let\next=% +} +\def\spx@boxes@sphinxbox@a{\spx@boxes@fcolorbox{% + \ifspx@opt@box@addstrut\strut\fi\box\z@}\endgroup} + +\newcommand\newsphinxbox[2][]{% + \newcommand#2[1][]{\sphinxbox[#1,##1]}% +} +% Let's catch \renewsphinxbox[...]{\sphinxbox} which would cause \sphinxbox +% to fall into infinite looping on use. +\newcommand\renewsphinxbox[2][]{% + \in@{#2}{\sphinxbox}% + \ifin@ + \PackageWarning{sphinx}{Attempt to \string\renewsphinxbox\space + the \string\sphinxbox\space command\MessageBreak + itself. This is not allowed and will be ignored.\MessageBreak + Reported}% + \else + \renewcommand#2[1][]{\sphinxbox[#1,##1]}% + \fi +} + +%%%%%%%%%%%%%%%% +% MACROS +% +% \spx@boxes@fcolorbox expands either to \spx@boxes@fcolorbox@rectangle +% or \spx@boxes@fcolorbox@rounded depending on preliminary set-up. +% +% This is decided by the "setup" which must have been executed by the caller. +% Let's give it some (thus unneeded) default fall-back for clarity. +\def\spx@boxes@fcolorbox{\spx@boxes@fcolorbox@rectangle} +% +% A macro \spx@boxes@fcolorbox@setuphook used to be executed at start of the +% \hbox constructs (rectangle or rounded). This was used until 6.2.0 for the +% support of pre_box-decoration-break option, hence was really an internal +% non-public macro. As it is not needed anymore, with some hesitation it got +% entirely removed at 6.2.0 on the occasion of a refactoring of interactions of +% this file with sphinxlatexliterals.sty. Besides its name should have been +% rather something such as \spx@boxes@fcolorbox@atstartofhbox. +% +% After "setup", \spx@boxes@fcolorbox expands to one of: +% +% - \spx@boxes@fcolorbox@rectangle (4 padding parameters, 4 border widths, 2 shadow widths, +% and three colours: background, border and shadow; same as in CSS styling) +% +% It branches to one of: +% - \spx@boxes@fcolorbox@externalshadow +% - \spx@boxes@fcolorbox@insetshadow (same concept of "inset" as in CSS styling) +% +% - \spx@boxes@fcolorbox@rounded: rounded corners using the picture environment +% and pict2e package for its low-weight interface to PDF graphics operations + +% MEMO: we have also successfully tested usage of tcolorbox.sty (its \tcbox) but +% decided to use pict2e.sty for the following reasons: +% 1- PDF build was observed to be an order of magnitude faster, +% 2- the boxes we can do with pict2e appear to be fancy enough, +% almost matching what one can see in HTML renderings, +% 2- orders of magnitude smaller dependency (tcolorbox uses the pgf TeX +% framework), although on Ubuntu it seems texlive-pictures is +% needed which also contains the whole of pgf/TikZ... so this point +% is a bit moot... + +% For code-blocks, attachments of caption and continuation hints are done +% exactly as prior to extension of Sphinx via this package, whether the box +% has straight or rounded corners. The vertical space occupied is the same, +% if nothing else is changed (perhaps in future the title itself could be also +% rendered in a rounded box?) + +%%%%%%%% +%//// \spx@boxes@fcolorbox@rectangle +% +% This box will have the same baseline as its argument (which is typeset in +% horizontal mode). It takes into account four border widths parameters, four +% padding parameters, two shadow widths (each possibly negative), and three +% colors: background, border and shadow. Its boundary box takes into account +% border and padding. Width of shadow is taken into account if the boolean +% \ifspx@boxes@shadowinbbox is \iftrue. The "setup" sets it to \iffalse. +% Prior to 6.2.0, shadow size was included in bbox but the callers manually +% removed it by extra steps. The \sphinxbox command sets it to \iftrue after +% the "setup". +% +% It is up to the caller to take extra steps if the border and padding must go +% into margin as well (see sphinxlatexliterals.sty for how this is done in +% \spx@verb@FrameCommand). +% +% In usage as a "FrameCommand" with framed.sty, the argument will already be a +% collection of TeX boxes (and interline glues). +% +% This was designed so that the parameters configured by "setup" are +% interpreted as they would be as CSS properties in an HTML context. +\long\def\spx@boxes@fcolorbox@rectangle#1{% + \hbox\bgroup + \setbox\spx@tempboxa + \hbox{\kern\dimexpr\spx@boxes@border@left+\spx@boxes@padding@left\relax + {#1}% + \kern\dimexpr\spx@boxes@padding@right+\spx@boxes@border@right\relax}% + \ht\spx@tempboxa + \dimexpr\ht\spx@tempboxa+\spx@boxes@border@top+\spx@boxes@padding@top\relax + \dp\spx@tempboxa + \dimexpr\dp\spx@tempboxa+\spx@boxes@padding@bottom+\spx@boxes@border@bottom\relax + \ifspx@boxes@insetshadow + \expandafter\spx@boxes@fcolorbox@insetshadow + \else + \expandafter\spx@boxes@fcolorbox@externalshadow + \fi +} + +% external shadow +\def\spx@boxes@fcolorbox@externalshadow{% + % reserve space to external shadow if on left + \ifspx@boxes@withshadow + \ifspx@boxes@shadowinbbox + \ifdim\spx@boxes@shadow@xoffset<\z@\kern-\spx@boxes@shadow@xoffset\fi + \fi + \fi + % BACKGROUND + % draw background and move back to reference point + {\color{spx@boxes@backgroundcolor}% + \vrule\@height\ht\spx@tempboxa + \@depth\dp\spx@tempboxa + \@width\wd\spx@tempboxa + \kern-\wd\spx@tempboxa + }% + % BOX SHADOW + % draw shadow and move back to reference point + \ifspx@boxes@withshadow + \vbox{% + \moveright\spx@boxes@shadow@xoffset + \hbox{\lower\spx@boxes@shadow@yoffset + \vbox{\ifspx@boxes@withshadowcolor + \color{spx@boxes@shadowcolor}% + \else + % 6.2.0: guard against a manually inserted \color command in + % contents which could leak at a page break to the shadow + \normalcolor + \fi + \ifdim\spx@boxes@shadow@yoffset<\z@ + \hrule\@height-\spx@boxes@shadow@yoffset + \kern\spx@boxes@shadow@yoffset + \fi + \setbox\spx@tempboxb\hb@xt@\wd\spx@tempboxa{% + \ifdim\spx@boxes@shadow@xoffset<\z@\vrule\@width-\spx@boxes@shadow@xoffset\fi + \hss + \ifdim\spx@boxes@shadow@xoffset>\z@\vrule\@width\spx@boxes@shadow@xoffset\fi + }% + \ht\spx@tempboxb\ht\spx@tempboxa + \dp\spx@tempboxb\dp\spx@tempboxa + \box\spx@tempboxb + \ifdim\spx@boxes@shadow@yoffset>\z@ + \kern-\spx@boxes@shadow@yoffset + \hrule\@height\spx@boxes@shadow@yoffset + \fi + \kern-\dp\spx@tempboxa + }% end of \vbox, attention it will have zero depth if yoffset>0 + \kern-\wd\spx@tempboxa + \ifdim\spx@boxes@shadow@xoffset>\z@ + \kern-\spx@boxes@shadow@xoffset + \fi + }% end of \hbox, attention its depth is only yoffset if yoffset>0 + }% end of \vbox + \fi % end of shadow drawing, and we are back to horizontal reference point + % BOX BORDER + % 7.4.0 requires a set border color + \vbox{\color{spx@boxes@bordercolor}% + \hrule\@height\spx@boxes@border@top + \kern-\spx@boxes@border@top + \setbox\spx@tempboxb\hb@xt@\wd\spx@tempboxa + {\vrule\@width\spx@boxes@border@left + \hss\vrule\@width\spx@boxes@border@right + }% + \ht\spx@tempboxb\ht\spx@tempboxa + \dp\spx@tempboxb\dp\spx@tempboxa + \box\spx@tempboxb + \kern-\spx@boxes@border@bottom + \hrule\@height\spx@boxes@border@bottom + \kern-\dp\spx@tempboxa + }% attention this box has zero depth due to \hrule at bottom + % step back to horizontal reference point + \kern-\wd\spx@tempboxa + % end of border drawing + % CONTENTS + % adjust the total depth to include the bottom shadow + \ifspx@boxes@withshadow + \ifdim\spx@boxes@shadow@yoffset>\z@ + \dp\spx@tempboxa\dimexpr\dp\spx@tempboxa+\spx@boxes@shadow@yoffset\relax + \fi + \fi + \box\spx@tempboxa + % include lateral shadow in total width + \ifspx@boxes@withshadow + \ifspx@boxes@shadowinbbox + \ifdim\spx@boxes@shadow@xoffset>\z@\kern\spx@boxes@shadow@xoffset\fi + \fi + \fi + \egroup +} + +% inset shadow +% +% The parameters signs are interpreted as in CSS styling. +\def\spx@boxes@fcolorbox@insetshadow{% + % BACKGROUND + % draw background and move back to reference point + % 7.4.0 always assumes a background color + {\color{spx@boxes@backgroundcolor}% + \vrule\@height\ht\spx@tempboxa + \@depth\dp\spx@tempboxa + \@width\wd\spx@tempboxa + \kern-\wd\spx@tempboxa + }% + % BOX SHADOW + % draw shadow and move back to reference point + \ifspx@boxes@withshadow + \hbox{\vbox{\ifspx@boxes@withshadowcolor + \color{spx@boxes@shadowcolor}% + \else + % 6.2.0: guard against a manually inserted \color command in + % contents which could leak at a page break to the shadow + \normalcolor + \fi +% NOTA BENE +% We deliberately draw shadow partially under an area later covered by frame +% with the idea to avoid anti-aliasing problems but in fact this may be a bad +% idea with border is thin. +% This may need some extra testing with PDF viewers... reports welcome! + \ifdim\spx@boxes@shadow@yoffset>\z@ + \hrule\@height\dimexpr\spx@boxes@border@top+\spx@boxes@shadow@yoffset\relax + \kern-\spx@boxes@shadow@yoffset + \kern-\spx@boxes@border@top + \fi + \setbox\spx@tempboxb\hb@xt@\wd\spx@tempboxa{% + \ifdim\spx@boxes@shadow@xoffset>\z@ + \vrule\@width\dimexpr\spx@boxes@border@left+\spx@boxes@shadow@xoffset\relax\fi + \hss + \ifdim\spx@boxes@shadow@xoffset<\z@ + \vrule\@width\dimexpr-\spx@boxes@shadow@xoffset+\spx@boxes@border@right\relax\fi + }% + \ht\spx@tempboxb\ht\spx@tempboxa + \dp\spx@tempboxb\dp\spx@tempboxa + \box\spx@tempboxb + \ifdim\spx@boxes@shadow@yoffset<\z@ + \kern\spx@boxes@shadow@yoffset + \kern-\spx@boxes@border@bottom + \hrule\@height\dimexpr-\spx@boxes@shadow@yoffset+\spx@boxes@border@bottom\relax + \fi + \kern-\dp\spx@tempboxa + }% end of \vbox, attention it will have zero depth if yoffset<0 + \kern-\wd\spx@tempboxa + }% end of \hbox, attention its depth is only |yoffset| if yoffset<0 + \fi % end of inset shadow drawing, and we are back to horizontal reference point + % BOX BORDER + % 7.4.0 requires a set border color + \vbox{\color{spx@boxes@bordercolor}% + \hrule\@height\spx@boxes@border@top + \kern-\spx@boxes@border@top + \setbox\spx@tempboxb\hb@xt@\wd\spx@tempboxa + {\vrule\@width\spx@boxes@border@left + \hss\vrule\@width\spx@boxes@border@right + }% + \ht\spx@tempboxb\ht\spx@tempboxa + \dp\spx@tempboxb\dp\spx@tempboxa + \box\spx@tempboxb + \kern-\spx@boxes@border@bottom + \hrule\@height\spx@boxes@border@bottom + \kern-\dp\spx@tempboxa + }% attention this box has zero depth due to \hrule at bottom + % step back to horizontal reference point + \kern-\wd\spx@tempboxa + % end of border drawing + % CONTENTS + \box\spx@tempboxa + \egroup +} + +% let's abort input if pict2e package could not be loaded. +% To be extra safe we also alias @rounded to @rectangle but +% a priori the architecture is done so that @rounded will never +% be called in that case by other Sphinx LaTeX components. +\@ifpackageloaded{pict2e} + {} + {\def\spx@boxes@fcolorbox@rounded{\spx@boxes@fcolorbox@rectangle}% + \endinput + } + +% we proceed now in the context of pict2e being available and loaded +% (TeX being a macro-expansion based language it would have +% swallowed all the coming definitions even if pict2e +% had in fact not been loaded... but we aborted the input above) +%%%%%%%% +%//// \spx@boxes@fcolorbox@rounded +% +% Prior to 6.2.0, a constant border-width was applied as the border was +% obtained as a \strokepath. This allowed 4 distinct radii but not to vary the +% border widths. Now the border is drawn by two \fillpath operation, the first +% one filling up to external border, the second one actually filling for the +% background paradoxically on top of it, up to internal border path. +% +% This 6.2.0 abandonment of \strokepath allowed great simplification in +% supporting opentop, openbottom and openboth situations, and it can +% allow automatic support of openleft and openright analogs. +% +% And 6.2.0 also implements elliptical arcs thanks to ellipse package, +% which extends pict2e. + +% Currently, inset shadow is not supported. +% +% Prior to 6.2.0 an inset shadow triggered the rectangle variant, so we never +% ended here, but now it is simply ignored. This change does not appear to me +% to be breaking, as it changes output only for conf.py's specifying both +% rounded corners and an inset shadow and the documentation said it was +% incompatible. + +% wrappers for pict2e usage if old +% Better not to copy over 2020 pict2e definitions in case +% something internal changes +% However our wrappers will work ONLY with dimensional inputs +% No need to pre-expand the arguments +% Braces in case the expression uses parentheses +\def\spx@moveto(#1,#2){\moveto({\strip@pt\dimexpr#1\relax},{\strip@pt\dimexpr#2\relax})} +\def\spx@lineto(#1,#2){\lineto({\strip@pt\dimexpr#1\relax},{\strip@pt\dimexpr#2\relax})} +% attention here the [N] becomes mandatory +% \circlearc[]{}{}{}{}{} +\def\spx@circlearc[#1]#2#3#4%#5#6 + {\circlearc[#1]{\strip@pt\dimexpr#2\relax}% + {\strip@pt\dimexpr#3\relax}% + {\strip@pt\dimexpr#4\relax}% + } +% attention here too the [N] becomes mandatory +% the core path macro of ellipse.sty. Thanks to Daan Leijen, author of this +% package. +% \elliparc []{}{}{}{}{}{} +% maybe this wrapper is unneeded but I don't have real time to check +\def\spx@elliparc[#1]#2#3#4#5%#6#7 + {\elliparc[#1]{\strip@pt\dimexpr#2\relax}% + {\strip@pt\dimexpr#3\relax}% + {\strip@pt\dimexpr#4\relax}% + {\strip@pt\dimexpr#5\relax}% + } + +% Macro whose execution prepares a path to be either stroked or filled +% Only fill operation is used at 6.2.0. The radii are given by the set box +% parameters, but the width and height are in \spx@width and \spx@height. A +% \put command will be used for appropriate shifts. +% 6.2.0 adds elliptical corners! +% But I feel perhaps I need to think about how x-radius and y-radius should +% interact with border-width. So consider output WIP for time being. +\def\spx@boxes@border@defpath{% + \spx@moveto(\spx@boxes@radius@bottomleft@x,\z@)% our \spx@moveto is a bit rigid + % and we must use \z@ not 0 here + \spx@lineto(\spx@width-\spx@boxes@radius@bottomright@x,\z@)% + % x and y radii are either both positive or both zero + % probably not needed to actually guard against the latter case, + % let's do it nevertheless + \ifdim\spx@boxes@radius@bottomright@x>\z@ + \ifdim\spx@boxes@radius@bottomright@x=\spx@boxes@radius@bottomright@y + \spx@circlearc[2]{\spx@width-\spx@boxes@radius@bottomright@x}% + {\spx@boxes@radius@bottomright@y}% + {\spx@boxes@radius@bottomright@x}{-90}{0}% + \else + \spx@elliparc[2]{\spx@width-\spx@boxes@radius@bottomright@x}% + {\spx@boxes@radius@bottomright@y}% + {\spx@boxes@radius@bottomright@x} + {\spx@boxes@radius@bottomright@y}{-90}{0}% + \fi + \fi + \spx@lineto(\spx@width,% + \spx@height-\spx@boxes@radius@topright@y)% + \ifdim\spx@boxes@radius@topright@x>\z@ + \ifdim\spx@boxes@radius@topright@x=\spx@boxes@radius@topright@y + \spx@circlearc[2]{\spx@width-\spx@boxes@radius@topright@x} + {\spx@height-\spx@boxes@radius@topright@y}% + {\spx@boxes@radius@topright@x}{0}{90}% + \else + \spx@elliparc[2]{\spx@width-\spx@boxes@radius@topright@x} + {\spx@height-\spx@boxes@radius@topright@y}% + {\spx@boxes@radius@topright@x}% + {\spx@boxes@radius@topright@y}{0}{90}% + \fi + \fi + \spx@lineto(\spx@boxes@radius@topleft@x,\spx@height)% + \ifdim\spx@boxes@radius@topleft@x>\z@ + \ifdim\spx@boxes@radius@topleft@x=\spx@boxes@radius@topleft@y + \spx@circlearc[2]{\spx@boxes@radius@topleft@x}% + {\spx@height-\spx@boxes@radius@topleft@y}% + {\spx@boxes@radius@topleft@x}{90}{180}% + \else + \spx@elliparc[2]{\spx@boxes@radius@topleft@x}% + {\spx@height-\spx@boxes@radius@topleft@y}% + {\spx@boxes@radius@topleft@x}% + {\spx@boxes@radius@topleft@y}{90}{180}% + \fi + \fi + \spx@lineto(\z@,\spx@boxes@radius@bottomleft@y)% + \ifdim\spx@boxes@radius@bottomleft@x>\z@ + \ifdim\spx@boxes@radius@bottomleft@x=\spx@boxes@radius@bottomleft@y + \spx@circlearc[2]{\spx@boxes@radius@bottomleft@x}% + {\spx@boxes@radius@bottomleft@y}% + {\spx@boxes@radius@bottomleft@x}{180}{270}% + \else + \spx@elliparc[2]{\spx@boxes@radius@bottomleft@x}% + {\spx@boxes@radius@bottomleft@y}% + {\spx@boxes@radius@bottomleft@x}% + {\spx@boxes@radius@bottomleft@y}{180}{270}% + \fi + \fi +}% end of definition of \spx@boxes@border@defpath + +% The customization of the various parameters must have been done via an +% appropriate call to \spx@boxes@fcolorbox@setup, which will have set up +% \spx@boxes@fcolorbox to expand to \spx@boxes@fcolorbox@rounded, and will +% have set its various parameters. +% +\long\def\spx@boxes@fcolorbox@rounded #1{% + \hbox{% + \ifspx@boxes@withshadow + \ifspx@boxes@insetshadow + \spx@boxes@withshadowfalse % ignore inset shadow + \fi + \fi + % reserve space to external shadow if on left + \ifspx@boxes@withshadow + \ifspx@boxes@shadowinbbox + \ifdim\spx@boxes@shadow@xoffset<\z@\kern-\spx@boxes@shadow@xoffset\fi + \fi + \fi + \vbox{% + % adjust vertical bbox + \ifspx@boxes@withshadow + \ifdim\spx@boxes@shadow@yoffset<\z@ + \kern-\spx@boxes@shadow@yoffset + \fi + \fi + \setlength{\unitlength}{1pt}% + \setbox\spx@tempboxa + \hbox{\kern\dimexpr\spx@boxes@border@left+\spx@boxes@padding@left\relax + {#1}% + \kern\dimexpr\spx@boxes@padding@right+\spx@boxes@border@right\relax}% + \ht\spx@tempboxa + \dimexpr\ht\spx@tempboxa+\spx@boxes@border@top+\spx@boxes@padding@top\relax + \dp\spx@tempboxa + \dimexpr\dp\spx@tempboxa+\spx@boxes@padding@bottom+\spx@boxes@border@bottom\relax + \edef\spx@width{\number\wd\spx@tempboxa sp}% + \edef\spx@height{\number\dimexpr\ht\spx@tempboxa+\dp\spx@tempboxa sp}% + \hbox{% + \begin{picture}% + % \strip@pt\dimexpr to work around "old" LaTeX picture limitation + % (we could use the "picture" package, this would add another dependency) + (\strip@pt\dimexpr\spx@width\relax,\strip@pt\dimexpr\spx@height\relax)% + \spx@boxes@border@defpath + \ifspx@boxes@withshadow + \ifspx@boxes@withshadowcolor + \color{spx@boxes@shadowcolor}% + \else + % 6.2.0: here and elsewhere guard against a manually inserted + % \color command in contents which could leak to the shadow + % to the shadow + \normalcolor + \fi + \put(\strip@pt\spx@boxes@shadow@xoffset,% + \strip@pt\dimexpr-\spx@boxes@shadow@yoffset\relax) + {\fillpath}% + \fi + \spx@boxes@border@defpath% must be redone after each \fillpath! (even if + % was in a \put) + % 7.4.0 requires a set border color + \color{spx@boxes@bordercolor}% + \fillpath + % and backgroundcolor command + \color{spx@boxes@backgroundcolor}% + \edef\spx@width{\number\dimexpr\spx@width-\spx@boxes@border@left + -\spx@boxes@border@right sp}% + \edef\spx@height{\number\dimexpr\spx@height-\spx@boxes@border@top + -\spx@boxes@border@bottom sp}% + % redefine a path (in relative coordinates) matching the area delimited + % by the internal borders + \spx@boxes@border@defpath + % use \put to shift, and fill it with background color + \put(\strip@pt\spx@boxes@border@left,\strip@pt\spx@boxes@border@bottom) + {\fillpath}% + \end{picture}}% end of picture \hbox in \vbox + % back-up vertically for outputting the contents + \kern-\dimexpr\ht\spx@tempboxa+\dp\spx@tempboxa\relax + % adjust vertical bbox + \ifspx@boxes@withshadow + \ifdim\spx@boxes@shadow@yoffset>\z@ + \dp\spx@tempboxa\dimexpr\dp\spx@tempboxa+\spx@boxes@shadow@yoffset\relax + \fi + \fi + % inhibit TeX's "line skip" adjustment when piling up hboxes in a vbox + \nointerlineskip + \box\spx@tempboxa + }% end of \vbox + % include lateral shadow in total width + \ifspx@boxes@withshadow + \ifspx@boxes@shadowinbbox + \ifdim\spx@boxes@shadow@xoffset>\z@\kern\spx@boxes@shadow@xoffset\fi + \fi + \fi + }% end of \hbox +}% + + +\endinput diff --git a/build/latex/sphinxpackagecyrillic.sty b/build/latex/sphinxpackagecyrillic.sty new file mode 100644 index 0000000..9aa62fc --- /dev/null +++ b/build/latex/sphinxpackagecyrillic.sty @@ -0,0 +1,55 @@ +%% CYRILLIC IN NON-CYRILLIC DOCUMENTS (pdflatex only) +% +% refs: https://tex.stackexchange.com/q/460271/ +\ProvidesPackage{sphinxpackagecyrillic}% + [2018/11/21 v2.0 support for Cyrillic in non-Cyrillic documents] +\RequirePackage{kvoptions} +\SetupKeyvalOptions{prefix=spx@cyropt@} % use \spx@cyropt@ prefix +\DeclareBoolOption[false]{Xtwo} +\DeclareBoolOption[false]{TtwoA} +\DeclareDefaultOption{\@unknownoptionerror} +\ProcessLocalKeyvalOptions* % ignore class options + +\ifspx@cyropt@Xtwo +% original code by tex.sx user egreg (updated 2019/10/28): +% https://tex.stackexchange.com/a/460325/ +% 159 Cyrillic glyphs as available in X2 TeX 8bit font encoding +% This assumes inputenc loaded with utf8 option, or LaTeX release +% as recent as 2018/04/01 which does it automatically. + \@tfor\next:=% + {Ё}{Ђ}{Є}{Ѕ}{І}{Ј}{Љ}{Њ}{Ћ}{Ў}{Џ}{А}{Б}{В}{Г}{Д}{Е}{Ж}{З}{И}{Й}% + {К}{Л}{М}{Н}{О}{П}{Р}{С}{Т}{У}{Ф}{Х}{Ц}{Ч}{Ш}{Щ}{Ъ}{Ы}{Ь}{Э}{Ю}% + {Я}{а}{б}{в}{г}{д}{е}{ж}{з}{и}{й}{к}{л}{м}{н}{о}{п}{р}{с}{т}{у}% + {ф}{х}{ц}{ч}{ш}{щ}{ъ}{ы}{ь}{э}{ю}{я}{ё}{ђ}{є}{ѕ}{і}{ј}{љ}{њ}{ћ}% + {ў}{џ}{Ѣ}{ѣ}{Ѫ}{ѫ}{Ѵ}{ѵ}{Ґ}{ґ}{Ғ}{ғ}{Ҕ}{ҕ}{Җ}{җ}{Ҙ}{ҙ}{Қ}{қ}{Ҝ}{ҝ}% + {Ҟ}{ҟ}{Ҡ}{ҡ}{Ң}{ң}{Ҥ}{ҥ}{Ҧ}{ҧ}{Ҩ}{ҩ}{Ҫ}{ҫ}{Ҭ}{ҭ}{Ү}{ү}{Ұ}{ұ}{Ҳ}{ҳ}% + {Ҵ}{ҵ}{Ҷ}{ҷ}{Ҹ}{ҹ}{Һ}{һ}{Ҽ}{ҽ}{Ҿ}{ҿ}{Ӏ}{Ӄ}{ӄ}{Ӆ}{ӆ}{Ӈ}{ӈ}{Ӌ}{ӌ}% + {Ӎ}{ӎ}{Ӕ}{ӕ}{Ә}{ә}{Ӡ}{ӡ}{Ө}{ө}\do + {% + \begingroup\def\IeC{\protect\DeclareTextSymbolDefault}% + \protected@edef\@temp{\endgroup + \@ifl@t@r{\fmtversion}{2019/10/01}{\csname u8:\next\endcsname}{\next}}% + \@temp{X2}% + }% +\else +\ifspx@cyropt@TtwoA +% original code by tex.sx user jfbu: +% https://tex.stackexchange.com/a/460305/ +% 63*2+1=127 Cyrillic glyphs as found in T2A 8bit TeX font-encoding + \@tfor\@tempa:=% + {ae}{a}{b}{chrdsc}{chvcrs}{ch}{c}{dje}{dze}{dzhe}{d}{erev}{ery}{e}% + {f}{ghcrs}{gup}{g}{hdsc}{hrdsn}{h}{ie}{ii}{ishrt}{i}{je}% + {kbeak}{kdsc}{kvcrs}{k}{lje}{l}{m}{ndsc}{ng}{nje}{n}{otld}{o}{p}{r}% + {schwa}{sdsc}{sftsn}{shch}{shha}{sh}{s}{tshe}{t}{ushrt}{u}{v}% + {ya}{yhcrs}{yi}{yo}{yu}{y}{zdsc}{zhdsc}{zh}{z}\do + {% + \expandafter\DeclareTextSymbolDefault\expandafter + {\csname cyr\@tempa\endcsname}{T2A}% + \expandafter\uppercase\expandafter{\expandafter + \def\expandafter\@tempa\expandafter{\@tempa}}% + \expandafter\DeclareTextSymbolDefault\expandafter + {\csname CYR\@tempa\endcsname}{T2A}% + }% + \DeclareTextSymbolDefault{\CYRpalochka}{T2A}% +\fi\fi +\endinput diff --git a/build/latex/sphinxpackagefootnote.sty b/build/latex/sphinxpackagefootnote.sty new file mode 100644 index 0000000..f68bcf3 --- /dev/null +++ b/build/latex/sphinxpackagefootnote.sty @@ -0,0 +1,439 @@ +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{sphinxpackagefootnote}% + [2025/11/15 v9.0.0 Sphinx custom footnotehyper package (Sphinx team)] +%% +%% Package: sphinxpackagefootnote +%% Version: based on footnotehyper.sty 2021/02/04 v1.1d +%% https://www.ctan.org/pkg/footnotehyper +%% License: the one applying to Sphinx +%% +% Provides support for footnote mark-up from Sphinx latex writer: +% - "footnote" and "footnotetext" environments allowing verbatim material +% - "savenotes" environment for wrapping environments, such as for tables +% which have problems with LaTeX footnotes +% - hyperlinks +% +% Sphinx uses exclusively this mark-up for footnotes: +% - \begin{footnote}[N] +% - \begin{footnotetext}[N] +% - \sphinxfootnotemark[N] +% where N is a number. +% +%% Some small differences from footnotehyper.sty 2021/02/04 v1.1d: +%% - a tabulary compatibility layer (partial but enough for Sphinx), +%% - usage of \spx@opt@BeforeFootnote +%% - usage of \sphinxunactivateextrasandspace from sphinx.sty, +%% - \sphinxlongtablepatch +%% - fix for a change of babel-french from late June 2025 +%% (\localleftbox undefined with pdflatex/xelatex, issue #14059) +%% +%% Starting with Sphinx v4.5.0, inherited footnotehyper macros for +%% footnote/footnotetext receive some Sphinx specific extras to +%% implement "intelligent" footnote marks checking page numbers. +%% +%% All footnotes output from Sphinx are hyperlinked. With "savenotes" +%% footnotes may appear on page distinct from footnote mark, the latter +%% will indicate page number of the footnote. +\newif\iffootnotehyperparse\footnotehyperparsetrue +\DeclareOption*{\PackageWarning{sphinxpackagefootnote}{Option `\CurrentOption' is unknown}}% +\ProcessOptions\relax +\newbox\FNH@notes +\newtoks\FNH@toks % 1.1c +\newdimen\FNH@width +\let\FNH@colwidth\columnwidth +\newif\ifFNH@savingnotes +\AtBeginDocument {% + \let\FNH@latex@footnote \footnote + \let\FNH@latex@footnotetext\footnotetext + \let\FNH@H@@footnotetext \@footnotetext + \let\FNH@H@@mpfootnotetext \@mpfootnotetext + \newenvironment{savenotes} + {\FNH@savenotes\ignorespaces}{\FNH@spewnotes\ignorespacesafterend}% + \let\spewnotes \FNH@spewnotes + \let\footnote \FNH@footnote + \let\footnotetext \FNH@footnotetext + \let\endfootnote \FNH@endfntext + \let\endfootnotetext\FNH@endfntext + % always True branch taken with Sphinx + \@ifpackageloaded{hyperref} + {\ifHy@hyperfootnotes + \let\FNH@H@@footnotetext\H@@footnotetext + \let\FNH@H@@mpfootnotetext\H@@mpfootnotetext + \else + \let\FNH@hyper@fntext\FNH@nohyp@fntext + \fi}% + {\let\FNH@hyper@fntext\FNH@nohyp@fntext}% +}% +\def\FNH@hyper@fntext{\FNH@fntext\FNH@hyper@fntext@i}% +\def\FNH@nohyp@fntext{\FNH@fntext\FNH@nohyp@fntext@i}% +\def\FNH@fntext #1{% + \ifx\ifmeasuring@\@undefined + \expandafter\@secondoftwo\else\expandafter\@firstofone\fi +% these two lines modified for Sphinx (tabulary compatibility): + {\ifmeasuring@\expandafter\@gobbletwo\else\expandafter\@firstofone\fi}% + {\ifx\equation$\expandafter\@gobbletwo\fi #1}%$ +}% +\long\def\FNH@hyper@fntext@i#1{% + \global\setbox\FNH@notes\vbox + {\unvbox\FNH@notes + \FNH@startnote + \@makefntext + {\rule\z@\footnotesep\ignorespaces + \ifHy@nesting\expandafter\ltx@firstoftwo + \else\expandafter\ltx@secondoftwo + \fi + {\expandafter\hyper@@anchor\expandafter{\Hy@footnote@currentHref}{#1}}% + {\Hy@raisedlink + {\expandafter\hyper@@anchor\expandafter{\Hy@footnote@currentHref}% + {\relax}}% + \let\@currentHref\Hy@footnote@currentHref + \let\@currentlabelname\@empty + #1}% + \@finalstrut\strutbox + }% + \FNH@endnote + }% +}% +\long\def\FNH@nohyp@fntext@i#1{% + \global\setbox\FNH@notes\vbox + {\unvbox\FNH@notes + \FNH@startnote + \@makefntext{\rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}% + \FNH@endnote + }% +}% +\def\FNH@startnote{% + \hsize\FNH@colwidth + \interlinepenalty\interfootnotelinepenalty + \reset@font\footnotesize + \floatingpenalty\@MM + \@parboxrestore + \protected@edef\@currentlabel{\csname p@\@mpfn\endcsname\@thefnmark}% + \color@begingroup +}% +\def\FNH@endnote{\color@endgroup}% +\def\FNH@savenotes{% + \begingroup + \ifFNH@savingnotes\else + \FNH@savingnotestrue + \let\@footnotetext \FNH@hyper@fntext + \let\@mpfootnotetext \FNH@hyper@fntext + \let\H@@mpfootnotetext\FNH@nohyp@fntext + \FNH@width\columnwidth + \let\FNH@colwidth\FNH@width + \global\setbox\FNH@notes\box\voidb@x + \let\FNH@thempfn\thempfn + \let\FNH@mpfn\@mpfn + \ifx\@minipagerestore\relax\let\@minipagerestore\@empty\fi + \expandafter\def\expandafter\@minipagerestore\expandafter{% + \@minipagerestore + \let\thempfn\FNH@thempfn + \let\@mpfn\FNH@mpfn + }% + \fi +}% +\def\FNH@spewnotes {% + \if@endpe\ifx\par\@@par\FNH@toks{}\else + \FNH@toks\expandafter{\expandafter + \def\expandafter\par\expandafter{\par}\@endpetrue}% + \expandafter\expandafter\expandafter + \FNH@toks + \expandafter\expandafter\expandafter + {\expandafter\the\expandafter\FNH@toks + \expandafter\def\expandafter\@par\expandafter{\@par}}% + \expandafter\expandafter\expandafter + \FNH@toks + \expandafter\expandafter\expandafter + {\expandafter\the\expandafter\FNH@toks + \expandafter\everypar\expandafter{\the\everypar}}\fi + \else\FNH@toks{}\fi + \expandafter + \endgroup\the\FNH@toks + \ifFNH@savingnotes\else + \ifvoid\FNH@notes\else + \begingroup + \let\@makefntext\@empty + \let\@finalstrut\@gobble + \let\rule\@gobbletwo + \ifx\@footnotetext\@mpfootnotetext + \expandafter\FNH@H@@mpfootnotetext + \else + \expandafter\FNH@H@@footnotetext + \fi{\unvbox\FNH@notes}% + \endgroup + \fi + \fi +}% +\def\FNH@footnote@envname {footnote}% +\def\FNH@footnotetext@envname{footnotetext}% +\def\FNH@footnote{% +% this line added for Sphinx: + \spx@opt@BeforeFootnote + \ifx\@currenvir\FNH@footnote@envname + \expandafter\FNH@footnoteenv + \else + \expandafter\FNH@latex@footnote + \fi +}% +\def\FNH@footnoteenv{% +% this line added for Sphinx (footnotes in parsed literal blocks): + \catcode13=5 \sphinxunactivateextrasandspace + \@ifnextchar[% + \FNH@footnoteenv@i %] + {\stepcounter\@mpfn + \protected@xdef\@thefnmark{\thempfn}% + \@footnotemark + \def\FNH@endfntext@fntext{\@footnotetext}% + \FNH@startfntext}% +}% +\def\FNH@footnoteenv@i[#1]{% + \begingroup + % This legacy code from LaTeX core restricts #1 to be digits only + % This limitation could be lifted but legacy Sphinx anyhow obeys it + \csname c@\@mpfn\endcsname #1\relax + \unrestored@protected@xdef\@thefnmark{\thempfn}% + \endgroup +% -- Sphinx specific: +% currently commented out due to +% https://github.com/sphinx-doc/sphinx/pull/10191#issuecomment-1038807448 +% Memo: memoir class detection of successive footnote marks (to separate them +% by commas) is broken by \refstepcounter and also by \label, and some +% mitigation such as in \sphinxfootref would be needed + % \global\let\spx@saved@thefnmark\@thefnmark + % % this is done to access robustly the page number where footnote mark is + % \refstepcounter{sphinxfootnotemark}\label{footnotemark.\thesphinxfootnotemark}% + % % if possible, compare page numbers of mark and footnote to define \@thefnmark + % \ltx@ifundefined{r@\thesphinxscope.footnote.#1}% + % {}% one more latex run is needed + % {\sphinx@xdef@thefnmark{#1}}% check of page numbers possible +% -- + \@footnotemark + \def\FNH@endfntext@fntext{\@footnotetext}% +% -- Sphinx specific: + % we need to reset \@thefnmark as it is used by \FNH@startfntext via + % \FNH@startnote to set \@currentlabel which will be used by \label +% currently commented out (see above) + % \global\let\@thefnmark\spx@saved@thefnmark +% -- + \FNH@startfntext +% -- again Sphinx specific + % \@currentlabel as needed by \label got set by \FNH@startnote + % insert this at start of footnote text then the label will allow + % to robustly know on which page the footnote text ends up +% currently only of use for extra footnote marks so in case footnote multiply referred + \phantomsection\label{\thesphinxscope.footnote.#1}% +}% +\def\FNH@footnotetext{% + \ifx\@currenvir\FNH@footnotetext@envname + \expandafter\FNH@footnotetextenv + \else + \expandafter\FNH@latex@footnotetext + \fi +}% +\def\FNH@footnotetextenv{% + \@ifnextchar[% + \FNH@footnotetextenv@i %] + {\protected@xdef\@thefnmark{\thempfn}% + \def\FNH@endfntext@fntext{\@footnotetext}% + \FNH@startfntext}% +}% +\def\FNH@footnotetextenv@i[#1]{% + \begingroup + \csname c@\@mpfn\endcsname #1\relax + \unrestored@protected@xdef\@thefnmark{\thempfn}% + \endgroup + \ifFNH@savingnotes + \def\FNH@endfntext@fntext{\FNH@nohyp@fntext}% + \else + \def\FNH@endfntext@fntext{\FNH@H@@footnotetext}% + \fi + \FNH@startfntext +% -- Sphinx specific addition + \phantomsection\label{\thesphinxscope.footnote.#1}% +}% +\def\FNH@startfntext{% + \setbox\z@\vbox\bgroup + \FNH@startnote + \FNH@prefntext + \rule\z@\footnotesep\ignorespaces +}% +\def\FNH@endfntext {% + \@finalstrut\strutbox + \FNH@postfntext + \FNH@endnote + \egroup + \begingroup + \let\@makefntext\@empty\let\@finalstrut\@gobble\let\rule\@gobbletwo + \FNH@endfntext@fntext {\unvbox\z@}% + \endgroup +}% +\let\FNH@prefntext\@empty +\let\FNH@postfntext\@empty +\AtBeginDocument{\iffootnotehyperparse\expandafter\FNH@check\fi}% +\def\FNH@safeif#1{% + \iftrue\csname if#1\endcsname\csname fi\endcsname\expandafter\@firstoftwo + \else\csname fi\endcsname\expandafter\@secondoftwo + \fi +}% +\def\FNH@check{% + \ifx\@makefntextFB\@undefined + \expandafter\FNH@check@ + \else + \providecommand\localleftbox[1]{}% + \expandafter\FNH@frenchb@ + \fi +}% +\def\FNH@frenchb@{% + \def\FNH@prefntext{% + \localleftbox{}% + \let\FBeverypar@save\FBeverypar@quote + \let\FBeverypar@quote\relax + \FNH@safeif{FB@koma}% + {\FNH@safeif{FBFrenchFootnotes}% + {\ifx\footnote\thanks + \let\@@makefnmark\@@makefnmarkTH + \@makefntextTH{} % space as in french.ldf + \else + \let\@@makefnmark\@@makefnmarkFB + \@makefntextFB{} % space as in french.ldf + \fi + }{\let\@@makefnmark\@@makefnmarkORI + \@makefntextORI{}% no space as in french.ldf + }% + }% + {\FNH@safeif{FBFrenchFootnotes}% + {\@makefntextFB{}}% + {\@makefntextORI{}}% + }% + }% + \def\FNH@postfntext{% + \let\FBeverypar@quote\FBeverypar@save + \localleftbox{\FBeveryline@quote}% + }% +}% +\def\FNH@check@{% + \expandafter\FNH@check@a\@makefntext{1.2!3?4,}% + \FNH@@@1.2!3?4,\FNH@@@\relax +}% +\long\def\FNH@check@a #11.2!3?4,#2\FNH@@@#3{% + \ifx\relax#3\expandafter\FNH@checkagain@ + \else + \def\FNH@prefntext{#1}\def\FNH@postfntext{#2}% + \expandafter\FNH@check@b + \fi +}% +\def\FNH@checkagain@{% + \expandafter\FNH@checkagain@a + \detokenize\expandafter{\@makefntext{1.2!3?4,}}\relax\FNH@@@ +}% +\edef\FNH@temp{\noexpand\FNH@checkagain@a ##1\string{1.2!3?4,\string}}% +\expandafter\def\FNH@temp#2#3\FNH@@@{% + \ifx\relax#2% + \def\FNH@prefntext{\@makefntext{}}% + \else\FNH@bad@makefntext@alert + \fi +}% +\def\FNH@check@b #1\relax{% + \expandafter\expandafter\expandafter\FNH@check@c + \expandafter\meaning\expandafter\FNH@prefntext + \meaning\FNH@postfntext1.2!3?4,\FNH@check@c\relax +}% +\def\FNH@check@c #11.2!3?4,#2#3\relax{% + \ifx\FNH@check@c#2\else\FNH@bad@makefntext@alert\fi +}% +% slight reformulation for Sphinx +\def\FNH@bad@makefntext@alert{% + \sphinxbuildwarning{badfootnotes}% + \PackageWarningNoLine{sphinxpackagefootnote}% + {Footnotes will be sub-optimal, sorry. This is due to the document class or^^J + some package modifying macro \string\@makefntext.^^J + You can try to report this incompatibility at^^J + https://github.com/sphinx-doc/sphinx with this info:}% + \typeout{\meaning\@makefntext}% + \let\FNH@prefntext\@empty\let\FNH@postfntext\@empty +}% +% this macro from original footnote.sty is not used anymore by Sphinx +% but for simplicity sake let's just keep it as is +\def\makesavenoteenv{\@ifnextchar[\FNH@msne@ii\FNH@msne@i}%] +\def\FNH@msne@i #1{% + \expandafter\let\csname FNH$#1\expandafter\endcsname %$ + \csname #1\endcsname + \expandafter\let\csname endFNH$#1\expandafter\endcsname %$ + \csname end#1\endcsname + \FNH@msne@ii[#1]{FNH$#1}%$ +}% +\def\FNH@msne@ii[#1]#2{% + \expandafter\edef\csname#1\endcsname{% + \noexpand\savenotes + \expandafter\noexpand\csname#2\endcsname + }% + \expandafter\edef\csname end#1\endcsname{% + \expandafter\noexpand\csname end#2\endcsname + \noexpand\expandafter + \noexpand\spewnotes + \noexpand\if@endpe\noexpand\@endpetrue\noexpand\fi + }% +}% +% +% some extras for Sphinx : +% \sphinxfootnotemark: +% - if in section titles will auto-remove itself from TOC +\def\sphinxfootnotemark [#1]% + {\ifx\thepage\relax\else\sphinxfootref{#1}\fi}% +\newcounter{sphinxfootnotemark} +\renewcommand\thesphinxfootnotemark{\number\value{sphinxfootnotemark}} +% - compares page number of footnote mark versus the one of footnote text +\def\sphinx@xdef@thefnmark#1{% + \expandafter\expandafter\expandafter\sphinx@footref@get + \csname r@\thesphinxscope.footnote.#1\endcsname\relax + \expandafter\expandafter\expandafter\sphinx@footmark@getpage + \csname r@footnotemark.\thesphinxfootnotemark\endcsname\thepage\relax + \protected@xdef\@thefnmark{% + \ifx\spx@footmarkpage\spx@footrefpage + \spx@footreflabel + \else + % the macro \sphinxthefootnotemark is in sphinx.sty + \sphinxthefootnotemark{\spx@footreflabel}{\spx@footrefpage}% + \fi + }% +}% +\def\sphinx@footref@get #1#2#3#4#5\relax{% + \def\spx@footreflabel{#1}% + \def\spx@footrefpage {#2}% + \def\spx@footrefHref {#4}% +}% +\def\sphinx@footmark@getpage #1#2#3\relax{% + \edef\spx@footmarkpage{#2}% +}% +\protected\def\sphinxfootref#1{% #1 always is explicit number in Sphinx + \spx@opt@BeforeFootnote + % each of \refstepcounter and \label interferes with memoir class detection + % of successive footnote marks, so we move them to inside \@makefnmark + \let\spx@saved@makefnmark\@makefnmark + \ltx@ifundefined{r@\thesphinxscope.footnote.#1}% + {\gdef\@thefnmark{?}% on first LaTeX run + \refstepcounter{sphinxfootnotemark}\label{footnotemark.\thesphinxfootnotemark}% + }% + {\def\@makefnmark{% will be used by \H@@footnotemark + \refstepcounter{sphinxfootnotemark}\label{footnotemark.\thesphinxfootnotemark}% + \sphinx@xdef@thefnmark{#1}% also defines \spx@footrefHref + % must be executed after \refstepcounter + \hyper@linkstart{link}{\spx@footrefHref}% + \spx@saved@makefnmark + \hyper@linkend + }% + }% + \H@@footnotemark + \let\@makefnmark\spx@saved@makefnmark +}% +\AtBeginDocument{% + % let hyperref less complain + \pdfstringdefDisableCommands{\def\sphinxfootnotemark [#1]{}}% + % to obtain hyperlinked footnotes in longtable environment we must replace + % hyperref's patch of longtable's patch of \@footnotetext by our own + \let\LT@p@ftntext\FNH@hyper@fntext + % this *requires* longtable to be used always wrapped in savenotes environment +}% +\endinput +%% +%% End of file `sphinxpackagefootnote.sty'. diff --git a/build/latex/sphinxpackagesubstitutefont.sty b/build/latex/sphinxpackagesubstitutefont.sty new file mode 100644 index 0000000..536bf20 --- /dev/null +++ b/build/latex/sphinxpackagesubstitutefont.sty @@ -0,0 +1,21 @@ +%% a stub for obsoleted LaTeX package substitutefont +% The package substitutefont stopped being distributed with TeXLive +% around August 2023 and was moved to "obsolete" section. +% cf https://ctan.org/pkg/substitutefont +% Trying to load it raises a LaTeX build error since. + +% The \substitutefont has a LaTeX kernel replacement +% \DeclareFontFamilySubstitution +% which was added to LaTeX 2020-02-02 +% The aim of this stub is to do that replacement silently. + +% change this info string if making any custom modification +\ProvidesPackage{sphinxpackagesubstitutefont}[2023/15/11 v7.3.0 substitutefont stub] + +\ifdefined\DeclareFontFamilySubstitution + \def\substitutefont{\DeclareFontFamilySubstitution} +\else + \usepackage{substitutefont} +\fi + +\endinput diff --git a/go/internal/leaf/leaf.go b/go/internal/leaf/leaf.go index f1d150a..51be009 100644 --- a/go/internal/leaf/leaf.go +++ b/go/internal/leaf/leaf.go @@ -64,8 +64,7 @@ func (n *Node) subscribe() error { } } if _, err := n.nc.Subscribe("verae.sm.send", func(msg *nats.Msg) { - // Passthrough: do not log ciphertext. - ack(msg, []byte(`{"accepted":true}`)) + n.handleSend(msg) }); err != nil { return err } @@ -82,6 +81,12 @@ func (n *Node) subscribe() error { if _, err := n.nc.Subscribe("verae.sm.log.summary", func(msg *nats.Msg) { var hdr map[string]any _ = json.Unmarshal(msg.Data, &hdr) + // Summary only: never log ciphertext or recipient payload. + if _, ok := hdr["ct"]; ok { + log.Printf("sm-summary rejected body-like field") + ack(msg, []byte(`{"logged":false,"error":"body-like fields present"}`)) + return + } log.Printf("sm-summary code=%v lookup=%v class=%v", hdr["error_code"], hdr["lookup_id"], hdr["dest_class"]) ack(msg, []byte(`{"logged":true}`)) }); err != nil { @@ -90,6 +95,57 @@ func (n *Node) subscribe() error { return nil } +func (n *Node) handleSend(msg *nats.Msg) { + var env map[string]any + if err := json.Unmarshal(msg.Data, &env); err != nil { + n.fail(msg, "SM-BAD-JSON", "parse", "") + return + } + to, _ := env["to"].(string) + alg, _ := env["alg"].(string) + ct, _ := env["ct"].(string) + lid, _ := env["from_lookup_id"].(string) + if _, hasBody := env["body"]; hasBody { + n.fail(msg, "SM-PLAINTEXT-BODY", "mailbox", lid) + return + } + if to == "" { + n.fail(msg, "SM-MISSING-TO", "mailbox", lid) + return + } + if alg != "" && alg != "npe" && alg != "lab-xor" && alg != "plain-lab" { + n.fail(msg, "SM-BAD-ALG", "mailbox", lid) + return + } + if alg != "plain-lab" && ct == "" { + n.fail(msg, "SM-EMPTY-CT", "mailbox", lid) + return + } + ack, _ := json.Marshal(map[string]any{"accepted": true, "lookup_id": lid}) + if msg.Reply != "" { + _ = n.nc.Publish(msg.Reply, ack) + } +} + +func (n *Node) fail(msg *nats.Msg, code, destClass, lid string) { + summary, _ := json.Marshal(map[string]any{ + "error_code": code, + "lookup_id": lid, + "dest_class": destClass, + }) + _ = n.nc.Publish("verae.sm.log.summary", summary) + _ = n.nc.Publish("verae.sm.error", summary) + _ = n.nc.Publish("verae.sm.dead", summary) + ack, _ := json.Marshal(map[string]any{ + "accepted": false, + "error_code": code, + "lookup_id": lid, + }) + if msg.Reply != "" { + _ = n.nc.Publish(msg.Reply, ack) + } +} + // HealthHandler is the loopback JSON health mux (does not expose NATS). func HealthHandler() http.Handler { mux := http.NewServeMux() diff --git a/go/internal/leaf/leaf_test.go b/go/internal/leaf/leaf_test.go index f72be65..5a57b70 100644 --- a/go/internal/leaf/leaf_test.go +++ b/go/internal/leaf/leaf_test.go @@ -56,19 +56,78 @@ func TestSMSubjectsAck(t *testing.T) { t.Fatal(err) } defer n.Shutdown() - cases := map[string]string{ - "verae.sm.send": `{"accepted":true}`, + good := []byte(`{"to":"npe.inbox.x","alg":"lab-xor","ct":"abcd","from_lookup_id":"lid-good"}`) + msg, err := n.nc.Request("verae.sm.send", good, time.Second) + if err != nil { + t.Fatal(err) + } + var ack map[string]any + if err := json.Unmarshal(msg.Data, &ack); err != nil { + t.Fatal(err) + } + if ack["accepted"] != true || ack["lookup_id"] != "lid-good" { + t.Fatalf("good send %s", msg.Data) + } + for subj, want := range map[string]string{ "verae.sm.dead": `{"queued":true}`, "verae.sm.error": `{"emitted":true}`, "verae.sm.log.summary": `{"logged":true}`, - } - for subj, want := range cases { - msg, err := n.nc.Request(subj, []byte(`{"lookup_id":"t"}`), time.Second) + } { + got, err := n.nc.Request(subj, []byte(`{"lookup_id":"t","error_code":"x","dest_class":"mailbox"}`), time.Second) if err != nil { t.Fatalf("%s: %v", subj, err) } - if string(msg.Data) != want { - t.Fatalf("%s got %s want %s", subj, msg.Data, want) + if string(got.Data) != want { + t.Fatalf("%s got %s want %s", subj, got.Data, want) } } } + +func TestSMSendRejectsMissingTo(t *testing.T) { + n, err := Start("") + if err != nil { + t.Fatal(err) + } + defer n.Shutdown() + msg, err := n.nc.Request("verae.sm.send", []byte(`{"alg":"lab-xor","ct":"ab"}`), time.Second) + if err != nil { + t.Fatal(err) + } + var ack map[string]any + _ = json.Unmarshal(msg.Data, &ack) + if ack["accepted"] != false || ack["error_code"] != "SM-MISSING-TO" { + t.Fatalf("missing to %s", msg.Data) + } +} + +func TestSMSendRejectsEmptyCiphertext(t *testing.T) { + n, err := Start("") + if err != nil { + t.Fatal(err) + } + defer n.Shutdown() + msg, err := n.nc.Request("verae.sm.send", []byte(`{"to":"npe.inbox.x","alg":"lab-xor","ct":""}`), time.Second) + if err != nil { + t.Fatal(err) + } + var ack map[string]any + _ = json.Unmarshal(msg.Data, &ack) + if ack["accepted"] != false || ack["error_code"] != "SM-EMPTY-CT" { + t.Fatalf("empty ct %s", msg.Data) + } +} + +func TestSMSummaryRejectsCiphertextField(t *testing.T) { + n, err := Start("") + if err != nil { + t.Fatal(err) + } + defer n.Shutdown() + msg, err := n.nc.Request("verae.sm.log.summary", []byte(`{"error_code":"x","ct":"secret"}`), time.Second) + if err != nil { + t.Fatal(err) + } + if string(msg.Data) == `{"logged":true}` { + t.Fatal("must not log body-like fields") + } +} diff --git a/python/secure_messaging/__init__.py b/python/secure_messaging/__init__.py index 7b8a2a6..67006f6 100644 --- a/python/secure_messaging/__init__.py +++ b/python/secure_messaging/__init__.py @@ -4,6 +4,7 @@ from .envelope import PassthroughEnvelope # dest-in-clear, body ciphertext from .error_bundle import NetworkErrorBundle # system-key + sender-only from .admin_history import AdminHistory # DataCube-shaped append-only config log from .npe_adapter import NpeRequired # fail-closed NPE +from .router import RouteResult, handle_send # success/failure send policy __all__ = [ "SignedConfig", @@ -12,4 +13,6 @@ __all__ = [ "NetworkErrorBundle", "AdminHistory", "NpeRequired", + "RouteResult", + "handle_send", ] diff --git a/python/secure_messaging/router.py b/python/secure_messaging/router.py new file mode 100644 index 0000000..37db339 --- /dev/null +++ b/python/secure_messaging/router.py @@ -0,0 +1,106 @@ +"""Passthrough send policy: accept good mail, reject bad, emit logging. + +Correct targeted messages get an ack with lookup_id. +Incorrect messages take the failure path: Network Error Bundle shape, +dead letter, and a summary log that never includes ciphertext. +""" + +from __future__ import annotations # annotations + +import json # parse wire +from typing import Any, Dict, List, Optional # types + +from .error_bundle import NetworkErrorBundle, build_bundle, log_summary # failure path + + +ALLOWED_ALG = {"npe", "lab-xor", "plain-lab"} # signed-config crypto.mode set + + +class RouteResult: + """Outcome of one verae.sm.send.""" + + def __init__( + self, + *, + accepted: bool, + lookup_id: str = "", + error_code: str = "", + dest_class: str = "", + events: Optional[List[Dict[str, Any]]] = None, + bundle: Optional[NetworkErrorBundle] = None, + ): + self.accepted = accepted # success path + self.lookup_id = lookup_id # opaque sender handle + self.error_code = error_code # empty on success + self.dest_class = dest_class # mailbox | parse + self.events = events or [] # NATS publishes (subject, body) + self.bundle = bundle # failure only + + def ack(self) -> Dict[str, Any]: + """JSON reply to the sender (no ciphertext).""" + out = {"accepted": self.accepted, "lookup_id": self.lookup_id} # always lookup + if self.error_code: # failure + out["error_code"] = self.error_code # machine code + return out # wire ack + + +def handle_send( + raw: bytes, + *, + sender_pub: bytes = b"sender-pub", + system_pub: bytes = b"system-pub", +) -> RouteResult: + """Apply catalog reject rules to one passthrough envelope.""" + try: # JSON required + env = json.loads(raw.decode() or "{}") # object + except json.JSONDecodeError: # bad json + return _fail("SM-BAD-JSON", "parse", "", sender_pub, system_pub, "not json") + if not isinstance(env, dict): # must be object + return _fail("SM-BAD-JSON", "parse", "", sender_pub, system_pub, "not object") + to = str(env.get("to") or "") # dest in the clear + alg = str(env.get("alg") or "") # npe | lab-xor | plain-lab + ct = str(env.get("ct") or "") # ciphertext hex + lid = str(env.get("from_lookup_id") or "") # opaque + if "ct" in env and "body" in env: # never log/accept plaintext body field + return _fail("SM-PLAINTEXT-BODY", "mailbox", lid, sender_pub, system_pub, "body field forbidden") + if not to: # catalog reject: missing to + return _fail("SM-MISSING-TO", "mailbox", lid, sender_pub, system_pub, "missing to") + if alg and alg not in ALLOWED_ALG: # alg not in signed config + return _fail("SM-BAD-ALG", "mailbox", lid, sender_pub, system_pub, "alg not allowed") + if alg != "plain-lab" and not ct: # empty ciphertext when not plain-lab + return _fail("SM-EMPTY-CT", "mailbox", lid, sender_pub, system_pub, "empty ciphertext") + # success: do not keep body; dest stays in the clear + return RouteResult(accepted=True, lookup_id=lid, dest_class="mailbox") + + +def _fail( + code: str, + dest_class: str, + lookup_id: str, + sender_pub: bytes, + system_pub: bytes, + detail: str, +) -> RouteResult: + """Failure path: bundle + dead + summary (no recipient plaintext).""" + bundle = build_bundle( # two ciphertexts + lookup_id=lookup_id or "unknown", + error_code=code, + dest_class=dest_class, + sender_pub=sender_pub, + system_pub=system_pub, + detail=detail, + ) + summary = log_summary(bundle) # codes only + events = [ # order: summary, error, dead + {"subject": "verae.sm.log.summary", "body": summary}, + {"subject": "verae.sm.error", "body": bundle.wire()}, + {"subject": "verae.sm.dead", "body": bundle.wire()}, + ] + return RouteResult( + accepted=False, + lookup_id=lookup_id, + error_code=code, + dest_class=dest_class, + events=events, + bundle=bundle, + ) diff --git a/source/conf.py b/source/conf.py new file mode 100644 index 0000000..2f0067d --- /dev/null +++ b/source/conf.py @@ -0,0 +1,10 @@ +project = "secure-messaging" +copyright = "2026, Verae" +author = "Verae / George Lambert" +extensions = [] +html_theme = "alabaster" +html_static_path = ["_static"] +latex_engine = "pdflatex" +latex_documents = [ + ("index", "secure-messaging.tex", "Secure Messaging", "Verae", "manual"), +] diff --git a/source/index.rst b/source/index.rst new file mode 100644 index 0000000..9350471 --- /dev/null +++ b/source/index.rst @@ -0,0 +1,40 @@ +Secure messaging +================ + +Passthrough NATS envelopes, Ed25519 signed configuration, DataCube +admin-history, and Network Error Bundles. + +This is **not** a HIPAA/SOC 2/ISO certificate. + +* Python spec: ``python/secure_messaging/`` +* Go leaf: ``go/cmd/sm-leaf`` (in-process NATS + optional hub) +* Loopback health: ``127.0.0.1:18783/health`` +* Catalog: https://git.georgelambert.org/marchon/nats-service-endpoints +* Hub: https://git.georgelambert.org/marchon/system-git-sync + +Who calls this module +--------------------- + +``pfc-py-admin`` (sign config, append history) and systemd ``pfc-sm-leaf``. +Tests send targeted good and bad messages on ``verae.sm.send``. + +Messages +-------- + +* **From:** console / tests / connectors +* **To:** mailbox dest in the clear; body ciphertext +* **Success:** ack ``accepted`` + ``lookup_id`` (sender cannot reopen ``ct``) +* **Failure:** ``SM-MISSING-TO``, ``SM-EMPTY-CT``, ``SM-BAD-ALG``, + ``SM-PLAINTEXT-BODY``, ``SM-BAD-JSON`` → ``verae.sm.error`` + + ``verae.sm.dead`` + ``verae.sm.log.summary`` +* **Filter:** no plaintext ``body`` field; summary must not contain ``ct`` +* **Timeout:** 5s NATS; 15s NPE sidecar + +Errors +------ + +Network Error Bundle: ``ct_sender`` (sender-only status) and ``ct_system`` +(ops bounce, no mail body). ``logging.mode=summary``. + +Variables: ``crypto.mode``, ``routing.mode=passthrough``, ``SM_LEAF_HUB``, +``SM_HTTP``. See system-git-sync ``docs/VARIABLES.md``. diff --git a/tests/test_sm.py b/tests/test_sm.py index fbc885e..37e9948 100644 --- a/tests/test_sm.py +++ b/tests/test_sm.py @@ -89,5 +89,43 @@ class HistoryTests(unittest.TestCase): h.append_change(actor="", prev_text="", new_text="x") +class RouterTests(unittest.TestCase): + def test_good_passthrough(self): + from secure_messaging.envelope import seal + from secure_messaging.router import handle_send + + env = seal(to="npe.inbox.abc", sender="alice", body={"note": "hello"}, mode="lab-xor", lab_key=b"lab") + r = handle_send(json.dumps(env.wire()).encode()) + self.assertTrue(r.accepted) + self.assertEqual(r.ack()["lookup_id"], env.from_lookup_id) + self.assertNotIn("ct", r.ack()) + self.assertEqual(r.events, []) + + def test_missing_to_failure_path(self): + from secure_messaging.router import handle_send + from secure_messaging.error_bundle import open_sender, open_system + + r = handle_send(b'{"alg":"lab-xor","ct":"ab","from_lookup_id":"lid-x"}') + self.assertFalse(r.accepted) + self.assertEqual(r.error_code, "SM-MISSING-TO") + subjects = [e["subject"] for e in r.events] + self.assertEqual(subjects, ["verae.sm.log.summary", "verae.sm.error", "verae.sm.dead"]) + summary = r.events[0]["body"] + self.assertNotIn("ct", summary) + self.assertNotIn("detail", summary) + s = open_sender(r.bundle, b"sender-pub") + sysb = open_system(r.bundle, b"system-pub") + self.assertEqual(s["error_code"], "SM-MISSING-TO") + self.assertNotIn("note", sysb) + + def test_empty_ct_and_plaintext_body(self): + from secure_messaging.router import handle_send + + r = handle_send(b'{"to":"npe.inbox.x","alg":"lab-xor","ct":""}') + self.assertEqual(r.error_code, "SM-EMPTY-CT") + r2 = handle_send(b'{"to":"npe.inbox.x","alg":"lab-xor","ct":"ab","body":{"secret":1}}') + self.assertEqual(r2.error_code, "SM-PLAINTEXT-BODY") + + if __name__ == "__main__": unittest.main()