Full Code of alexpovel/latex-cookbook for AI

main 13bd8e4d8782 cached
63 files
508.9 KB
139.9k tokens
18 symbols
1 requests
Download .txt
Showing preview only (532K chars total). Download the full file or copy to clipboard to get everything.
Repository: alexpovel/latex-cookbook
Branch: main
Commit: 13bd8e4d8782
Files: 63
Total size: 508.9 KB

Directory structure:
gitextract_sv1rvnjz/

├── .devcontainer/
│   ├── README.md
│   ├── devcontainer.json
│   └── image/
│       ├── Dockerfile
│       ├── README.md
│       ├── config/
│       │   ├── .wgetrc
│       │   └── texlive.profile
│       └── texlive.sh
├── .gitattributes
├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── .latexmkrc
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── acp.cls
├── bib/
│   ├── README.md
│   ├── bibliography.bib
│   └── glossaries/
│       ├── abbreviations.bib
│       ├── constants.bib
│       ├── index/
│       │   ├── names.bib
│       │   └── terms.bib
│       └── symbols/
│           ├── greek.bib
│           ├── other.bib
│           ├── roman.bib
│           └── subscripts.bib
├── chapters/
│   ├── README.md
│   ├── backmatter.tex
│   ├── frontmatter/
│   │   ├── abstract.tex
│   │   ├── authorship_declaration.tex
│   │   ├── colophon.tex
│   │   ├── preface.tex
│   │   └── task.tex
│   ├── frontmatter.tex
│   ├── mainmatter/
│   │   ├── base-features.tex
│   │   ├── code-listings.tex
│   │   ├── floats.tex
│   │   └── usage.tex
│   └── mainmatter.tex
├── cookbook.tex
├── data/
│   ├── README.md
│   ├── diffuser.csv
│   ├── matlab2tikz_table_example.tex
│   └── matlab2tikz_table_example_data.csv
├── images/
│   ├── bitmaps/
│   │   └── README.md
│   └── vectors/
│       └── README.md
├── lib/
│   ├── README.md
│   └── example.lua
├── pandoc/
│   ├── README.md
│   ├── defaults.yaml
│   ├── metadata.yaml
│   └── promote-headers.lua
└── tests/
    ├── Makefile
    ├── README.md
    ├── config.yml
    ├── pyproject.toml
    └── tests/
        ├── __init__.py
        ├── conftest.py
        ├── test_pdfs.py
        ├── test_self.py
        └── utils.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .devcontainer/README.md
================================================
# Remote: Containers for VSCode

This directory contains all files required to enable [working *inside* of containers](https://code.visualstudio.com/docs/remote/containers) in VSCode.
The entire workspace/IDE will work from *within* the context of a container of an image of your choice.


================================================
FILE: .devcontainer/devcontainer.json
================================================
{
    "name": "LaTeX",
    // Instead of *building* the accompanying Dockerfile and its whole context, like:
    //
    // "build": {
    //     "context": "..",
    //     "dockerfile": "image/Dockerfile"
    // },
    //
    // simply download the prepared image the author has already uploaded, based on
    // what's found inside the `image/` directory.
    // Advantages:
    // - build process is slow (downloads from TeX servers), each user doing it every
    //   time is too much. It can take *hours* in worst-cases
    // - build might fail for various reasons
    // It is much easier to download the ready-made image.
    // Disadvantages:
    // - cannot easily iterate on the Docker image, need to go through Docker Hub.
    //   Recourse: simply change the below to use the *local image temporarily*
    // - Upstream image on Docker Hub might not be the latest
    "image": "alexpovel/latex",
    "customizations": {
        "vscode": {
            // Set *default* container specific settings.json values on container create.
            "settings": {
                "terminal.integrated.defaultProfile.linux": "bash"
            },
            // Add the IDs of extensions you want installed when the container is created.
            // Browse for extensions here: https://marketplace.visualstudio.com/
            // then look for 'Unique Identifier' on the extension's page.
            "extensions": [
                "James-Yu.latex-workshop",
                "streetsidesoftware.code-spell-checker",
                "streetsidesoftware.code-spell-checker-german"
            ]
        }
    },
    "containerEnv": {
        // Inside the container, act as though we're in CI. Important for the Makefile.
        "CI": "true",
        // The base image has this locale:
        //     $ docker run --rm --entrypoint="locale" alexpovel/latex
        //     LANG=
        //     LANGUAGE=
        //     LC_CTYPE="POSIX"
        //     LC_NUMERIC="POSIX"
        //     LC_TIME="POSIX"
        //     LC_COLLATE="POSIX"
        //     LC_MONETARY="POSIX"
        //     LC_MESSAGES="POSIX"
        //     LC_PAPER="POSIX"
        //     LC_NAME="POSIX"
        //     LC_ADDRESS="POSIX"
        //     LC_TELEPHONE="POSIX"
        //     LC_MEASUREMENT="POSIX"
        //     LC_IDENTIFICATION="POSIX"
        //     LC_ALL=
        // *However*, starting this very same container in VSCode's Remote Containers,
        // the locale changes to:
        //     $ locale
        //     locale: Cannot set LC_CTYPE to default locale: No such file or directory
        //     locale: Cannot set LC_MESSAGES to default locale: No such file or directory
        //     locale: Cannot set LC_ALL to default locale: No such file or directory
        //     LANG=en_US.UTF-8
        //     LANGUAGE=
        //     LC_CTYPE="en_US.UTF-8"
        //     LC_NUMERIC="en_US.UTF-8"
        //     LC_TIME="en_US.UTF-8"
        //     LC_COLLATE="en_US.UTF-8"
        //     LC_MONETARY="en_US.UTF-8"
        //     LC_MESSAGES="en_US.UTF-8"
        //     LC_PAPER="en_US.UTF-8"
        //     LC_NAME="en_US.UTF-8"
        //     LC_ADDRESS="en_US.UTF-8"
        //     LC_TELEPHONE="en_US.UTF-8"
        //     LC_MEASUREMENT="en_US.UTF-8"
        //     LC_IDENTIFICATION="en_US.UTF-8"
        //     LC_ALL=
        // There's three errors because the container doesn't seem to have the correct
        // locale files:
        //     $ locale -a
        //     locale: Cannot set LC_CTYPE to default locale: No such file or directory
        //     locale: Cannot set LC_MESSAGES to default locale: No such file or directory
        //     locale: Cannot set LC_COLLATE to default locale: No such file or directory
        //     C
        //     C.UTF-8
        //     POSIX
        // This leads to `lualatex` erroring out, see also https://tex.stackexchange.com/q/374303/120853
        // Using "POSIX" is possible and brings us back to vanilla container locale:
        "LC_ALL": "POSIX"
    }
}


================================================
FILE: .devcontainer/image/Dockerfile
================================================
# ARGs before the first FROM are global and usable in all stages

ARG BASE_OS="debian"

# Tag of the base OS image
ARG OS_VERSION="testing"

# TeXLive version. This will be used by the `texlive.sh` script to determine what to
# download and install. `latest` will fetch the latest version available on their servers.
# Alternatively, you can specify *a past year* and it will download that version
# from the TeXLive archives and use it (can take a long time).
# For available years, see ftp://tug.org/historic/systems/texlive/ .
ARG TL_VERSION="latest"

ARG _BUILD_CONTEXT_PREFIX=".devcontainer/image/"

# Image with layers as used by all succeeding steps
FROM ${BASE_OS}:${OS_VERSION} as base

# Use `apt-get` over just `apt`, see https://askubuntu.com/a/990838/978477.
# Also run `apt-get update` on every `RUN`, see:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt-get update && \
    apt-get install --yes --no-install-recommends \
    # wget for `install-tl` script to download TeXLive, and other downloads.
    wget \
    # In a similar vein, `curl` is required by various tools, or is just very
    # nice to have for various scripting tasks.
    curl \
    # wget/install-tl requires capability to check certificate validity.
    # Without this, executing `install-tl` fails with:
    #
    # install-tl: TLPDB::from_file could not initialize from: https://<mirror>/pub/ctan/systems/texlive/tlnet/tlpkg/texlive.tlpdb
    # install-tl: Maybe the repository setting should be changed.
    # install-tl: More info: https://tug.org/texlive/acquire.html
    #
    # Using `install-tl -v`, found out that mirrors use HTTPS, for which the
    # underlying `wget` (as used by `install-tl`) returns:
    #
    # ERROR: The certificate of '<mirror>' is not trusted.
    # ERROR: The certificate of '<mirror>' doesn't have a known issuer.
    #
    # This is resolved by installing:
    ca-certificates \
    # Update Perl, otherwise: "Can't locate Pod/Usage.pm in @INC" in install-tl
    # script; Perl is already installed, but do not use `upgrade`, see
    # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
    perl \
    # Install `latexindent` Perl dependencies.
    # Found these using this method: https://unix.stackexchange.com/a/506964/374985
    # List of `latexindent` dependencies is here:
    # https://latexindentpl.readthedocs.io/en/latest/appendices.html#linux,
    # see also the helper script at
    # https://github.com/cmhughes/latexindent.pl/blob/master/helper-scripts/latexindent-module-installer.pl
    #
    # Installing via Debian system packages because installing the modules via
    # `cpanm` requires `gcc` and I wanted to avoid installing that (~200MB).
    #
    # YAML::Tiny:
    libyaml-tiny-perl \
    # File::HomeDir:
    libfile-homedir-perl \
    # Unicode:GCString:
    libunicode-linebreak-perl \
    # Log::Log4perl:
    liblog-log4perl-perl \
    # Log::Dispatch:
    liblog-dispatch-perl \
    # Usually, `latexmk` is THE tool to use to automate, in a `make`-like style,
    # LaTeX (PDF) file generation. However, if that is not enough, the following
    # will fill the gaps and cover all other use cases:
    make \
    # Get `envsubst` to replace environment variables in files with their actual
    # values.
    gettext-base \
    # Using the LaTeX package `minted` for syntax highlighting of source code
    # snippets. It's much more powerful than the alternative `listings` (which is
    # pure TeX: no outside dependencies but limited functionality) but requires
    # Python's `pygments` package:
    python3 \
    python3-pygments \
    # Required to embed git metadata into PDF from within Docker container:
    git \
    # Required to use pdfunite for merging PDF files. Ghostscript is causing
    # trouble with Mozilla Firefox's PDF Reader.
    poppler-utils

# The `minted` LaTeX package provides syntax highlighting using the Python `pygmentize`
# package. That package also installs a callable script, which `minted` uses, see
# https://tex.stackexchange.com/a/281152/120853.
# Therefore, `minted` primarily works by invoking `pygmentize` (or whatever it was
# overridden by using `\MintedPygmentize`). However, it requires `python` for other
# jobs, e.g. to remove leading whitespace for the `autogobble` function, see the
# "\minted@autogobble Remove common leading whitespace." line in the docs.
# It is invoked with `python -c`, but Debian only has `python3`. Therefore, alias
# `python` to invoke `python3`. Use `update-alternatives` because it's cooler than
# symbolic linking, and made for this purpose.
# If `python` is not available but `pygmentize` is, stuff like `autogobble` and
# `\inputminted`won't work but syntax highlighting will.
# See also https://stackoverflow.com/a/55351449/11477374
# Last argument is `priority`, whose value shouldn't matter since there's nothing else.
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1


FROM base as downloads

# Cannot share ARGs over multiple stages, see also:
# https://github.com/moby/moby/issues/37345.
# Therefore, work in root (no so `WORKDIR`), so in later stages, the location of
# files copied from this stage does not have to be guessed/WET.

# Using an ARG with 'TEX' in the name, TeXLive will warn:
#
#  ----------------------------------------------------------------------
#  The following environment variables contain the string "tex"
#  (case-independent).  If you're doing anything but adding personal
#  directories to the system paths, they may well cause trouble somewhere
#  while running TeX. If you encounter problems, try unsetting them.
#  Please ignore spurious matches unrelated to TeX.

#     TEXPROFILE_FILE=texlive.profile
#  ----------------------------------------------------------------------
#
# This also happens when the *value* contains 'TEX'.
# `ARG`s are only set during Docker image build-time, so this warning should be void.

# Renew (https://stackoverflow.com/a/53682110):
ARG TL_VERSION
ARG _BUILD_CONTEXT_PREFIX

ARG TL_INSTALL_ARCHIVE="install-tl-unx.tar.gz"
ARG EISVOGEL_ARCHIVE="Eisvogel.tar.gz"
ARG INSTALL_TL_DIR="install-tl"

COPY ./${_BUILD_CONTEXT_PREFIX}/texlive.sh .

RUN \
    # Get appropriate installer for the TeXLive version to be installed:
    ./texlive.sh get_installer ${TL_VERSION} && \
    # Get Eisvogel LaTeX template for pandoc,
    # see also #175 in that repo.
    wget https://github.com/Wandmalfarbe/pandoc-latex-template/releases/latest/download/${EISVOGEL_ARCHIVE}

RUN \
    mkdir ${INSTALL_TL_DIR} && \
    # Save archive to predictable directory, in case its name ever changes; see
    # https://unix.stackexchange.com/a/11019/374985.
    # The archive comes with a name in the form of 'install-tl-YYYYMMDD' from the source,
    # which is of course unpredictable.
    tar --extract --file=${TL_INSTALL_ARCHIVE} --directory=${INSTALL_TL_DIR} --strip-components 1 && \
    \
    # Prepare Eisvogel pandoc template (yields `eisvogel.latex` among other things):
    tar --extract --file=${EISVOGEL_ARCHIVE}


FROM base as main

# Renew (https://stackoverflow.com/a/53682110):
ARG TL_VERSION
ARG _BUILD_CONTEXT_PREFIX

ARG TL_PROFILE="texlive.profile"
# Auxiliary, intermediate file:
ARG TMP_TL_PROFILE="${TL_PROFILE}.tmp"

# Layer with graphical and auxiliary tools
# Put as early as possible in Dockerfile since this should rarely change (cache-friendly)
RUN apt-get update && \
    apt-get install --yes --no-install-recommends \
    # cannot use `default-jre-headless` version (25% of normal size), see
    # https://github.com/alexpovel/latex-cookbook/issues/17
    default-jre \
    # No headless inkscape available currently:
    inkscape \
    # nox (no X Window System): CLI version, 10% of normal size:
    gnuplot-nox \
    # For various conversion tasks, e.g. EPS -> PDF (for legacy support):
    ghostscript

# Pandoc layer; not required for LaTeX compilation, but useful for document conversions
# Put as early as possible in Dockerfile since this should rarely change (cache-friendly)
RUN apt-get update && \
    apt-get install --yes --no-install-recommends \
    # librsvg2 for 'rsvg-convert' used by pandoc to convert SVGs when embedding
    # into PDF
    librsvg2-bin \
    pandoc

# User to install and run LaTeX as.
# This is a security and convenience measure: by default, containers run as root.
# To work and compile PDFs using this container, you will need to map volumes into it
# from your host machine. Those bind-mounts will then be accessed as root from this
# container, and any generated files will also be owned by root. This is inconvenient at
# best and dangerous at worst.
# The generated user here will have IDs of 1000:1000. If your local user also has those
# (the case for single-user Debians etc.), your local user will already have correct
# ownership of all files generated by the user we create here.
ARG USER="tex"
RUN useradd --create-home ${USER}

# Label according to http://label-schema.org/rc1/ to have some metadata in the image.
# This is important e.g. to know *when* an image was built. Depending on that, it can
# contain different software versions (even if the base image is specified as a fixed
# version).
LABEL \
    maintainer="Alex Povel <alex.povel@tuhh.de>" \
    org.label-schema.description="TeXLive with most packages, JavaRE, Inkscape, pandoc and more" \
    org.label-schema.vcs-url="https://github.com/alexpovel/latex-cookbook" \
    org.label-schema.schema-version="1.0"

ARG INSTALL_DIR="/install"
WORKDIR ${INSTALL_DIR}

# Copy custom file containing TeXLive installation instructions
COPY ${_BUILD_CONTEXT_PREFIX}/config/${TL_PROFILE} ${TMP_TL_PROFILE}
COPY --from=downloads /install-tl/ /texlive.sh ./

# Move to where pandoc looks for templates, see https://pandoc.org/MANUAL.html#option--data-dir
COPY --from=downloads /eisvogel.latex /home/${USER}/.pandoc/templates/

# Global wget config file, see the comments in that file for more info and the rationale.
# Location of that file depends on system, e.g.: https://askubuntu.com/a/368050
COPY ${_BUILD_CONTEXT_PREFIX}/config/.wgetrc /etc/wgetrc

# "In-place" `envsubst` run is a bit more involved, see also:
# https://stackoverflow.com/q/35078753/11477374.
# Do not use `mktemp`, will break Docker caching since it's a new file each time.
RUN cat "$TMP_TL_PROFILE" | envsubst | tee "$TL_PROFILE" && \
    rm "$TMP_TL_PROFILE"

# (Large) LaTeX layer
RUN ./texlive.sh install "$TL_VERSION"

# Remove no longer needed installation workdir.
# Cannot run this earlier because it would be recreated for any succeeding `RUN`
# instructions.
# Therefore, change `WORKDIR` first, then delete the old one.
WORKDIR /${USER}

USER ${USER}

# Load font cache, has to be done on each compilation otherwise
# ("luaotfload | db : Font names database not found, generating new one.").
# If not found, e.g. TeXLive 2012 and earlier, simply skip it. Will return exit code
# 0 and allow the build to continue.
# Warning: This is USER-specific. If the current `USER` for which we run this is not
# the container user, the font will be regenerated for that new user.
RUN luaotfload-tool --update || echo "luaotfload-tool did not succeed, skipping."

# Make our class file available for the entire latex/TeXLive installation, see also
# https://tex.stackexchange.com/a/1138/120853
COPY acp.cls /home/${USER}/texmf/tex/latex/

USER root
# Give back control to own user files; might be root-owned from previous copying processes
RUN chown --recursive ${USER}:${USER} /home/${USER}/
USER ${USER}

# The default parameters to the entrypoint; overridden if any arguments are given to
# `docker run`.
# `lualatex` usage for `latexmk` implies PDF generation, otherwise DVI is generated.
CMD [ "--lualatex" ]

# Allow container to run as an executable; override with `--entrypoint`.
# Allows to simply `run` the image without specifying any executable.
# If `latexmk` is called without a file argument, it will run on all *.tex files found.
ENTRYPOINT [ "latexmk" ]


================================================
FILE: .devcontainer/image/README.md
================================================
# Docker image with custom, almost-full TeXLive distribution & various tools

[![Docker Pulls](https://img.shields.io/docker/pulls/alexpovel/latex)](https://hub.docker.com/r/alexpovel/latex)

Serves a lot of needs surrounding LaTeX file generation and handling.
For the rationale behind the installed Debian packages, see [below](#custom-tools).
To see how to build the image, also see [below](#building).

## Quick Intro

If you use [VSCode Remote Containers](https://code.visualstudio.com/docs/remote/containers), the below does not apply.
There is no need to run manual `docker` invocations on the host.

---

[Install Docker](https://docs.docker.com/get-docker/), navigate to your project directory, then run the image as follows:

- Bash:

  ```bash
  docker run --rm --volume $(pwd):/tex alexpovel/latex
  ```

- PowerShell:

  ```powershell
  docker run --rm --volume ${PWD}:/tex alexpovel/latex
  ```

The parts making up the command are:

- The last line is the location on [DockerHub](https://hub.docker.com/repository/docker/alexpovel/latex).
  Without specifying a [*tag*](https://hub.docker.com/repository/docker/alexpovel/latex/tags?page=1), the default `latest` is implied.
  See [below](#historic-builds) for more options.
- The `--rm` option removes the container after a successful run.
  This is generally desired since containers are not supposed to be stateful: once their process terminates, the container terminates, and it can be considered junk.
- Providing a `--volume`, in this case the current working directory aka pwd, is required for the container to find files to work on.
  It has to be *mounted* to a location *inside* the container.
  This has to be whatever the last `WORKDIR` instruction in the [Dockerfile](Dockerfile) is, e.g. `/tex`.

  Otherwise, you can always override the `WORKDIR` using the `--workdir` option.
  This is the directory in which the Docker container's process works in and expects to find files.
- Note that there is no command given, e.g. there is nothing *after* `alexpovel/latex`.
  In this form, the container runs as an executable (just as if you ran `lualatex` or similar commands), where the program to be executed is determined by the `ENTRYPOINT` instruction in the [Dockerfile](Dockerfile).

  For example, if the `ENTRYPOINT` is set to `latexmk`, running the above command will execute `latexmk` in the container's context, without you having to specify it.

  (`latexmk` is a recipe-like tool that automates LaTeX document compilation by running `lualatex`, `biber` and whatever else required for compilation as many times as needed for proper PDF output (so references like `??` in the PDF are resolved).
  It does this by detecting that auxiliary files no longer change (steady-state).
  The tool is best configured using its config file, `.latexmkrc`.)

  Any options to the `ENTRYPOINT` executable are given at the end of the command, e.g.:

  ```bash
  docker run --rm --volume $(pwd)/tests:/tex alexpovel/latex -c
  ```

  to run, if `latexmk` is the `ENTRYPOINT`, the equivalent of `latexmk -c` ([cleaning auxiliary files](https://mg.readthedocs.io/latexmk.html#cleaning-up)).

  To **overwrite** the `ENTRYPOINT`, e.g. because you want to run only `lualatex`, use the `--entrypoint` option, e.g. `--entrypoint="lualatex"`.
  Similarly, you can work inside of the container directly, e.g. for debugging, using `--entrypoint="bash"`.

### Image

For the above to work, the `alexpovel/latex` image needs to be available on whatever your default image registry is (usually [DockerHub](https://hub.docker.com/)).
If it's not available for pulling (i.e., downloading) from there, you can build this image locally, see [below](#building).

## Approach

This Dockerfile is based on a custom TeXLive installer using their [`install-tl` tool](https://www.tug.org/texlive/doc/install-tl.html), instead of [Debian's `texlive-full`](https://packages.debian.org/search?searchon=names&keywords=texlive-full).
Other, smaller `texlive-` collections would be [available](https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=texlive), but TeXLive cannot install missing packages on-the-fly, [unlike MiKTeX](https://miktex.org/howto/miktex-console/).
Therefore, images should come with all desirable packages in place; installing them after the fact in running containers using [`tlmgr`](https://www.tug.org/texlive/tlmgr.html) is the wrong approach (containers are only meant to be run; if they are incomplete, modify the *image*, ordinarily by modifying the `Dockerfile`).

This approach has the following advantages:

- Using ["vanilla" TeXLive](https://www.tug.org/texlive/debian.html) affords us the latest packages directly from the source, while the official   Debian package might lag behind a bit.
  This is often not relevant, but has bitten me several times while working with the latest packages.
- The installation can be adjusted better.
  For example, *multiple GBs* of storage/image size are saved by omitting unneeded PDF documentation files.
- We can install arbitrary TeXLive versions, as long as they are the [current](https://tug.org/texlive/acquire-netinstall.html) or an archived (<ftp://tug.org/historic/systems/texlive/>) version.
  Otherwise, to obtain [older or even obsolete TeXLive installations](#historic-builds), one would have to also obtain a corresponding Debian version.
  This way, we can choose a somewhat recent Debian version and simply install an old TeXLive into it.

  Eligible archive versions are those year directories (`2019`, `2020`, ...) present at the above FTP link that have a `tlnet-final` subdirectory.
  This is (speculating here) a frozen, aka final, version, put online the day the *next* major release goes live.
  For example, version `2021` released on 2021-04-01 and `2020` received its `tlnet-final` subdirectory that same day.

The `install-tl` tool is configured via a [*Profile* file](config/texlive.profile), see also the [documentation](https://www.tug.org/texlive/doc/install-tl.html#PROFILES).
This enables unattended, pre-configured installs, as required for a Docker installation.

---

The (official?) [`texlive/texlive` image](https://hub.docker.com/r/texlive/texlive) follows [the same approach](https://hub.docker.com/layers/texlive/texlive/latest/images/sha256-70fdbc1d9596c8eeb4a80c71a8eb3a5aeb63bed784112cbdb87f740e28de7a80?context=explore).
However, there are a bunch of things this Dockerfile does differently that warrant not building `FROM` that image:

- a user-editable, thus more easily configurable [profile](config/texlive.profile).
  This is mainly concerning the picked package *collections*.
  Unchecking (putting a `0`) unused ones saves around 500MB at the time of writing.
- more elaborate support for [historic versions](#historic-builds)
- an installation procedure incorporating a proper `USER`

Things they do that do not happen here:

- verify download integrity using `gpg`

### Historic Builds

LaTeX is a slow world, and many documents/templates in circulation still rely on outdated practices or packages.
This can be a huge hassle.
Maintaining an old LaTeX distribution next to a current one on the same host is not fun.
This is complicated by the fact that (La)TeX seems to do things differently than pretty much everything else.
For this, Docker is the perfect tool.

This image can be built (`docker build`) with different build `ARG`s, and the build process will figure out the proper way to handle installation.
There is a [script](texlive.sh) to handle getting and installing TeXLive from the proper location ([current](https://www.tug.org/texlive/acquire-netinstall.html) or [archive](ftp://tug.org/historic/systems/texlive/)).
Refer to the [Dockerfile](Dockerfile) for the available `ARG`s (all `ARG` have a default).
These are handed to the build process via the [`--build-arg` option](https://docs.docker.com/engine/reference/commandline/build/#options).

Note that for a *specific* TeXLive version to be picked, it needs to be present in their [archives](ftp://tug.org/historic/systems/texlive/).
The *current* TeXLive is not present there (it's not historic), but is available under the `latest` Docker tag.
As such, if for example `2020` is the *current* TeXLive, and the image is to be based on Debian 10, there is *no* `debian-10-texlive-2020` tag.
You would obtain this using the `latest` tag.
As soon as TeXLive 2020 is superseded and consequently moved to the archives, the former tag can become available.

To build an array of different versions automatically, DockerHub provides [advanced options](https://docs.docker.com/docker-hub/builds/advanced/) in the form of hooks, e.g. a [build hook](hooks/build).
These are bash scripts that override the default DockerHub build process.
At build time, DockerHub provides [environment variables](https://docs.docker.com/docker-hub/builds/advanced/#environment-variables-for-building-and-testing) which can be used in the build hook to forward these into the Dockerfile build process.
As such, by just specifying the image *tags* on DockerHub, we can build corresponding images automatically (see also [here](https://web.archive.org/web/20201005132636/https://dev.to/samuelea/automate-your-builds-on-docker-hub-by-writing-a-build-hook-script-13fp)).
For more info on this, see [below](#on-dockerhub).

The approximate [matching of Debian to TeXLive versions](https://www.tug.org/texlive/debian.html) is (see also [here](https://www.debian.org/releases/) and [here](https://www.debian.org/distrib/archive).):

| Debian Codename | Debian Version | TeXLive Version |
| --------------- | :------------: | :-------------: |
| bullseye        |       11       |      2020       |
| buster          |       10       |      2018       |
| stretch         |       9        |      2016       |
| jessie          |       8        |      2014       |
| wheezy          |       7        |      2012       |
| squeeze         |      6.0       |      2009       |
| lenny           |      5.0       |     unknown     |
| etch            |      4.0       |     unknown     |
| sarge           |      3.1       |     unknown     |
| woody           |      3.0       |     unknown     |
| potato          |      2.2       |     unknown     |
| slink           |      2.1       |     unknown     |
| hamm            |      2.0       |     unknown     |

This is only how the official Debian package is shipped.
These versions can be, to a narrow extend, freely mixed.
Using `install-tl`, older versions of TeXLive can be installed on modern Debian versions.

#### Issues

Using [*obsolete* Debian releases](https://www.debian.org/releases/) comes with a long list of headaches.
As such, Debian versions do not reach too far back.
It does not seem worth the effort.
Instead, it seems much easier to install older TeXLive versions onto reasonably recent Debians.

Issues I ran into are:

- `apt-get update` will fail if the original Debian repository is dead (Debian 6/TeXLive 2014):

  ```plaintext
  W: Failed to fetch http://httpredir.debian.org/debian/dists/squeeze/main/binary-amd64/Packages.gz  404  Not Found
  W: Failed to fetch http://httpredir.debian.org/debian/dists/squeeze-updates/main/binary-amd64/Packages.gz  404  Not Found
  W: Failed to fetch http://httpredir.debian.org/debian/dists/squeeze-lts/main/binary-amd64/Packages.gz  404  Not Found
  E: Some index files failed to download, they have been ignored, or old ones used instead.
  ```

  As such, there needs to be a [dynamic way to update `/etc/apt/sources.list`](https://github.com/alexpovel/latex-extras-docker/blob/fa9452c236079a65563daff22767b2b637dd80c6/adjust_sources_list.sh) if the Debian version to be used in an archived one, see also [here](https://web.archive.org/web/20201007095943/https://www.prado.lt/using-old-debian-versions-in-your-sources-list).
- `RUN wget` (or `curl` etc.) via `HTTPS` will fail for older releases, e.g. GitHub rejected the connection due to the outdated TLS version of the old release (Debian 6/TeXLive 2015):

  ```text
  Connecting to github.com|140.82.121.4|:443... connected.
  OpenSSL: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
  ```

- Downloading older releases requires using the [Debian archives](http://archive.debian.org/debian/).
  This works fine, however a warning is issued (Debian 6/TeXLive 2014):

  ```plaintext
  W: GPG error: http://archive.debian.org squeeze Release: The following signatures were invalid: KEYEXPIRED 1520281423 KEYEXPIRED 1501892461
  ```

  Probably related to this, the installation then fails:

  ```plaintext
  WARNING: The following packages cannot be authenticated!
    libgdbm3 libssl0.9.8 wget libdb4.7 perl-modules perl openssl ca-certificates
  E: There are problems and -y was used without --force-yes
  ```

  According to `man apt-get`, `--force-yes` is both deprecated and absolutely not recommended.
  The correct course here is to `--allow-unauthenticated`, however this would also affect the build process for modern versions, where authentication *did not* fail.
  The official Debian archives are probably trustworthy, but this is still an issue.
- A more obscure issue is (Debian 7/TeXLive 2011):

  ```plaintext
  The following packages have unmet dependencies:
    perl : Depends: perl-base (= 5.14.2-21+deb7u3) but 5.14.2-21+deb7u6 is to be installed
  E: Unable to correct problems, you have held broken packages.
  ```

  While the error message itself is crystal-clear, debugging this is probably a nightmare.
- Tools like `pandoc`, which was released in [2006](https://pandoc.org/releases.html), limit the earliest possible Debian version as long as the tool's installation is part of the Dockerfile.
  In this example, 2006 should in any case be early enough (if not, update your LaTeX file to work with more recent versions, that is probably decidedly less work).

## Custom Tools

The auxiliary tools are (for the actual, up-to-date list, see the [Dockerfile](Dockerfile)):

- A *Java Runtime Environment* for [`bib2gls`](https://ctan.org/pkg/bib2gls) from the [`glossaries-extra` package](https://www.ctan.org/pkg/glossaries-extra).

  `bib2gls` takes in `*.bib` files with glossary, symbol, index and other definitions and applies sorting, filtering etc.
  For this, it requires Java.
- [`inkscape`](https://inkscape.org/) because the [`svg`](https://ctan.org/pkg/svg) package needs it.
  We only require the CLI, however there is no "no-GUI" version available.
  Headless Inkscape is [currently in the making](https://web.archive.org/web/20201007100140/https://wiki.inkscape.org/wiki/index.php/Future_Architecture).

  Using that package, required PDFs and PDF_TEXs are only generated at build-time (on the server or locally) and treated as a cache.
  As such, they can be discarded freely and are regenerated in the next compilation run, using `svg`, which calls `inkscape`.
  Therefore, the `svg` package gets rid of all the PDF/PDF_TEX intermediate junk and lets us deal with the true source -- `*.svg` files -- directly.
  These files are really [XML](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics), ergo text-based, ergo suitable for VCS like `git` (as opposed to binary PDFs).

  Being an external tool, `svg`/`inkscape` also requires the `--shell-escape` option to `lualatex` etc. for writing outside files.
- [`gnuplot`](http://www.gnuplot.info/) for `contour gnuplot` commands for `addplot3` in `pgfplots`.
  So essentially, an external add-on for the magnificent `pgfplots` package.
  For `gnuplot` to write computed results to a file for `pgfplots` to read, `--shell-escape` is also required.
- [`pandoc`](https://pandoc.org/) as a very flexible, convenient markup conversion tool.
  For example, it can convert Markdown (like this very [README](README.md)) to PDF via LaTeX:

  ```bash
  pandoc README.md --output=README.pdf  # pandoc infers what to do from suffixes
  ```

  The default output is usable, but not very pretty.
  This is where *templates* come into play.
  A very tidy and well-made such template is [*Eisvogel*](https://github.com/Wandmalfarbe/pandoc-latex-template).
  Its installation is not via a (Debian) package, so it has to be downloaded specifically.
  For this, additional requirements are:

  - `wget` to download the archive,
  - `librsvg2-bin` for the `rsvg-convert` tool.
    This is used by `pandoc` to convert SVGs when embedding them into the new PDF.

  Note that `pandoc` and its *Eisvogel* template can draw [metadata from a YAML header](https://pandoc.org/MANUAL.html#metadata-variables), for example:

  ```yaml
  ---
  title: "Title"
  author: [Author]
  date: "YYYY-MM-DD"
  subject: "Subject"
  keywords: [Keyword1, Keyword2]
  lang: "en"
  ...
  ```

  among other metadata variables.
  *Eisvogel* uses it to fill the document with info, *e.g.* the PDF header and footer.

  `pandoc` is not required for LaTeX work, but is convenient to have at the ready for various conversion jobs.

## Building

The proper way to access these images is via DockerHub.

### On DockerHub ([Requires Pro Plan](https://docs.docker.com/docker-hub/builds/))

This repository and its [Dockerfile](Dockerfile) used to be built into the corresponding image continuously and made available on [DockerHub](https://hub.docker.com/repository/docker/alexpovel/latex).
This process now requires a Pro plan and was therefore retired.

For the currently available tags, see [here](https://hub.docker.com/repository/docker/alexpovel/latex/tags?page=1).

### Locally

The Dockerfile is now built locally and pushed manually.
Refer to the Dockerfile for all the available configuration environment variables (`ARG`s).

The build can take a very long time (if you have all collections selected in the [profile](config/texlive.profile)), especially when downloading from the TeXLive/TUG archives.
For developing/debugging, it is advisable to download the archive files once.
E.g. for TexLive 2014, you would want this directory: <ftp://tug.org/historic/systems/texlive/2014/tlnet-final/>.
Download in one go using:

```bash
wget --recursive --no-clobber ftp://tug.org/historic/systems/texlive/2014/tlnet-final
```

The `--no-clobber` option allows you to restart the download at will.
Then, work with the `--repository=/some/local/path` option of `install-tl`, after [copying the archive directory into the image at build time](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#understand-build-context) (see also [here](https://tex.stackexchange.com/a/374651/120853)).
Having a local copy circumvents [unstable connections](https://tex.stackexchange.com/q/370686/120853) and minimizes unnecessary load onto TUG servers.


================================================
FILE: .devcontainer/image/config/.wgetrc
================================================
# wget config file

# TeXLive uses wget. Make wget as robust as possible here.
# Make downloading as robust as possible since TeXLive/TUG servers can be unreliable.
# If we leave downloading to the install script, we cannot influence the parameters
# and it might fail without retrying and for unfortunate reasons at that (like
# failing the entire install an hour in because of one package that failed to
# download). All of this is exacerbated using Docker, since we are building remotely
# on their infrastructure, which is inaccessible. A failure after 8h of queue and
# 2h of build time due to unstable downloads is annoying.
# See also:
# https://www.gnu.org/software/wget/manual/wget.html#Startup-File
# https://superuser.com/a/689340/1144470
# https://www.gnu.org/software/wget/manual/html_node/Sample-Wgetrc.html

retry_connrefused = on
wait_retry = 120
read_timeout = 20
timeout = 15
tries = 5

# Setting the following option to `on` can give:
# install-tl: open tlpdb(ftp://tug.org/historic/systems/texlive/2016/tlnet-final/tlpkg/texlive.tlpdb) failed: Inappropriate ioctl for device at tlpkg/TeXLive/TLPDB.pm line 359.
# no-clobber = off


================================================
FILE: .devcontainer/image/config/texlive.profile
================================================
# -------------------------------------------------------------------------------
# TeX Live profile to configure the installation procedure, enabling headless/
# unattended install.
# For more info, see: https://www.tug.org/texlive/doc/install-tl.html#PROFILES
# -------------------------------------------------------------------------------
# File has to have LF line endings to work with `install-tl` Perl script!
# -------------------------------------------------------------------------------

# We do a manual-ish install, do not use premade scheme:
selected_scheme scheme-custom

# -------------------------------------------------------------------------------
# The below directories are the installation destinations.
# An alternative to using the setting here is to set environment variables like
# `TEXLIVE_INSTALL_TEXMFHOME` directly (e.g. in the Dockerfile), but as of late,
# `install-tl` claims to ignore environment variables when installing from a profile
# file ("Environment variables are ignored"):
# https://web.archive.org/web/20201122233159/https://www.tug.org/texlive/doc/install-tl.html#OPTIONS
# So with this profile file guaranteed to work and parallel environment variables
# *maybe* breaking in the future, use this profile file for everything.
# Replace the below environment variables with appropriate values (this is automated
# in the Dockerfile using `envsubst`).
# -------------------------------------------------------------------------------

# See: https://www.tug.org/texlive/doc/install-tl.html#ENVIRONMENT-VARIABLES,
# https://tex.stackexchange.com/a/470341/120853.
# IMPORTANT: Put these into the actual designated container's user's home for full
# write access. Otherwise, we run into all sorts of annoying errors, like
# https://tex.stackexchange.com/q/571021/120853.
# The user we run this as is specified in the Dockerfile and inserted into here.
TEXMFHOME /home/${USER}/texmf
TEXMFVAR /home/${USER}/.texlive/texmf-var
TEXMFCONFIG /home/${USER}/.texlive/texmf-config

# Not required, left at default:
# TEXDIR /usr/local/texlive/<version>
# TEXMFSYSCONFIG /usr/local/texlive/<version>/texmf-config
# TEXMFSYSVAR /usr/local/texlive/<version>/texmf-var
# TEXMFLOCAL /usr/local/texlive/texmf-local
#
# -------------------------------------------------------------------------------
# Collections of packages; for their contents, see
# http://mirror.ctan.org/systems/texlive/tlnet/tlpkg/texlive.tlpdb
# and search for 'name collection-<name>', e.g. 'name collection-basic'.
# At the time of writing, the following encompasses all available collections.
# Only the core ones with very few supported languages are enabled. For example,
# just including 'collection-langjapanese' requires 800MB of space.
# -------------------------------------------------------------------------------
collection-basic 1
collection-bibtexextra 1
collection-binextra 1
collection-fontsextra 1
collection-fontsrecommended 1
collection-fontutils 1
collection-formatsextra 1
collection-langenglish 1
collection-langeuropean 1
collection-langgerman 1
collection-latex 1
collection-latexextra 1
collection-latexrecommended 1
collection-luatex 1
collection-mathscience 1
collection-pictures 1
collection-plaingeneric 1
collection-publishers 1
collection-xetex 1
# -------------------------------------------------------------------------------
# Enable the following disabled ones as needed. They are included here so
# everyone can see what is available; as many as possible are disabled, since
# image size matters. The default is aimed at documents in the sciences domain.
# Therefore, everything else is disabled. This includes various languages, so
# activate your missing language here!
# -------------------------------------------------------------------------------
collection-context 0
collection-games 0
collection-humanities 0
collection-langarabic 0
collection-langchinese 0
collection-langcjk 0
collection-langcyrillic 0
collection-langczechslovak 0
collection-langfrench 0
collection-langgreek 0
collection-langitalian 0
collection-langjapanese 0
collection-langkorean 0
collection-langother 0
collection-langpolish 0
collection-langportuguese 0
collection-langspanish 0
collection-metapost 0
collection-music 0
collection-pstricks 0
collection-texworks 0
collection-wintools 0
# -------------------------------------------------------------------------------
# Options for TeXLive installation
# -------------------------------------------------------------------------------
# Create symlinks in standard PATH directories (TeXLive installs into `TEXDIR`,
# see its path above). Instead of manipulating PATH, symlinks to `TEXDIR` are
# created, per default into `/usr/local/bin`.
# This setting is required to find tools!
# WARNING: This seems to only have been introduced in TeXLive 2017, see:
# https://web.archive.org/web/20171213102459/http://www.tug.org/texlive/doc/install-tl.html
# (archives from 2016 and earlier do not mention `adjustpath` on that page).
#
# At the same time, TeXLive 2020 does not seem to respect the set `TEXDIR`, breaking
# installation. However, adjusting the path here automatically works.
# Since older installations will simply ignore this setting, enable it for safety.
instopt_adjustpath 1
# Do not adjust remote CTAN repository; keep the one manually specified.
# Shouldn't matter since the repository is not used after installation/image build.
instopt_adjustrepo 0
# A4 default, not letter format
instopt_letter 0
# No portable installation required
instopt_portable 0
# Required for --shell-escape option, as required by packages, e.g. `svg`
instopt_write18_restricted 1
# -------------------------------------------------------------------------------
# Some more documentation for the following options at:
# https://tug.org/texlive/doc/tlmgr.html
# -------------------------------------------------------------------------------
# Autobackup just fills cache, skip; see
# https://tex.stackexchange.com/a/398831/120853
tlpdbopt_autobackup 0
tlpdbopt_backupdir tlpkg/backups
# Create font format files, otherwise they have to be created on the fly each
# time.
tlpdbopt_create_formats 1
# None of the following is required; especially not documentation and source
# files, which fill multiple GBs
tlpdbopt_desktop_integration 0
tlpdbopt_file_assocs 0
tlpdbopt_generate_updmap 0
tlpdbopt_install_docfiles 0
tlpdbopt_install_srcfiles 0
#
# Execute postinstallation code for packages:
tlpdbopt_post_code 1
# Symlink destinations (binaries, documentation, manuals).
# Since symlinking is done manually in the Dockerfile, these are not needed.
# tlpdbopt_sys_bin /usr/local/bin
# tlpdbopt_sys_info /usr/local/share/info
# tlpdbopt_sys_man /usr/local/share/man


================================================
FILE: .devcontainer/image/texlive.sh
================================================
#!/bin/bash

# Script to fetch `install-tl` script from different sources, depending on argument
# given.

set -ueo pipefail

usage() {
    echo "Usage: $0 get_installer|install latest|version (YYYY)"
}

# From: https://stackoverflow.com/a/2990533/11477374
echoerr() { echo "$@" 1>&2; }

check_path() {
    # The following test assumes the most basic program, `tex`, is present, see also
    # https://www.tug.org/texlive/doc/texlive-en/texlive-en.html#x1-380003.5
    echo "Checking PATH and installation..."
    if tex --version
    then
        echo "PATH and installation seem OK, exiting with success."
        exit 0
    else
        echoerr "PATH or installation unhealthy, further action required..."
    fi
}

if [[ $# != 2 ]]; then
    echoerr "Unsuitable number of arguments given."
    echoerr "Got arguments: $*"
    usage
    # From /usr/include/sysexits.h
    exit 64
fi

# Bind CLI arguments to explicit names:
ACTION=${1}
VERSION=${2}

# Download the `install-tl` script from the `tlnet-final` subdirectory, NOT
# from the parent directory. The latter contains an outdated, non-final `install-tl`
# script, causing this exact problem:
# https://tug.org/pipermail/tex-live/2017-June/040376.html
HISTORIC_URL="ftp://tug.org/historic/systems/texlive/${VERSION}/tlnet-final"
REGULAR_URL="http://mirror.ctan.org/systems/texlive/tlnet"

case ${ACTION} in
    "get_installer")
        if [[ ${VERSION} == "latest" ]]
        then
            # Get from default, current repository
            GET_URL="${REGULAR_URL}/${TL_INSTALL_ARCHIVE}"
        else
            # Get from historic repository
            GET_URL="${HISTORIC_URL}/${TL_INSTALL_ARCHIVE}"
        fi
        wget "$GET_URL"
    ;;
    "install")
        if [[ ${VERSION} == "latest" ]]
        then
            # Install using default, current repository.
            # Install process/script documentation is here:
            # https://www.tug.org/texlive/doc/texlive-en/texlive-en.html
            perl install-tl \
                --profile="$TL_PROFILE"
        else
            # Install using historic repository (`install-tl` script and repository
            # versions need to match)
            perl install-tl \
                --profile="$TL_PROFILE" \
                --repository="$HISTORIC_URL"
        fi

        # If automatic `install-tl` process has already adjusted PATH, we are happy.
        check_path
        echo "install-tl procedure did not adjust PATH automatically, trying other options..."

        # `\d` class doesn't exist for basic `grep`, use `0-9`, which is much more
        # portable. Finding the initial dir is very fast, but looking through everything
        # else afterwards might take a while. Therefore, print and quit after first result.
        # Path example: `/usr/local/texlive/2018/bin/x86_64-linux`
        TEXLIVE_BIN_DIR=$(find / -type d -regextype grep -regex '.*/texlive/[0-9]\{4\}/bin/.*' -print -quit)

        # -z test: string zero length?
        if [ -z "$TEXLIVE_BIN_DIR" ]
        then
            echoerr "Expected TeXLive installation dir not found and TeXLive installation did not modify PATH automatically."
            echoerr "Exiting."
            exit 1
        fi

        echo "Found TeXLive binaries at $TEXLIVE_BIN_DIR"
        echo "Trying native TeXLive symlinking using tlmgr..."

        # To my amazement, `tlmgr path add` can fail but still link successfully. So
        # check if PATH is OK despite that command failing.
        "$TEXLIVE_BIN_DIR"/tlmgr path add || \
            echoerr "Command borked, checking if it worked regardless..."
        check_path
        echoerr "Symlinking using tlmgr did not succeed, trying manual linking..."

        SYMLINK_DESTINATION="/usr/local/bin"

        # "String contains", see: https://stackoverflow.com/a/229606/11477374
        if [[ ! ${PATH} == *${SYMLINK_DESTINATION}* ]]
        then
            # Should never get here, but make sure.
            echoerr "Symlink destination ${SYMLINK_DESTINATION} not in PATH (${PATH}), exiting."
            exit 1
        fi

        echo "Symlinking TeXLive binaries in ${TEXLIVE_BIN_DIR}"
        echo "to a directory (${SYMLINK_DESTINATION}) found on PATH (${PATH})"

        # Notice the slash and wildcard.
        ln \
            --symbolic \
            --verbose \
            --target-directory="$SYMLINK_DESTINATION" \
            "$TEXLIVE_BIN_DIR"/*

        check_path

        echoerr "All attempts failed, exiting."
        exit 1
    ;;
    *)
        echoerr "Input not understood."
        usage
        # From /usr/include/sysexits.h
        exit 64
esac


================================================
FILE: .gitattributes
================================================
# bib -> latex does not help much, since it is also not valid latex, but at
# least highlights comments (%) correctly
*.bib linguist-language=latex

# Bash is wrong, it is really a plain-text file.
# However, it gets us comment highlighting (hiding/grey) and is close enough.
*.profile linguist-language=bash

# Do not include git config files in archives (e.g. when downloading as ZIP):
.git* export-ignore


================================================
FILE: .github/workflows/build.yml
================================================
name: Building and testing
on: [push]
jobs:
  building:
    runs-on: ubuntu-latest
    container:
      image: alexpovel/latex
      # Need root, otherwise this exact issue occurs:
      # https://github.community/t/permission-problems-when-checking-out-code-as-part-of-github-action/202263
      options: --user root
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
      - name: Run preflight checks
        run: make preflight
      - name: Build all LaTeX PDFs
        run: make tex
      - name: Build README PDF
        run: make README.pdf
      - name: Archive compilation artifacts
        uses: actions/upload-artifact@v7
        with:
          name: pdfs
          path: ./*.pdf
          if-no-files-found: error
  testing:
    needs: building
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: "3.14"
          cache: "pip"
      - name: Install Python dependencies
        working-directory: ./tests # Needs to find pyproject.toml file
        run: >
          python -m venv .venv
          && . .venv/bin/activate
          && pip install .
      - name: Test the suite itself
        run: >
          . ./tests/.venv/bin/activate
          && make test-self
      - uses: actions/download-artifact@v8
        with:
          name: pdfs # Specify name, else it'll be downloaded to a subdirectory
      - name: Test generated PDFs
        run: >
          . ./tests/.venv/bin/activate
          && make test-pdfs


================================================
FILE: .gitignore
================================================
# This file tells git what files *not* to track in its version control.
# Specific files, general suffixes, whole directories etc. can be specified.

# ======================================================================================
# Python (https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore)
# ======================================================================================

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# ======================================================================================
# LaTeX
# ======================================================================================

# Generated PDF is not suitable for Git. We get our compiled PDF via CI.
# Only ignore root level PDF, since images/vectors might be in PDF format.
/*.pdf

Eisvogel*/

# Testing environment
testing.tex

# Some weird junk file from VSCode LaTeX Workshop?
__latexindent_temp.tex

# Include settings files, but nothing else, since that is used as part of the cookbook
.vscode/*
!.vscode/settings.json
!.vscode/extensions.json

organisational/

# Used to generate the 'dirty directory tree'
dirty_directory/

# Temporarily generated files using gnuplot (e.g. 'contour gnuplot') with pgfplots. Filenames are of the form '<main tex file name>_contourtmp_<sequential numbering>.<ext>
# Extensions <ext> are 'dat', 'table', 'script'
*contourtmp*

# Automatically generated files by svg package:
**/svg-inkscape/*

## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
# List of Reactions (`chemmacros`):
*.lor
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2
.*.lb

## Intermediate documents:
*.dvi
*.xdv
*-converted-to.*
# these rules might exclude image files for figures etc.
# *.ps
# *.eps
# *.pdf

## Generated if empty string is given at "Please type another file name for output:"
.pdf

## Bibliography auxiliary files (bibtex/biblatex/biber):
*.bbl
*.bcf
*.blg
*-blx.aux
*-blx.bib
*.run.xml

## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync

## Build tool directories for auxiliary files
# latexrun
latex.out/

## Auxiliary and intermediate files from other packages:
# algorithms
*.alg
*.loa

# achemso
acs-*.bib

# amsthm
*.thm

# beamer
*.nav
*.pre
*.snm
*.vrb

# changes
*.soc

# comment
*.cut

# cprotect
*.cpt

# elsarticle (documentclass of Elsevier journals)
*.spl

# endnotes
*.ent

# fixme
*.lox

# feynmf/feynmp
*.mf
*.mp
*.t[1-9]
*.t[1-9][0-9]
*.tfm

#(r)(e)ledmac/(r)(e)ledpar
*.end
*.?end
*.[1-9]
*.[1-9][0-9]
*.[1-9][0-9][0-9]
*.[1-9]R
*.[1-9][0-9]R
*.[1-9][0-9][0-9]R
*.eledsec[1-9]
*.eledsec[1-9]R
*.eledsec[1-9][0-9]
*.eledsec[1-9][0-9]R
*.eledsec[1-9][0-9][0-9]
*.eledsec[1-9][0-9][0-9]R

# glossaries
*.acn
*.acr
*.glg
*.glo
*.gls
*.glsdefs

# gnuplottex
*-gnuplottex-*

# gregoriotex
*.gaux
*.gtex

# htlatex
*.4ct
*.4tc
*.idv
*.lg
*.trc
*.xref

# hyperref
*.brf

# knitr
*-concordance.tex
# TODO Comment the next line if you want to keep your tikz graphics files
*.tikz
*-tikzDictionary

# listings
*.lol

# makeidx
*.idx
*.ilg
*.ind
*.ist

# minitoc
*.maf
*.mlf
*.mlt
*.mtc[0-9]*
*.slf[0-9]*
*.slt[0-9]*
*.stc[0-9]*

# minted
_minted*
*.pyg

# morewrites
*.mw

# nomencl
*.nlg
*.nlo
*.nls

# pax
*.pax

# pdfpcnotes
*.pdfpc

# sagetex
*.sagetex.sage
*.sagetex.py
*.sagetex.scmd

# scrwfile
*.wrt

# sympy
*.sout
*.sympy
sympy-plots-for-*.tex/

# pdfcomment
*.upa
*.upb

# pythontex
*.pytxcode
pythontex-files-*/

# tcolorbox
*.listing

# thmtools
*.loe

# TikZ & PGF
*.dpth
*.md5
*.auxlock

# todonotes
*.tdo

# vhistory
*.hst
*.ver

# easy-todo
*.lod

# xcolor
*.xcp

# xmpincl
*.xmpi

# xindy
*.xdy

# xypic precompiled matrices
*.xyc

# endfloat
*.ttt
*.fff

# Latexian
TSWLatexianTemp*

## Editors:
# WinEdt
*.bak
*.sav

# Texpad
.texpadtmp

# LyX
*.lyx~

# Kile
*.backup

# KBibTeX
*~[0-9]*

# auto folder when using emacs and auctex
./auto/*
*.el

# expex forward references with \gathertags
*-tags.tex

# standalone packages
*.sta

# tikz externalize with make-list option
*.makefile

# Glossaries:
*.slg
*.slo
*.sls

# Illustrations Custom Environment and Aux File:

*.illustrations

# from glossaries-extra with bib2gls
*.glstex
*.syi
*.syg

# windows thumbnail cache:
Thumbs.db


================================================
FILE: .latexmkrc
================================================
#!/bin/env perl

# This file contains instructions and configurations for the `latexmk` program.
# That program is somewhat like `make`, but tailored to LaTeX.
# LaTeX has a distinct characteristic of regularly requiring *multiple runs* of
# the same program (e.g. `lualatex`) before the build is finished.
# It's a *multi-pass* system.
# In the intermediary runs, latex generates auxiliary files responsible for resolving
# references, links, tables of content etc.

# `latexmk` knows about these dependencies (otherwise we tell it in this very config
# file, see below), detects these and runs latex (and other, outside programs)
# accordingly.

# Now, why do we need *both* `latexmk` and `make`?
# Both automate builds.

# `latexmk` is not powerful enough to cover all use cases.
# `make` is more general and more suitable to be integrated in CI.
# For our latex needs, `make` basically only delegates to `latexmk`.
# We **do not** call e.g. `lualatex` multiple times manually from `make`:
# this logic is left to `latexmk` and `.latexmkrc`.
# However, `make` can also do much more, e.g. cover `pandoc`, clean-up operations etc.
# Therefore, `make` and `latexmkrc` *together* are just super powerful and useful.


# The shebang at the top  is only to get syntax highlighting right across GitLab,
# GitHub and IDEs.
# This file is not meant to be run, but read by `latexmk`.

# ======================================================================================
# Perl `latexmk` configuration file
# ======================================================================================

# ======================================================================================
# PDF Generation/Building/Compilation
# ======================================================================================

# PDF-generating modes are:
# 1: pdflatex, as specified by $pdflatex variable (still largely in use)
# 2: postscript conversion, as specified by the $ps2pdf variable (useless)
# 3: dvi conversion, as specified by the $dvipdf variable (useless)
# 4: lualatex, as specified by the $lualatex variable (best)
# 5: xelatex, as specified by the $xelatex variable (second best)
$pdf_mode = 4;

# Treat undefined references and citations as well as multiply defined references as
# ERRORS instead of WARNINGS.
# This is only checked in the *last* run, since naturally, there are undefined references
# in initial runs.
# This setting is potentially annoying when debugging/editing, but highly desirable
# in the CI pipeline, where such a warning should result in a failed pipeline, since the
# final document is incomplete/corrupted.
#
# However, I could not eradicate all warnings, so that `latexmk` currently fails with
# this option enabled.
# Specifically, `microtype` fails together with `fontawesome`/`fontawesome5`, see:
# https://tex.stackexchange.com/a/547514/120853
# The fix in that answer did not help.
# Setting `verbose=silent` to mute `microtype` warnings did not work.
# Switching between `fontawesome` and `fontawesome5` did not help.
$warnings_as_errors = 0;

# Show used CPU time. Looks like: https://tex.stackexchange.com/a/312224/120853
$show_time = 1;

# Default is 5; we seem to need more owed to the complexity of the document.
# Actual documents probably don't need this many since they won't use all features,
# plus won't be compiling from cold each time.
$max_repeat=7;

# --shell-escape option (execution of code outside of latex) is required for the
#'svg' package.
# It converts raw SVG files to the PDF+PDF_TEX combo using InkScape.
#
# SyncTeX allows to jump between source (code) and output (PDF) in IDEs with support
# (many have it). A value of `1` is enabled (gzipped), `-1` is enabled but uncompressed,
# `0` is off.
# Testing in VSCode w/ LaTeX Workshop only worked for the compressed version.
# Adjust this as needed. Of course, only relevant for local use, no effect on a remote
# CI pipeline (except for slower compilation, probably).
#
# %O and %S will forward Options and the Source file, respectively, given to latexmk.
#
# `set_tex_cmds` applies to all *latex commands (latex, xelatex, lualatex, ...), so
# no need to specify these each. This allows to simply change `$pdf_mode` to get a
# different engine. Check if this works with `latexmk --commands`.
set_tex_cmds("--shell-escape --synctex=1 %O %S");

# option 2 is same as 1 (run biber when necessary), but also deletes the
# regeneratable bbl-file in a clenaup (`latexmk -c`). Do not use if original
# bib file is not available!
$bibtex_use = 2;  # default: 1

# Change default `biber` call, help catch errors faster/clearer. See
# https://web.archive.org/web/20200526101657/https://www.semipol.de/2018/06/12/latex-best-practices.html#database-entries
$biber = "biber --validate-datamodel %O %S";

# ======================================================================================
# Auxiliary Files
# ======================================================================================

# Let latexmk know about generated files, so they can be used to detect if a
# rerun is required, or be deleted in a cleanup.
# loe: List of Examples (KOMAScript)
# lol: List of Listings (`listings` and `minted` packages)
# run.xml: biber runs
# glg: glossaries log
# glstex: generated from glossaries-extra
push @generated_exts, 'loe', 'lol', 'lor', 'run.xml', 'glg', 'glstex';

# Also delete the *.glstex files from package glossaries-extra. Problem is,
# that that package generates files of the form "basename-digit.glstex" if
# multiple glossaries are present. Latexmk looks for "basename.glstex" and so
# does not find those. For that purpose, use wildcard.
# Also delete files generated by gnuplot/pgfplots contour plots
# (.dat, .script, .table).
$clean_ext = "%R-*.glstex %R_contourtmp*.*";

# ======================================================================================
# bib2gls as a custom dependency
# ======================================================================================

# Grabbed from latexmk CTAN distribution:
# Implementing glossary with bib2gls and glossaries-extra, with the
# log file (.glg) analyzed to get dependence on a .bib file.
# !!! ONLY WORKS WITH VERSION 4.54 or higher of latexmk

# Add custom dependency.
# latexmk checks whether a file with ending as given in the 2nd
# argument exists ('toextension'). If yes, check if file with
# ending as in first argument ('fromextension') exists. If yes,
# run subroutine as given in fourth argument.
# Third argument is whether file MUST exist. If 0, no action taken.
add_cus_dep('aux', 'glstex', 0, 'run_bib2gls');

# PERL subroutine. $_[0] is the argument (filename in this case).
# File from author from here: https://tex.stackexchange.com/a/401979/120853
sub run_bib2gls {
    if ( $silent ) {
    #    my $ret = system "bib2gls --silent --group '$_[0]'"; # Original version
        my $ret = system "bib2gls --silent --group $_[0]"; # Runs in PowerShell
    } else {
    #    my $ret = system "bib2gls --group '$_[0]'"; # Original version
        my $ret = system "bib2gls --group $_[0]"; # Runs in PowerShell
    };

    my ($base, $path) = fileparse( $_[0] );
    if ($path && -e "$base.glstex") {
        rename "$base.glstex", "$path$base.glstex";
    }

    # Analyze log file.
    local *LOG;
    $LOG = "$_[0].glg";
    if (!$ret && -e $LOG) {
        open LOG, "<$LOG";
    while (<LOG>) {
            if (/^Reading (.*\.bib)\s$/) {
        rdb_ensure_file( $rule, $1 );
        }
    }
    close LOG;
    }
    return $ret;
}


================================================
FILE: .vscode/extensions.json
================================================
{
	// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
	// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
	// List of extensions which should be recommended for users of this workspace.
	"recommendations": [
		"ms-vscode-remote.remote-containers",
		"James-Yu.latex-workshop"
	],
	// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
	"unwantedRecommendations": []
}

================================================
FILE: .vscode/settings.json
================================================
{
    "latex-workshop.latex.recipes": [
        {
            "name": "latexmk",
            "tools": [
                "latexmk"
            ]
        },
        {
            "name": "lualatex",
            "tools": [
                "lualatex"
            ]
        }
    ],
    "latex-workshop.latex.tools": [
        {
            "name": "lualatex",
            "command": "lualatex",
            "args": [
                "--shell-escape",
                "--synctex=1",
                "--recorder",
                "%DOC%"
            ]
        },
        {
            "name": "latexmk",
            "command": "latexmk",
            "args": [
                // latexmk doesn't need a file argument, but provide it to avoid running
                // on *all* found tex files
                "%DOC%"
            ]
        }
    ],
    "latex-workshop.latex.recipe.default": "first",
    "latex-workshop.linting.chktex.enabled": true,
    "latex-workshop.linting.run": "onSave",
    "latex-workshop.latex.autoBuild.run": "never",
}


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [5.0.0] - 2022-05-11

### Added

- GitHub Actions configuration (b847c85)

  This is supposed to replace the GitLab config.

### Changed

- GitLab references to point to GitHub instead (7a33ee3)
- Updated Python test suite from 3.7 to 3.10 (0733c83)
- Simplified `polyglossia` language loading (053b87d)
- Switched VSCode Remote Containers config from building to downloading image (4efd364).

  When new users first use this template, it is extremely frustrating for them to have to *build* the entire Docker image from scratch themselves, which can take very long.
  Simply download the existing one from DockerHub, which is much faster.

### Removed

- GitLab-specific content (config files, documentation, ...) (7a33ee3)
- Deprecated `chemmacros` `usechemmodule` macro (0909097)
- Profanity check in PDF test (0733c83)

## [4.0.0] - 2021-10-18

### Added

- `matlab2tikz` improved alternative showcase using `pgfplots` (0910bca)
- Important badges of high importance for important information (d19b8d9)
- Hint on `parskip` usage to remove paragraph indentation in favor of vertical space (a292f6b)
- Support for *Acronyms* glossary title localization (86c0be1)
- New package for tables, `tabularray` (6825ff9, 480b400)
- Docker image source (merged in c584129)
- Additional math/unit font examples (2e3a582)

### Fixed

- Display of dimensionless quantities (5f8dc71)
- Tabular vertical excess white space (e5f983e)

### Changed

- usage of `chemmacros` over `chemformula` (e379fa9, c26d613)
- `siunitx` settings and usage to support [major version 3](https://github.com/josephwright/siunitx/blob/v3.0.0/CHANGELOG.md#v300) (bb931a9, 4fc2caf, 6747a36, 190bc89, e83902a, 82977ce)
- Docker image source (b50eb6f, f10005e, 548dca9, a8fff45, afa8407, 3a0b4f0, a57a4ec)
- massive simplification/moving of README content (f8f4d3f, 2925463, 2840312, a99df09, bcb4d69)

### Removed

- LaTeX Workshop automatic compilation on save (6b0d313)
- Old files (6fbdc2e, 04eb8fe, 096331c, b37316d, cdc285d)

## [3.1.0] - 2021-03-12

### Added

- Toggle for inclusion of glossaries in the Table of Contents (ToC) (5c23bd0)
- Example for an appendix (d4a42ce)
- Translations for code listings in references, lists, captions (6148d55)
- ARCHITECTURE document (840eff8)
- Example for a `longtabu` (multi-page table) displaying random data generated by custom Lua script (9e89214)
- Section on alternative ways to compile (f2d550d)
- Configuration and ideal setup for working with this template inside Visual Studio Code, using its native container development environment (38a0bb2)
- Example for a new unit specification using `siunitx` (7a2d0d0)

### Changed

- Switched bibliography generation from vanilla Zotero to Zotero with its excellent **Better Bibtex** addon (a05f5f4)
- Fixed biblatex fields according to `biber --validate-datamodel` validation (eb068bd)
- Fixed using a system directory for `pandoc`, which required `sudo` privileges (no just user privileges) (d8f4c1c)

### Removed

- TeXGyrePagella font files: use those included in the TeX distribution itself (d74c2d9)
- Trailing whitespaces (WOW!) (d766fb6)

## [3.0.0] - 2021-02-03

### Added

- Option to suppress printing of pages list in the glossaries (b75d3d1)
- GitLab description templates (7038798)

### Changed

- Syntax highlighting now uses `minted` instead of `listings`, a backwards-incompatible change (19fbd87)
- Documentation now stresses Docker usage over manual "labour" (6843a2b)

### Removed

- Previous, custom-made `listings` language definitions; these are covered much better by `pygments`, aka `minted` (19fbd87)

## [2.0.0] - 2020-11-11

### Added

- Python-based tests for the produced PDFs (1746e4e).
  This allows the user to automatically run a test suite against the produced PDFs,
  for example checking for page count, metadata and much more.
- Makefiles for the [root](Makefile) and [tests](tests/Makefile) directories, while
  also swapping all CI routines over to use `make` (b4a9881).
  This allows for local as well as CI use using the same commands, and reduces coupling
  with the CI engine.
- Caching of files in CI, for much faster pipelines (while introducing some issues) (28aea76).
- Showcase and fixing of `\abs` macro for absolute values (4d0c6ff, bb11b72).

### Changed

- Git metadata display in the colophon (7c59cbe).

## [1.2.0] - 2020-10-29

### Added

- Showcase for multiple lines with contours in TikZ overlay (ae4ad39)
- Hint for the `glossaries-extra` *Beginner's Guide* (d8b7fb4)
- Written permission (license) to use and distribute the [Fontin Sans](https://www.fontsquirrel.com/fonts/fontin-sans)
  font (cf79ee4)
- Summary for font licenses (0372475)
- Contributing guideline (56c4eac)
- README info on git and Docker (fa228b7)
- A `matlab2tikz` exported plot example (86dac19, c3e9b09)
- `YAML`-based configs for pandoc (cb39706)
- Proper check for the used TeX engine (de2a293)

### Changed

- Fontawesome implementation, away from the `fontawesome` package to the more
  modern `fontawesome5` (8df784e)
- Insertion of git metadata into the document (PDF metadata or into the printed text
  directly): now based on Lua (6d0cd7e)
- Also adjusted the README according to the new Lua implementation (ed946b8)

## [1.1.1] - 2020-06-09

### Added

- Entry `Mach` in `names.bib` (d0d5683). Was previously removed, but is required.

## [1.1.0] - 2020-06-09

### Added

- Added `bib` file entries for the built-in math macros (f1803d3b):
  - `\mean`
  - `\logmean`
  - `\flow`
  - `\difference`
  - `\nablaoperator`
  - `\vect`
  - `\deriv`
  - `\fracderiv`
  - `\timederiv`
  - `\posderiv`
- New tabular showcasing those built-in math macros (119fce11)
- New tabular showcasing the built-in glossary commands (0e7ed5a9):
  - `\idx`
  - `\name`
  - `\sym`
  - `\sub`
  - `\abb`
  - `\cons`
- Added sample entries for the *Terms* index (6ca2670b)

### Removed

- Unused entry `Mach` in `names.bib` (c000d4ec)

## [1.0.0] - 2020-04-22

### Added

- Initial release


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Alex Povel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
# This file contains instructions for the GNU `make` program: https://www.gnu.org/software/make/
#
# The program is quite old, very stable, ubiquitous and widely used.
# It is a staple in the Linux world.
# There are ways to get it to run on Windows, but I haven't tried any.
# Use WSL (https://docs.microsoft.com/en-us/windows/wsl/install-win10) instead and
# save yourself the headaches.

# `make` runs steps according to this very `Makefile` in order to arrive at a target,
# like a PDF compiled with latex.
# It checks all the dependencies automatically and only updates the target if changes
# in the sources are detected.

# The idea is that this project's PDFs can be compiled by simply calling e.g.
# `make file.pdf` *both locally and in CI*.
# Without make, we would otherwise have very different build steps in local and CI
# environments.
# Additionally, using `make`, the CI instructions (.gitlab-ci.yml, GitHub actions etc.)
# can be simplified considerably, leading to decoupling.
# Moving CI systems then becomes much easier.


# =====================================================================================
# =====================================================================================
# Prerequisites
# =====================================================================================
# =====================================================================================

# The following are "special targets", see:
# https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets
# A phony target: not a file, just some routine.
.PHONY: all clean mostlyclean clean-aux clean-pdf tex preflight help image

# =====================================================================================
# Helper tool, adjusted from:
# https://medium.com/@exustash/three-good-practices-for-better-ci-cd-makefiles-5b93452e4cc3
# Allows to annotate targets with regular comments and have a summary printed by calling
# `make help`.
# =====================================================================================

# Note escaping of comment char #
FS = ":.*?\#"

help: # List available targets on this project. First one shown is the default.
	@grep --extended-regexp --no-filename "\w+$(FS) .*" $(MAKEFILE_LIST) | \
		awk --field-separator="$(FS)" '{printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

# =====================================================================================
# Set variables, executables and their flags.
# =====================================================================================

# Common flags go here:

# Configure latexmk tool using '.latexmkrc' in project root, not in here.
LATEXMK_FLAGS =

# For pandoc, provide dynamic metadata for the date (see below). Git short SHA works
# both in CI and locally. All other settings are in the `defaults` file.
PANDOC_FLAGS = --defaults=pandoc/defaults.yaml

# Flags depending on CI/Local go here:

# GitLab CI defines variables that we can check for. This allows us to detect if we're
# in a CI scenario.
# See also:
# https://www.gnu.org/software/make/manual/html_node/Conditional-Syntax.html#Conditional-Syntax
# https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
#
# That same environment variable is defined for GitHub Actions as well:
# https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
ifdef CI
	# In container, run commands directly:
	LATEXMK = latexmk
	PANDOC = pandoc
	#
	GIT_SHORT_SHA = $$CI_COMMIT_SHORT_SHA
	# pandoc is quiet by default
	PANDOC_FLAGS += --verbose
	# After the run, display the relevant rules (for debugging)
	LATEXMK_FLAGS += --rules
else
	DOCKER_RUN = docker run --rm --volume ${PWD}:/tex
	DOCKER_IMAGE = alexpovel/latex
	#
	LATEXMK = $(DOCKER_RUN) --entrypoint="latexmk" $(DOCKER_IMAGE)
	PANDOC = $(DOCKER_RUN) --entrypoint="pandoc" $(DOCKER_IMAGE)
	# No supporting Docker image available yet:
	GIT_SHORT_SHA = $(shell git rev-parse --short HEAD)
	# latexmk is verbose by default:
	LATEXMK_FLAGS += --quiet
endif

PANDOC_FLAGS += --metadata=date:"$(shell date --iso-8601) ($(GIT_SHORT_SHA))"

# =====================================================================================
# =====================================================================================
# Files to build
# =====================================================================================
# =====================================================================================

# Produce all found tex files.
tex_sources = $(wildcard *.tex)
tex_pdfs := $(tex_sources:.tex=.pdf)

# First rule is what is run by default if just using `make` with no arguments.
# It is the 'goal': https://www.gnu.org/software/make/manual/html_node/Goals.html.
# The name `all` is just a convention.
# Change suffix of multiple different extensions (.tex, .md), to the same suffix (.pdf).
# See also: https://stackoverflow.com/a/33926814
all: preflight tex README.pdf test  # Performs preflight checks, then builds and tests all PDFs.
# A rule for only LaTeX files:
tex: $(tex_pdfs)  # Builds all *.tex files into PDFs.

# =====================================================================================
# Rules for file building
# =====================================================================================

# This Makefile uses implicit rules, see:
# https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html#Implicit-Rules
# For those, Automatic Variables are important:
# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
# $*: "The stem with which an implicit rule matches"
# $<: "The name of the first prerequisite"
# $@: "The file name of the target of the rule"
# $^: "The names of all the prerequisites, with spaces between them"

# Pattern rule, see:
# https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html,
# Just sets up an implicit rule to specify how to get from prerequisite to target,
# called whever `make` detects it needs to do so. No need to specify things manually.
%.pdf: %.tex  # Allows to build any PDF from a corresponding *.tex file.
	$(info Running $(LATEXMK) to build $@...)
	@$(LATEXMK) $(LATEXMK_FLAGS) $<

PANDOC_TEMPLATE = $(strip $(shell grep "^template:" pandoc/defaults.yaml | cut --delimiter=":" --field=2)).latex
PANDOC_TEMPLATE_DIR = ~/.pandoc/templates

%.pdf: %.md $(PANDOC_TEMPLATE_DIR)/$(PANDOC_TEMPLATE)  # Allows to build any PDF from a corresponding *.md file.
	$(info Running $(PANDOC) to build $@...)
	@$(PANDOC) $(PANDOC_FLAGS) --output=$@ $<

EISVOGEL_ARCHIVE = Eisvogel.tar.gz
EISVOGEL_VERSION = 3.4.0

# The `$(info ...)` function gives out-of-order logging, while `echo` works with the
# `wget` progress display.
$(PANDOC_TEMPLATE_DIR)/$(PANDOC_TEMPLATE):
	@echo "Template not found at $@, downloading..."
	@wget --quiet --show-progress --no-clobber \
		"https://github.com/Wandmalfarbe/pandoc-latex-template/releases/download/v${EISVOGEL_VERSION}/${EISVOGEL_ARCHIVE}"
	@echo "Extracting $(EISVOGEL_ARCHIVE)..."
	@tar --extract --file=${EISVOGEL_ARCHIVE} Eisvogel-${EISVOGEL_VERSION}/eisvogel.latex
# `$(@D)` is directory part of current target:
	@mkdir --parents $(@D)
	@mv "Eisvogel-${EISVOGEL_VERSION}/eisvogel.latex" $@
	@$(RM) $(EISVOGEL_ARCHIVE)

# =====================================================================================
# Help users install programs required for compilation and help debug.
# =====================================================================================
preflight:  # Performs checks to ensure prerequisites for compilation are met.
	@echo "Checking presence of required libraries..."
	@ldconfig --print-cache | grep --silent "librsvg" || \
		(echo "librsvg missing: required by pandoc to convert files containing SVGs."; exit 69)
	@echo "Libraries OK."
# Output looks like: https://tex.stackexchange.com/a/311753/120853
	@$(LATEXMK) --commands

# =====================================================================================
# Docker
# =====================================================================================

image: ./.devcontainer/image/Dockerfile
	@docker build --tag alexpovel/latex:local --file $< .

# =====================================================================================
# Testing.
# =====================================================================================

include tests/Makefile

# =====================================================================================
# Cleanup jobs.
# =====================================================================================
clean-aux:  # Cleans LaTeX's auxiliary files.
	@echo "Removing auxiliary files of all found TeX files..."
	@$(LATEXMK) -c $(LATEXMK_FLAGS)

clean-pdf:  # Cleans all found PDFs.
	@echo "Removing all PDF files:"
	@ls *.pdf 2>/dev/null || echo "No files to remove."
	@$(RM) *.pdf

# For target name, see: https://www.gnu.org/prep/standards/html_node/Standard-Targets.html
mostlyclean: clean-aux clean-pdf  # Runs clean-{aux,pdf}, then cleans more.
	@echo "Removing downloaded pandoc archive, if any..."
	@$(RM) $(EISVOGEL_ARCHIVE)

clean: mostlyclean  # Runs all other clean jobs, then cleans absolutely everything.
	@echo "Removing all files ignored by git (.gitignore)..."
	@echo "For safety, this is done interactively:"
	@git clean -xd --interactive
	@echo "Removing pandoc template..."
	@$(RM) $(PANDOC_TEMPLATE_DIR)/$(PANDOC_TEMPLATE)


================================================
FILE: README.md
================================================
# LaTeX Cookbook

[![Download PDF](https://img.shields.io/badge/Download-PDF-blue.svg)][download]

This repo contains a [LaTeX document](cookbook.tex), usable as a cookbook (different "recipes" to achieve various things in LaTeX) as well as as a template.
The resulting PDF covers LaTeX-specific topics and instructions on compiling the LaTeX source.

See the [releases page](https://github.com/alexpovel/latex-cookbook/releases) for more downloads.

> [!IMPORTANT]
> This project is not archived, and [issues are still
> addressed](https://github.com/alexpovel/latex-cookbook/issues/17). However, the
> document is regarded as "done" and no new feature development actively happens. As LaTeX is a glacially slow-moving target, the document
> should be useful, valid and buildable for many years to come still.
>
> There is a [fork
> maintained](https://collaborating.tuhh.de/m21/public/theses/itt-latex-template) by
> former coworkers of the author, at the research institute this template originated
> from as well. Active development is still happening there.

## Getting started

After installing [Docker](https://www.docker.com/) (and git), building works out of the
box:

- Bash:

  ```console
  $ git clone git@github.com:alexpovel/latex-cookbook.git
  $ cd latex-cookbook
  $ docker run --rm --volume $(pwd):/tex alexpovel/latex
  $ xdg-open cookbook.pdf
  ```

- PowerShell:

  ```powershell
  PS> git clone git@github.com:alexpovel/latex-cookbook.git
  PS> cd latex-cookbook
  PS> docker run --rm --volume ${PWD}:/tex alexpovel/latex
  PS> Invoke-Item cookbook.pdf
  ```

The [entrypoint](https://docs.docker.com/engine/reference/builder/#entrypoint) is
[`latexmk`](https://ctan.org/pkg/latexmk?lang=en), which when given no arguments (as
done here) runs on all found `*.tex` files, which in this case is only the root's [main
file](./cookbook.tex).

> [!NOTE]
> Should this fail to compile (this is a bug, please report!), feel free to try other
> images. When `alexpovel/latex` was built,
> [`texlive/texlive`](https://hub.docker.com/r/texlive/texlive) did not exist yet.
> **That image is strongly recommended**, as it is actively maintained by the actual
> authors of TeXLive. If tools are missing, like `inkscape`, build your own image `FROM
> texlive/texlive`, then install required software.
>
> Alternatively, there is [a
> fork](https://collaborating.tuhh.de/m21/public/theses/latex_dockerfile) for the image
> as well, accompanying the [template
> fork](https://collaborating.tuhh.de/m21/public/theses/itt-latex-template).

## Features

The [PDF itself][download] has much more to say on this and is meant to speak for itself, visually.
The following is simply a brief overview of the features contained in this repo.

### Tooling

- accompanying [Docker image](.devcontainer/image/Dockerfile), usable locally and in CI/CD, guaranteeing compilation success without interfering with your local installation.
  In fact, using Docker (containerization in general), no LaTeX installation is required at all.
  - accompanying Visual Studio Code [environment configuration](.devcontainer/devcontainer.json).

    If you open this repository in [Visual Studio Code](https://code.visualstudio.com/), it should automatically put you into the correct Docker container environment for development, and just work™.
    See [here](.devcontainer/README.md) for more info.
  - in the image, [`pandoc`](https://pandoc.org/) is available with the [Eisvogel](https://github.com/Wandmalfarbe/pandoc-latex-template) template, allowing beautiful PDFs to be generated from Markdown (like this README: download it from the latest [Actions artifacts](https://github.com/alexpovel/latex-cookbook/actions); it currently looks lackluster because this README is mainly PNGs)
- [tests](tests/config.yml) for your PDF, using Python to ensure some (basic) properties of your output adhere to expectations
- a [Makefile](Makefile) to facilitate ease of use and platform independence (commands like `make file.pdf` work locally as well as in CI pipelines)

### LaTeX-specific

- full Unicode support through `lualatex`, the [successor](https://en.wikipedia.org/wiki/LuaTeX) to the obsolete `pdflatex`.
  This also affords beautiful font typesetting through [`unicode-math`](https://ctan.org/pkg/unicode-math).
  High-quality fonts like [TeX Gyre Pagella](https://ctan.org/pkg/tex-gyre-pagella) have all desirable font shapes available:
  ![font-shapes](images/bitmaps/readme/font-shapes.png)
- automatic compilation using [`latexmk`](.latexmkrc), ensuring the PDF is built fully, running all steps necessary (generation of the bibliography, glossaries, ...) automatically as needed
- comprehensive support for:
  - generating [indices](bib/glossaries/index/),
  - typesetting and displaying [symbols](bib/glossaries/symbols/) in an automatically generated nomenclature,
  - [acronyms and abbreviations](bib/glossaries/abbreviations.bib), as well as
  - [mathematical constants](bib/glossaries/constants.bib),

  made possible through [`glossaries-extra`](https://ctan.org/pkg/glossaries-extra).
- structured and commented source code, explaining rationales and providing context
- showcasing plotting and data display (floats):
  - computing more complicated plots (in this example, a contour plot) *directly in LaTeX*, with no explicit outside tools used ([`gnuplot`](http://www.gnuplot.info/) is used by LaTeX in the background):

    ![plot-compute](images/bitmaps/readme/plot-compute.png)
  - ingesting a CSV directly, and plotting it (so we can skip [`matlab2tikz`](https://www.mathworks.com/matlabcentral/fileexchange/22022-matlab2tikz-matlab2tikz) etc.).
    The below style is inspired by [Tufte](https://www.edwardtufte.com/tufte/):

    ![plot-csv](images/bitmaps/readme/plot-csv.png)
  - typesetting more complex tables, with footnotes, decimal alignment and more:

    ![table](images/bitmaps/readme/tables.png)
  - using tikz:
    - for annotating bitmap graphics:

      ![tikz-annotation](images/bitmaps/readme/tikz-annotations.png)
    - for drawing diagrams (this template contains a (basic) `pgf`/`tikz` library for energy systems/thermodynamics/hydraulics/... symbols like pipes, compressors, valves, ...) and 3D sketches.
      For a much better and comprehensive collection of TikZ examples, see [here](https://texample.net/tikz/examples/).

      ![tikz-diagram](images/bitmaps/readme/tikz-diagram.png)
      ![tikz-libaries](images/bitmaps/readme/tikz-libraries.png)
- back-referencing of citations, using the excellent [`biblatex`](https://ctan.org/pkg/biblatex):

  ![backref](images/bitmaps/readme/backref.png)
- support for elaborate chemical reaction equations, using [`chemmacros`](https://ctan.org/pkg/chemmacros):

  ![chemmacros](images/bitmaps/readme/chem.png)
- comprehensive code syntax highlighting, thanks to [`minted`](https://ctan.org/pkg/minted) and `pygments`:

  ![pygments](images/bitmaps/readme/code.png)
- quick and structural switching of language contexts, provided by [`polyglossia`](https://ctan.org/pkg/polyglossia):

  ![language](images/bitmaps/readme/language.png)
- of course, support for enhanced mathematical typesetting, like highlighted equations or premade macros.
  The blue color are *hyperlinks*, turning those symbols into links to the glossary (this can be toggled off).

  ![math](images/bitmaps/readme/math.png)

  ![math-macros](images/bitmaps/readme/math-macros.png)

[download]: https://github.com/alexpovel/latex-cookbook/releases/latest/download/cookbook.pdf


================================================
FILE: acp.cls
================================================
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LuaLaTeX based on KOMA-Script
%
% Author (2021): Alex Povel - tex(at)alexpovel.de
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Class Options
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Refer to https://www.overleaf.com/learn/latex/Writing_your_own_class
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{acp}[2021-10-06 v4.0.0 acp class]

% Fail early and give useful information on the required engine.
% This helps users who do not read the documentation beforehand, by promoting the
% requirement from some statement in the docs to actual code that errors out.
\RequirePackage{iftex}
\RequireLuaTeX{}

\newcommand*{\@baseclass}{scrbook}% Name of class this one is based on

% If option 'language' is not given at all, use initialization 'english' as a fallback.
% If it is called without a value, use default (or throw error of no default given)
% This method was chosen to have the language available in a macro, so it may be passed
% to polyglossia.
% This approach messes with the forwarding of the language and raises a warning
% 'Unused global options'; we can probably ignore that for now
% (https://tex.stackexchange.com/a/278172/120853).
\RequirePackage{kvoptions}
    %[default]{language} % If no default entered: option requires a value:
    \DeclareStringOption[english]{language}
    \DeclareStringOption{titlestyle}
    \DeclareBoolOption{censoring}% Initially false by default
    \ProcessKeyvalOptions*

\PassOptionsToClass{%
    \acp@language,% Scheme: \filename@keyoption
    twoside,% For printing two-sided documents
    % 'List of (Tables, Figures, ...)' gets pushed down one hierarchical level:
    % listof=leveldown,
    listof=totoc,% All registered Lists of XYZ to Table of Contents
    bibliography=totoc,
    chapterprefix=true,% Print 'Chapter' etc. label in front of number
    open=right,% Open new Chapters on recto pages
    numbers=noenddot,% https://tex.stackexchange.com/a/102305/120853
}{\@baseclass}

% Bundle 'a5' to not only have a5paper but also decrease font size.
% https://tex.stackexchange.com/a/418947/120853
% https://tex.stackexchange.com/a/27149/120853
\DeclareOption{a5}{%
    % Not forwarded to typearea package if passed as class option: do it manually here:
    \PassOptionsToPackage{paper=a5}{typearea}
    \PassOptionsToClass{fontsize=10pt}{\@baseclass}%
}%

% Forward all other options given to \documentclass[] to base class:
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\@baseclass}}

\ProcessOptions\relax% Execute these options

\LoadClass{\@baseclass}% Finally, load the base class

\RequirePackage[\acp@language]{tracklang}% Language Tracking

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Typography and Misc.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{scrhack}% Fixes for packages incompatible with KOMA features

\RequirePackage{import}% Relative path imports

\RequirePackage[super]{nth}% For ordinal numbers, like \nth{1} -> 1^{st}

\RequirePackage{etoolbox}% Programming facilities

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Translations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Providing localization that are not automatically covered by polyglossia.
% The commands are provided by KOMAscript.
% Maintaining the list is not the easiest, but currently likely the best approach.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Colophon
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransCompiledOn}{Compiled on}
\providecaptionname{german}{\TransCompiledOn}{Kompiliert am}

\providecaptionname{english}{\TransLatexClass}{Class}
\providecaptionname{german}{\TransLatexClass}{Klasse}

\providecaptionname{english}{\TransGenerator}{Generator}
\providecaptionname{german}{\TransGenerator}{Generiert durch}

\providecaptionname{english}{\TransCensorNotice}{CENSORED VERSION}
\providecaptionname{german}{\TransCensorNotice}{ZENSIERTE VERSION}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Task
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransPlaceDate}{Place \& Date}
\providecaptionname{german}{\TransPlaceDate}{Ort \& Datum}

\providecaptionname{english}{\TransTopic}{Topic}
\providecaptionname{german}{\TransTopic}{Thema}

\providecaptionname{english}{\TransTask}{Task}
\providecaptionname{german}{\TransTask}{Problemstellung}

\providecaptionname{english}{\TransFor}{For}
\providecaptionname{german}{\TransFor}{Für}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Declaration of Authorship
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransAuthorshipDeclTitle}{Declaration of Authorship}
\providecaptionname{german}{\TransAuthorshipDeclTitle}{Erklärung zur Eigenständigkeit}

%
% No warranty these wordings are valid in your case!
%
\providecaptionname{english}{\TransAuthorshipDeclText}{%
    I, \@author{}, hereby declare to be the sole, independent author of the
    \@documenttype{} submitted here.
    No other than the cited references have been used.
    Any content directly or indirectly obtained from external sources has been marked up as such.
    This thesis has neither been submitted to a second examination authority nor been published.%
}%

\providecaptionname{german}{\TransAuthorshipDeclText}{%
    Hiermit bestätige ich, \@author{}, der alleinige und selbstständige Autor der hier
    vorgelegten \@documenttype{} zu sein.
    Keine anderen als die angegebenen Quellen wurden benutzt.
    Jeglicher aus externen Quellen direkt oder indirekt bezogene Inhalt ist als solcher markiert.
    Diese Arbeit wurde weder einer anderen Prüfungsbehörde vorgelegt noch veröffentlicht.
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Cleveref
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransReaction}{Reaction}
\providecaptionname{german}{\TransReaction}{Reaktion}
\providecaptionname{english}{\TransReactions}{Reactions}
\providecaptionname{german}{\TransReactions}{Reaktionen}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Glossary
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransGreek}{Greek}
\providecaptionname{german}{\TransGreek}{Griech.}

\providecaptionname{english}{\TransRoman}{Roman}
\providecaptionname{german}{\TransRoman}{Röm.}

\providecaptionname{english}{\TransOther}{Other}
\providecaptionname{german}{\TransOther}{Andere}

\providecaptionname{english}{\TransTerms}{Terms}
\providecaptionname{german}{\TransTerms}{Begriffe}

\providecaptionname{english}{\TransNames}{Names}
\providecaptionname{german}{\TransNames}{Namen}

\providecaptionname{english}{\TransAcronyms}{Acronyms}
\providecaptionname{german}{\TransAcronyms}{Akronyme}

\providecaptionname{english}{\TransSubscripts}{Subscripts}
\providecaptionname{german}{\TransSubscripts}{Indizes}

\providecaptionname{english}{\TransSuperscripts}{Superscripts}
\providecaptionname{german}{\TransSuperscripts}{Hochgest.}

\providecaptionname{english}{\TransSubSuperTitle}{Sub- and Superscripts}
\providecaptionname{german}{\TransSubSuperTitle}{Indizes}

\providecaptionname{english}{\TransUnit}{Unit}
\providecaptionname{german}{\TransUnit}{Einheit}

\providecaptionname{english}{\TransPhysicalQuantity}{Phys.\ Qtt.}
\providecaptionname{german}{\TransPhysicalUnit}{Phys.\ Größe}

\providecaptionname{english}{\TransFirstUse}{\nth{1} Use}
\providecaptionname{german}{\TransFirstUse}{Einführ.}

\providecaptionname{english}{\TransShort}{Short}
\providecaptionname{german}{\TransShort}{Kurz}

\providecaptionname{english}{\TransContinued}{continued}
\providecaptionname{german}{\TransContinued}{fortgesetzt}

\providecaptionname{english}{\TransGlossaryLegend}{
    Marked (\specificsymbolmark) symbols possess a mass\-/specific variant in which
    the symbol is written in lowercase and the unit is extended by
    \unit[per-mode=reciprocal]{\per\kilogram}.
    Alternative symbols are specified following the \alternativesymbolmark{} mark.
    International symbols are specified in brackets.%
}
\providecaptionname{german}{\TransGlossaryLegend}{
    Markierte (\specificsymbolmark) Symbole besitzen eine massenspezifische Variante,
    bei der das Symbol als Kleinbuchstabe gesetzt und die Einheit entsprechend um
    \unit[per-mode=reciprocal]{\per\kilogram} erweitert wird.
    Alternative Symbole sind nach \alternativesymbolmark{} angegeben,
    internationale Symbole in eckigen Klammern.%
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SCRLayer
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransBlankPage}{Rest of this page intentionally left blank.}
\providecaptionname{german}{\TransBlankPage}{Rest der Seite absichtlich freigelassen.}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Lists of ...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransIllustrativeElements}{Illustrative Elements}
\providecaptionname{german}{\TransIllustrativeElements}{Veranschaulichende Elemente}

\providecaptionname{english}{\TransListOfIllustrations}{List of Illustrations}
\providecaptionname{german}{\TransListOfIllustrations}{Illustrationsverzeichnis}

\providecaptionname{english}{\TransListing}{Code Listing}
\providecaptionname{english}{\TransListings}{Code Listings}% Plural for cleveref

\providecaptionname{german}{\TransListing}{Code}
\providecaptionname{german}{\TransListings}{Codes}% Plural for cleveref

\providecaptionname{english}{\TransListOfListings}{List of Code}
\providecaptionname{german}{\TransListOfListings}{Codeverzeichnis}

\providecaptionname{english}{\TransListOfExamples}{List of Examples}
\providecaptionname{german}{\TransListOfExamples}{Beispielverzeichnis}

\providecaptionname{english}{\TransExample}{Example}
\providecaptionname{german}{\TransExample}{Beispiel}
\providecaptionname{english}{\TransExamples}{Examples}
\providecaptionname{german}{\TransExamples}{Beispiele}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Bibliography
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransFurtherReadingTitle}{Further Reading}
\providecaptionname{german}{\TransFurtherReadingTitle}{Weitere Literatur}

\providecaptionname{english}{\TransFurtherReadingText}{%
    The following references were used in this work but not cited in the text body;
    they are provided here as\-/is.
}
\providecaptionname{german}{\TransFurtherReadingText}{%
    Die folgenden Quellen wurden im Rahmen dieser Arbeit benutzt, jedoch nicht
    explizit zitiert.
    Sie sind hier der Vollständigkeit halber aufgeführt.
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Other
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\providecaptionname{english}{\TransConstant}{const}
\providecaptionname{german}{\TransConstant}{konst}

\providecaptionname{english}{\TransAdaptedFrom}{Adapted from}
\providecaptionname{german}{\TransAdaptedFrom}{Adaptiert von}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tweaks and improvements for amsmath; also loads amsmath.
% Needs to be loaded before unicode-math!
\RequirePackage{mathtools}
    % We want to be cool, so standard parantheses don't cut it:
    \newtagform{brackets}{[}{]}
    \usetagform{brackets}

    % Allow multi-line environments to break across pages.
    % While it makes sense to disallow it, not doing so can produce big spacing issues.
    % Usually, any such environment will require manual attention.
    % Number from 1 to 4 as optional argument:
    % [1]: allow pagebreaks, but avoid as much as possible.
    % [4]: maximum permissiveness
    \allowdisplaybreaks[2]

    % Automatic macro for delimiters (parentheses, brackets, ...)
    % Using the starred variant of the created command (like \parens*{<content>})
    % also scales the delimiters automatically, using \left and \right.
    \DeclarePairedDelimiter{\parens}{(}{)}
    \DeclarePairedDelimiter{\brackets}{[}{]}
    \DeclarePairedDelimiter{\braces}{\{}{\}}

% For a 'cases' environment that also supports equation numbering,
% https://tex.stackexchange.com/a/180910/120853
\RequirePackage{empheq}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Colour
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Load this before unicode-math font specifications to make colors available there
\RequirePackage[x11names]{xcolor}% x11names provides some usable default names
    % Shades of grey (we don't need 50 though)
    % This is nice to have consistent color shading.
    \colorlet{g1}{black!70}
    \colorlet{g2}{black!55}
    \colorlet{g3}{black!40}
    \colorlet{g4}{black!20}
    \colorlet{g5}{black!10}
    \colorlet{g6}{black!05}

    % Different fluids/materials.
    \definecolor{Glass}{RGB}{170, 238, 255}% Very light blue
    \definecolor{Air}{RGB}{213, 246, 255}% Light blue
    \definecolor{LightFluid}{RGB}{148, 224, 255}
    \definecolor{MediumFluid}{RGB}{135, 178, 232}
    \definecolor{DarkFluid}{RGB}{119, 151, 197}
    \definecolor{HotFluid}{RGB}{255, 128, 128}% 255/128/128 is same as 'red!50'

    % Dark blue link color:
    \definecolor{darklink}{RGB}{48, 62, 116}%

    % From colorbrewer's RdYlBu: from red (1) to blue (6)
    \definecolor{rdylbu1}{RGB}{215,  48,  39}%
    \definecolor{rdylbu2}{RGB}{252, 141,  89}%
    \definecolor{rdylbu3}{RGB}{254, 224, 144}%
    \definecolor{rdylbu4}{RGB}{224, 243, 248}%
    \definecolor{rdylbu5}{RGB}{145, 191, 219}%
    \definecolor{rdylbu6}{RGB}{ 69, 117, 180}%

    % From colorbrewer's Set2 for qualitative data/color discernibility
    \definecolor{Set2A}{RGB}{102, 194, 165}%
    \definecolor{Set2B}{RGB}{252, 141,  98}%
    \definecolor{Set2C}{RGB}{141, 160, 203}%
    \definecolor{Set2D}{RGB}{231, 138, 195}%
    \definecolor{Set2E}{RGB}{166, 216,  84}%
    \definecolor{Set2F}{RGB}{255, 217,  47}%
    \definecolor{Set2G}{RGB}{229, 196, 148}%
    \definecolor{Set2H}{RGB}{179, 179, 179}%

    % Matlab colours:
    \definecolor{mBlue}{HTML}{0072BD}
    \definecolor{mOrange}{HTML}{D95319}
    \definecolor{mYellow}{HTML}{EDB120}
    \definecolor{mPurple}{HTML}{7E2F8E}
    \definecolor{mGreen}{HTML}{77AC30}
    \definecolor{mSky}{HTML}{4DBEEE}
    \definecolor{mRed}{HTML}{A2142F}

    % Code annotations:
    \definecolor{cRed}{RGB}{209,0,86}%
    \definecolor{cBlue}{RGB}{0, 130, 185}%
    \definecolor{cGreen}{RGB}{0, 128, 63}%
    \definecolor{cOrange}{RGB}{244, 131, 66}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Typeset code snippets
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% minted is a Python-based syntax highlighter and therefore much, much more powerful
% than anything LaTeX-built-in
\RequirePackage[%
    % `minted` uses the `float` package to provide the `[H]` float position specifier.
    % Sadly, the `float` package is incompatible with `floatrow`, which we make heavy
    % use of. Luckily, we can use `minted` with the `newfloat` package instead, fixing
    % all those otherwise breaking issues.
    % See https://tex.stackexchange.com/a/378588/120853
    newfloat=true,%
]{minted}

    \setminted{% Global `minted` aka code syntax highlighting options
        % If code is indented in the LaTeX source, this is reflected in the print.
        % This option automatically removes as much whitespace as the first line of a listing
        % is indented by (note: requires `python` to be available, not only `pygmentize`)
        autogobble=true,
        %
        % Assuming the code to be displayed is written at 80-90 characters per line,
        % \footnotesize makes sure it fits onto one line (roughly).
        fontsize=\footnotesize,
        %
        breaklines=true,
        breakanywhere=false, % default "false"; could be ugly, only use if required
        breakbytokenanywhere=true, % Breaks tokens on non-spaces too
        %
        % Regular LaTeX can occur in these (on UK Keyboard: SHIFT+`).
        % Otherwise, you'll have to copy-paste this whenever needed.
        % The problem is that the escapechar has to be quite exotic so it never occurs
        % in source code.
        escapeinside=¬¬,
        %
        frame=leftline, % leftline pulls it together visually quite nicely
        framerule=1pt, % default is 0.4pt
        rulecolor=\color{g3},
        %
        numbers=left,
        numberfirstline=true, % Always color the first line despite `stepnumber` setting
        stepnumber=5, % Interval of line numbering
        numbersep=2pt, % Horizontal distance between line number and line
        %
        % Used highlighting style, see https://pygments.org/demo/#try or `python -m pygments -L`
        % For colorful output, I like:
        % `paraiso-light` (prob. too light for print), `manni`, `tango`, `lovelace`
        % For grayscale:
        % `algol`
        style=manni,
    }

    \setmintedinline{% Overwrite `\setminted` settings
        fontsize=auto,% Reset to surrounding font size so its fits into the text flow
    }

    % Set up the floating environment, e.g. what is says in the caption of floats:
    \SetupFloatingEnvironment{listing}{% Requires `newfloat` usage
        name=\TransListing{},
        listname=\TransListOfListings{},
    }
    % Create a new environment for breaking code listings across pages.
    \newenvironment{longlisting}{\captionsetup{type=listing}}{}
    % Setup for referencing the floats correctly is done in `cleveref` settings!

    % In code environments, to be able to copy from the PDF (despite that not being a good
    % idea usually), we want the line numbers to not be part of the selection.
    % This command prints them, but renders the actual copied content empty,
    % on supported readers like Adobe Acrobat.
    \RequirePackage{accsupp}% https://tex.stackexchange.com/a/57160/120853

    \newcommand*{\emptyaccsupp}[1]{%
        \BeginAccSupp{ActualText={}}#1\EndAccSupp{}%
    }%

    \renewcommand*{\theFancyVerbLine}{ % Redefine how line numbers are printed
        \textcolor{g3}{\ttfamily\tiny\emptyaccsupp{\arabic{FancyVerbLine}}}
    }

    % Colors for escaped, normal LaTeX in code environments
    \newcommand*{\phstring}[1]{%
        \textcolor{cRed}{#1}%
    }%
    \newcommand*{\phnum}[1]{%
        \textcolor{cBlue}{#1}%
    }%
    \newcommand*{\phother}[1]{%
        \textcolor{cGreen}{#1}%
    }%
    \newcommand*{\phnote}[1]{%
        {%
            \hypersetup{allcolors=cOrange}% If references occur in here
            \textbf{\textcolor{cOrange}{#1}}%
        }%
    }%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TODO notes in the PDF
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{todonotes}% TODO-notes in the margins
    \setuptodonotes{fancyline}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Fonts
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage[
    warnings-off={
        % Unicode overwrites colon-commands but uses over/underbracket from mathtools
        % and warns us; suppress this:
        mathtools-colon,%
        mathtools-overbracket,%
    }
]{unicode-math}% Builds onto fontspec and loads it automatically

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Fonts shipped with TeXLive from here: https://tug.org/FontCatalogue/
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\setmainfont[%
    Numbers=Lowercase,% Hanging/OldStyle numbers through Lowercase numbers
    % Color=Orange2,% Toggle color for debugging (should be xcolor name)
]{TeX Gyre Pagella}% Load existing fond, see also https://tex.stackexchange.com/a/351100/120853
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Source: https://fonts.google.com/specimen/Inconsolata
% (Consolas is considered better but is not free (?))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\setmonofont[%
    % Inconsolata doesn't have italics font, so fake it. Discouraged but should
    % only occur in a few places in code and not be noticable there. Inconsolata
    % is too nice to give up on it for lack of italics. See also
    % https://tex.stackexchange.com/a/183220/120853
    AutoFakeSlant,
    Scale=MatchLowercase,% Prettier when using inline-code alongside our main font
    % Color=DodgerBlue3,% Toggle color for debugging (should be xcolor name)
]{inconsolata}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Source: https://www.exljbris.com/fontinsans.html
% Viable alternative: https://fonts.google.com/specimen/Fira+Sans
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\setsansfont[%
    % Color=Red3,% Toggle color for debugging (should be xcolor name)
]{Merriweather Sans}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Source: https://ctan.org/texarchive/fonts/tex-gyre-math/opentype
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\setmathfont[%
    %Set math-font-commands to new versions; use \symbf{} instead of \mathbf{} etc:
    mathrm=sym,%
    mathit=sym,%
    mathsf=sym,%
    mathbf=sym,%
    mathtt=sym,%
    % 'tpgl': 'TexGyrePagellaLining'.
    % This 'NFSS' style is required for \fontfamily{nfss-code}\selectfont to work,
    % e.g. in package chemmacros/chemformula
    NFSSFamily=tgpl,%
    % Color=Green4,% Toggle color for debugging (should be xcolor name)
]{TeX Gyre Pagella Math}% Load existing fond, see also https://tex.stackexchange.com/a/351100/120853

% Provide a new font family for siunitx to work.
% See: https://tex.stackexchange.com/a/468031/120853.
% \newfontfamily is used similarly to \setmainfont etc,
% see: https://tex.stackexchange.com/a/12568/120853
\newfontfamily{\unitnumberfont}[
    % New font family for typesetting units.
    % Required since otherwise, numbers typeset with \qty/\num etc. from siunitx
    % might be hanging if that feature is turned on in the main font (OldStyle numbers).
    % To ensure these physical numbers are always upright, set Numbers:
    Numbers=Uppercase,
    % Color=LightCyan4,% Toggle color for debugging (should be xcolor name)
]{TeX Gyre Pagella}% Load existing fond, see also https://tex.stackexchange.com/a/351100/120853

% Looking at CTAN, `fontawesome5' looks much more recent and packs many more symbols
% in comparison to `fontawesome'.
% It ships with its own font files, so no need to specify here.
\RequirePackage{fontawesome5}% High-quality Unicode vector web symbols

% Wrapper for "i.e.", "e.g.", "c.f.", "etc.", etc.
% Call this command as "The animals, \iecfeg{e.g.}\ an elephant, are..."
% to get a small space after the ending period.
% We do not define dedicated commands here (like \eg or \etc) to print that stuff
% automatically, since there are way too many exceptions and caveats.
% Such macros are not worth it because the requirements change too much from use to use
%  (different languages, capitalisation, ending dot if abbreviation is at end of
% sentence, ...).
% It is left to the user to do the specifics.
% This macro just makes sure it is all in italics.
\newcommand*{\iecfeg}[1]{\textit{#1}}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% System Information Banner
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Provides \hologo and \Hologo to typeset various logos, like the LuaLaTeX logo.
\RequirePackage{hologo}

% Using fontspec, this document is incompatible with anything but XeLaTeX/LuaLaTeX.
% LuaLaTeX can grab additional memory as needed, therefore no issues with tikz and no
% need to tikzexternalize (!).
% Further, contour-package and XeLaTeX are strictly incompatible (LuaLaTeX works).
% Therefore, only ever use LuaLaTeX anyway.

\RequirePackage{xstring}% String manipulation macros

% Print only what occurs after 'This is ' and store in macro given in brackets at end.
% luatexbanner is provided by luatex engine, but prints 'This is luatex XYX' usually.
% https://tex.stackexchange.com/a/394043/120853
\StrBehind*{\luatexbanner}{This is }[\shortbanner]

% Take input and substitute strings; here: make plain LuaTeX string into pretty logo.
% StrSubstitue has no starred variant, therefore dekotenize.
% https://tex.stackexchange.com/a/350583/120853
\StrSubstitute{\shortbanner}{\detokenize{LuaTeX}}{\hologo{LuaTeX}}[\prettybanner]

% Generate some control sequences which contain metadata, which can be inserted e.g.
% into the PDF metadata (e.g. to have the exact git commit SHA of a build).
% See % https://www.overleaf.com/learn/latex/Articles/An_Introduction_to_LuaTeX_(Part_2):_Understanding_%5Cdirectlua
% for how to inline Lua code in TeX.
% It's an absolute abomination; the below code first passes through TeX, gets expanded,
% then gets processed by Lua.
% Hence, there is a lot of escaping going on.
\directlua{%
    local function get_cmd_stdout(cmd)
        % -- See: https://stackoverflow.com/a/326715/11477374
        local fh = assert(io.popen(cmd))
        local first_line = assert(fh:read())
        fh:close()
        return first_line
    end
%
    % -- Environment variables as used e.g. in GitLab CI.
    % -- Otherwise, e.g. when developing locally, use commands as a fallback.
    local macro_content_sources = {
        GitRefName = {
            env = "CI_COMMIT_REF_NAME",
            cmd = "git rev-parse --abbrev-ref HEAD",
        },
        GitShortSHA = {
            env = "CI_COMMIT_SHORT_SHA",
            cmd = "git rev-parse --short HEAD",
        },
    }
%
    for macro_name, content_sources in pairs(macro_content_sources) do
        % -- Default: check for environment variable:
        local env = content_sources.env
        local cmd = content_sources.cmd
        % -- Default value:
        local content = "n.a."
        local env_content = os.getenv(env)
%
        % -- Empty string evaluates to true:
        if env_content and env_content \noexpand~= "" then
            texio.write_nl("Found and will be using environment variable '"..env.."'.")
            content = env_content
        else
            texio.write_nl("Environment variable '"..env.."' undefined or empty, trying fallback command.")
            % -- luatex reference for shell escape:
            % -- "0 means disabled, 1 means anything is permitted, and 2 is restricted"
            if status.shell_escape == 1 then
                local cmd_success, cmd_stdout = pcall(get_cmd_stdout, cmd)
                if cmd_success then
                    texio.write_nl("Fallback command '"..cmd.."' succeeded.")
                    content = cmd_stdout
                else
                    texio.write_nl("Fallback command '"..cmd.."' unsuccessful.")
                end
            else
                texio.write_nl("shell-escape is disabled, cannot use fallback command.")
            end
        end
%
        % -- Shouldn't happen, would be programmer error, therefore assert Python-style
        assert(content, "Content not defined (neither success nor fallback present)")
%
        % --[[
        %     The `content` can contain unprintable characters, like underscores in git branch
        %     names. Towards this end, use detokenize in the macro itself, which will make all
        %     characters printable (assigns category code 12). See also:
        %     https://www.overleaf.com/learn/latex/Articles/An_Introduction_to_LuaTeX_(Part_2):_Understanding_%5Cdirectlua
        % --]]
        local escaped_content = "\unexpanded{\\detokenize{"..content.."}"}
%
        texio.write_nl("Providing new macro '"..macro_name.."' with contents: '"..escaped_content.."'.")
        % --  Set a macro (newcommand) see also: https://tex.stackexchange.com/a/450892/120853
        token.set_macro(macro_name, escaped_content)
    end
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Macros to pretty-print keyboard buttons and menu navigation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage[
    os=win,% Default is `mac`
]{menukeys}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% KOMA Layout, Sectioning etc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% label, e.g. 'Chapter', appearing before the chapter number:
\addtokomafont{chapterprefix}{\raggedleft}

\renewcommand*{\chapterformat}{%
    \color{g3}% g3 is a shade of grey
    %
    % chapappifchapterprefix{addtext} checks if 'chapterprefix=true' is active,
    % then prints 'Chapter' or 'Appendix' in front of number,
    % followed by more text 'addtext':
    \chapappifchapterprefix{~}% ~ is an unbreakable space character
    %
    % Autodot automates the generation of a dot/period, like \thechapter\autodot.
    % Leave out for no dot.
    \scalebox{4.5}{\thechapter}
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Titlepage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Define new font for the title page, so it is created once (\newkomafont)
% and can later be set however often required (\setkomafont)
\newkomafont{documenttype}{\usekomafont{subtitle}\footnotesize}

% Emulating a budget 'case' switch statement here

% \ifstrequal from etoolbox doesn't work, it does not expand macros.
% Use \ifdefstring from same package,
% see also https://tex.stackexchange.com/a/451937/120853

\ifdefstring{\acp@titlestyle}{thesis}{
    % These exist already, overwrite:
    \setkomafont{title}{\sffamily\bfseries\Huge}
    \setkomafont{subtitle}{\normalfont\normalsize\sffamily}
    \setkomafont{author}{\sffamily\bfseries}
    \setkomafont{publishers}{\sffamily}
%
    % One same line as subtitle, so should look the same; inherit style:
    \setkomafont{date}{\usekomafont{subtitle}}
%
    \setkomafont{documenttype}{\usekomafont{subtitle}\footnotesize}
%
    \renewcommand{\maketitle}{%
        \begin{titlepage}
            \hfill%
            %
            % 2nd optional argument is height, required for \vfill etc. to work
            \begin{minipage}[b][1\textheight]{0.05\textwidth}%
                \color{black}\rule{0.15em}{\textheight}% Vertical line
                \hfill%
            \end{minipage}% This comment char is important to suppress linebreak
            %
            \begin{minipage}[b][1\textheight]{0.75\textwidth}
                \vspace{4\baselineskip}
                {\usekomafont{documenttype}\faGraduationCap{}\ \@documenttype{}\hspace{0.5em}}
                \hrulefill
                \begin{spacing}{1.1}% In case of multi-line titles, more relaxed spacing
                    \usekomafont{title}\raggedright\@title
                \end{spacing}
                \hrule
                \vspace{0.8\baselineskip}
                {%
                    \usekomafont{author}%
                    % Tabular enables \and and \\ syntax
                    \begin{tabular}[t]{@{}l@{}}%
                        \@author
                    \end{tabular}
                }%
                \hfill
                {\usekomafont{date}\@date}\par
                \vfill
                {\usekomafont{subtitle}\@subtitle}\par
                \vspace{2\baselineskip}
                {%
                    \usekomafont{publishers}%
                    \begin{tabular}[t]{@{}l@{}}%
                        \@publishers
                    \end{tabular}
                }\par
                \vspace{0.2ex}% Also required for \vfill as something to 'fill against'
            \end{minipage}
        \end{titlepage}
    }%
}{%
    % Else: nothing; faking a 'case' environment
}

\ifdefstring{\acp@titlestyle}{book}{
    % These exist already, overwrite:
    \setkomafont{title}{\sffamily\bfseries\Huge}
    \setkomafont{subtitle}{\itshape}
    \setkomafont{author}{\scshape\Large}
    \setkomafont{date}{\normalfont\normalsize\sffamily}
    \setkomafont{publishers}{\scshape}
%
    % One same line as date, so should look the same; inherit style:
    \setkomafont{documenttype}{\usekomafont{date}}
%
    \renewcommand{\maketitle}{%
        \begin{titlepage}
            \hfill%
            %
            % 2nd optional argument is height, required for \vfill etc. to work
            \begin{minipage}[b][1\textheight]{0.05\textwidth}%
                \color{black}\rule{0.15em}{\textheight}% Vertical line
                \hfill%
            \end{minipage}% This comment char is important to suppress linebreak
            %
            \begin{minipage}[b][1\textheight]{0.75\textwidth}
                \vspace{2\baselineskip}
                {\usekomafont{author}
                    % Tabular enables \and and \\ syntax
                    \begin{tabular}[t]{@{}l@{}}%
                        \@author
                    \end{tabular}
                }\par
                \vspace{1.5\baselineskip}
                \begin{spacing}{1.1}% In case of multi-line titles, more relaxed spacing
                    \usekomafont{title}\raggedright\@title
                \end{spacing}
                \hrule
                \vspace{0.8\baselineskip}
                {\usekomafont{documenttype}\@subtitle}
                \hfill
                {\usekomafont{date}\@date}\par
                \vfill
                {\usekomafont{publishers}
                \begin{tabular}[t]{@{}l@{}}%
                    \@publishers
                    \end{tabular}
                }\par
                \vspace{0.2ex}% Also required for \vfill as something to 'fill against'
            \end{minipage}
        \end{titlepage}
    }%
}{
    % Else: nothing; faking a 'case' environment
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% tocbasic
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Dynamic width of number column in LoF/LoT etc (numsep + width of longest entry).
% 'tocline' is the (dynamic) default style.
\DeclareTOCStyleEntry[dynnumwidth=true]{tocline}{figure}
\DeclareTOCStyleEntry[dynnumwidth=true]{tocline}{table}

% Declare a new list of contents, with the file suffix in brackets.
% This will give access to \listof<name>s
\DeclareNewTOC[%
    type=example,% This also creates types=example+s, that is by appending an s
    % Listname is "List of <Type>s" by default, therefore translate:
    listname={\TransListOfExamples{}},
]{loe}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SCRLayer for page makeup (header/footer etc.)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage[automark]{scrlayer-scrpage}% Automatically mark

\clearpairofpagestyles % Reset defaults

% Declare new length (acting as a height) for the vertical bar in the header:
\newlength{\headerrulelength}
% Increase height of rule here; KOMA Script will complain, no idea how to fix
\setlength{\headerrulelength}{3ex}

% New command for the vertical rule, with height as specified by the new length above:
\newcommand*{\headerrule}{%
    \rule[-1ex]{0.1em}{\headerrulelength}%
}%

% Define headers:
\lehead{% Left, even head
    \llap{%
        \pagemark\enskip\headerrule%
    }%
    \enskip\headmark%
}%

\rohead{% Right, odd head
    \headmark\enskip%
    \rlap{%
        \headerrule\enskip\pagemark%
    }%
}%

% https://tex.stackexchange.com/q/299125/120853:
\renewcommand*{\chaptermarkformat}{\thechapter\enskip}%

\addtokomafont{pagehead}{\sffamily\itshape\footnotesize}%
\addtokomafont{pagenumber}{\sffamily\bfseries\footnotesize}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Deliberately blank pages with message
% Occurs if new chapter starts (opens right) but previous chapter ended on
% a recto (right) page itself.
% The intermediate left page will be blank; leave a message that this is intentional.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand*{\blankpage}{% https://tex.stackexchange.com/a/205536/120853
    \par\vspace*{\fill}%
    \begin{center}
        \textcolor{g2}{%
            \TransBlankPage{}% See translations file
        }%
    \end{center}
}%

\DeclareNewLayer[% Create new layer under some name
    foreground,%
    textarea,%
    contents=\blankpage,%
]{blankpage.fg}

\DeclarePageStyleByLayers{blank}{blankpage.fg}% Make layer available as pagestyle
\KOMAoptions{cleardoublepage=blank}% Use pagestyle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Typesetting
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Using 'shortcuts' package option, do e.g. 'fast\-/paced' to get a breakable
% 'fast-pace' word in print.
% Otherwise, LaTeX does not hyphenate/linebreak words that already come with a hyphen,
% since that could be ambiguous
\RequirePackage[shortcuts]{extdash}

\RequirePackage{microtype}% Advanced typesetting for kerning etc.

% Dummy text in readable English (Other languages are also detected)
% Provides a more realistic preview than Lorem Ipsum
\RequirePackage{blindtext}

\RequirePackage{pdflscape}% Pages in landscape format

\RequirePackage{url}% Escaping special chars as URL

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Language Support
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{polyglossia}% Language rules. Replacement for babel in lualatex
    % Expand this properly; the version without \expandsafters does not work fully.
    % It works this way:
    % The first \expandafter is seen, so the following \setdefaultlanguage is not
    % expanded and skipped.
    % Next, the second \expandafter is looked at. It sees the token { next, saving it
    % for later.
    % \acp@language is then expanded fully, to the current language.
    % What is left is a properly working string, \setdefaultlanguage{<language string>}
    \expandafter\setdefaultlanguage\expandafter{\acp@language }

    % Whatever main language (setmainlanguage = setdefaultlanguage) was loaded, we want
    % the "other" one (since we expect only English and German) to be available as a
    % secondary language. This is very convenient if for example a thesis is in English,
    % but certain parts have to be in German, e.g. for legal reasons. A simple switch
    % \begin{german} ... \end{german} would then achieve that.
    \setotherlanguages{german,english}

% Proper quotation support, mainly through \enquote
\RequirePackage[
    autostyle=true,% true always adapts quotes to current language
]
{csquotes}
    % Add itshape to beginning (beg) of display quote environments:
    \renewcommand*{\mkbegdispquote}[2]{\itshape}

\RequirePackage[inline]{enumitem}% Custom list environments
    \setlist{noitemsep}% No vertical spacing in lists
    \setlist[1]{labelindent=\parindent}% Indent lists by paragraph indent
    % Refer to unimath_symbols.pdf for source of \smblksquare etc.:
    % https://ctan.org/texarchive/macros/latex/contrib/unicode-math
    \setlist[itemize,1]{label=\smblksquare}%
    \setlist[enumerate]{font=\sffamily\bfseries}

    % For compact itemize lists within table cells:
    \newlist{tabitemize}{itemize}{1}% Second argument is max. depth
    \setlist[tabitemize]{%
        label=\smblksquare,%
        nosep,% nosep kills all vertical spacing
        align=parleft,
        leftmargin=*,
        % https://tex.stackexchange.com/a/443573/120853,
        % but before=\compress didn't work:
        after=\vspace{-\baselineskip},
        before=\vspace{-0.75\baselineskip},% Hacky manual parameter
    }

    % For compact enumerations lists within table cells:
    \newlist{tabenum}{enumerate}{1}% Second argument is max. depth
    \setlist[tabenum]{
        label={\arabic*.},
        font=\sffamily\bfseries,
        leftmargin=*,
        nosep,% nosep kills all vertical spacing
        align=parleft,
        % https://tex.stackexchange.com/a/443573/120853,
        % but before=\compress didn't work:
        after=\vspace{-\baselineskip},
        before=\vspace{-0.75\baselineskip},% Hacky manual parameter
    }

    % An enumerated description list:
    % https://tex.stackexchange.com/a/30035/120853
    \newcounter{descriptcount}
    \newlist{enumdescript}{description}{2}% Derive from existing description env.
    \setlist[enumdescript, 1]{% Set first level action
        before={%
            \setcounter{descriptcount}{0}%
            % \renewcommand*\thedescriptcount{\alph{descriptcount}}%
        },
        font={\bfseries\stepcounter{descriptcount}\thedescriptcount.~}
    }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Floats
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Does \centering automatically, provides side captions (fcapside) and much more.
\RequirePackage{floatrow}

\floatsetup{footposition=bottom}% For all floats

\floatsetup[longtable]{LTcapwidth=table}% https://tex.stackexchange.com/a/345772/120853

\floatsetup[table]{%
    style=plaintop,% Always above, no matter where \caption is called
    footnoterule=none,%
    footskip=.35\skip\footins,%
}%

\floatsetup[figure]{%
    capbesideposition=right,%
    capbesidesep=quad,%
}%

\floatsetup[subfigure]{style=plain}% Plain style, so no rules

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Float Captions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{caption}

% Will be printed between 'Figure/Table/... XYZ' and the caption text:
\DeclareCaptionLabelSeparator{slash}{\ /\ }% `\ ' (backslash+space) is a short space

\DeclareCaptionFont{ftfont}{%
    \scriptsize%
    \color{g3}%
    \hypersetup{hidelinks}%
    \sffamily\raggedleft%
}%

\captionsetup{% All captions
    format=plain,%
    textformat=period,% Always print period at end
    font=small,% All fonts
    labelfont={sf,bf},%
    labelsep=slash,%
    labelformat=simple,% Just Name/Number, no period or similar
    indention=1em,%
}%

\captionsetup[floatfoot]{%
    footfont=ftfont,% https://tex.stackexchange.com/q/9547/120853
}%

\captionsetup[capbesidefigure]{
    % When using sidecaptions, the linewidth can be rather small and awkward breaks and
    % many underfull hboxes occur. Therefore, raggedright.
    justification=raggedright,
}

\captionsetup[subfigure]{%
    labelformat=simple,% 'parens' uses parantheses, 'brace' just the right one
    labelsep=slash,%
    labelfont={sf,bf},%
    list=off,% list=off removes subfigures from LoF
}%

\captionsetup[subtable]{%
    labelformat=simple,% 'parens' uses parantheses, 'brace' just the right one
    labelsep=slash,%
    labelfont={sf,bf},%
    list=off,% list=off removes subfigures from LoF
}%

% Change counter from Arabic number to letter:
\renewcommand*{\theContinuedFloat}{\alph{ContinuedFloat}}

% Make this new length and indent, same length as regular caption indent:
\newlength{\floatfootruleindent}
\setlength{\floatfootruleindent}{\caption@indent}% Set the new length

% A bit hacky; introduce a rule underneath caption if \floatfoot is called:
\renewcommand*{\floatfootskip}{2pt\hspace{\floatfootruleindent}\hrulefill}%

\RequirePackage{subcaption}% For subfloats

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Bibliography
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage[% Default back-end: biber
    % short style is 'alphabetic' (like [AB99]);
    % longer: 'authoryear' (like (Einstein, 1940)):
    style=authoryear,
    autocite=footnote,% Control what \autocite does
    %
    sortcites=true,% Apply what is specified in sorting=
    % Introduce back references in bibliography:
    % https://tex.stackexchange.com/a/211631/120853
    % Do not use hyperref for this
    backref,
    url=false,% Still prints URL for @online, but nowhere else
    doi=false,%
    isbn=false,%
]{biblatex}%

% The `\addbibresource` command moved to the root *.tex file to work for VSCode's
% LaTeX Workshop extension.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Special Treatment for anything in \nocite{*}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Provides a category/sub-bibliography where all entries that occur in the bib-
% file(s) but were not actually cited occur. Kind of like a "Further Reading".

% New heading
\defbibheading{notcited}{%
    \section*{%
        \TransFurtherReadingTitle{}%
    }%
}%

\defbibnote{further}{%
    \textit{\TransFurtherReadingText{}}%
}%

% https://tex.stackexchange.com/a/280545/120853
\DeclareBibliographyCategory{cited}
\AtEveryCitekey{\addtocategory{cited}{\thefield{entrykey}}}

% A header for when the bibliography is divided per-chapter:
\defbibheading{subbibliography}{%
    \section*{%
        \Cref{refsegment:\therefsection\therefsegment}%
    }%
}%

% https://tex.stackexchange.com/a/477525/120853
\defbibenvironment{bibnonum}{
        \list{%
            %
        }{%
            \setlength{\leftmargin}{\bibhang}%
            \setlength{\itemindent}{-\leftmargin}%
            \setlength{\itemsep}{\bibitemsep}%
            \setlength{\parsep}{\bibparsep}
        }%
    }%
    {\endlist}%
    {\item}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Arrays / Tables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{tabu}% For longtabu in the glossary

\RequirePackage{array}
    \newcolumntype{M}[1]{>{\centering\arraybackslash}m{#1}}% Vert.+Hor. centered cells

    % A command to have a cell with vertical text as a multirow:
    \newcommand*{\multirotatecell}[2]{%
        \multirow{#1}{*}{%
            \begin{tabular}{@{}c@{}}%
                \rotatebox[origin=c]{90}{#2}%
            \end{tabular}%
        }%
    }%

\RequirePackage{tabularray}% Powerful, up and coming package
    \UseTblrLibrary{booktabs}% Get `\toprule` etc. for tabularrays
    \UseTblrLibrary{siunitx}% Get S column type

\RequirePackage{multirow}% Cells spanning multiple rows (like multicolumn)

\RequirePackage{booktabs}% Pretty tables; an absolute must

% More vertical stretch for more relaxed visuals in all tables (global setting)
\renewcommand*{\arraystretch}{1.3}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Other
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Replaces datetime; use regional date format from document language
\RequirePackage[useregional]{datetime2}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Visuals, Graphics, Drawing etc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{censor}
    \ifacp@censoring
        % censor package censors by default; do nothing if censoring requested
        % TeX doesn't have \ifnot or similar, see also
        % https://tex.stackexchange.com/q/386093/120853
    \else
        % Turn off if document option given
        \StopCensoring
    \fi

\RequirePackage{cancel}% Cancel out math in equations

\RequirePackage{setspace}% Line spacing, used for title page
    % To achieve a reasonable 'text color', i.e. 'filled-ness' of the text,
    % adjust line spacing.
    % Recommendation for Palatino fonts (TeX Gyre Pagella is a Palatino clone) is a
    % factor of 1.05.
    % Discussion: https://tex.stackexchange.com/q/31064/120853
    % For German, we might even want to go higher to allow space for the many capital
    % letters.
    % Also note that inline-math will look terrible at too low leading/linespread
    \linespread{1.05}
    \KOMAoption{singlespacing}{true}% Do not apply changed linespread to header/footer

% Print a contour around letters, e.g. black text with a white border on some noisy
% background, so that text remains legible.
% NOT COMPATIBLE WITH XELATEX! Requires pdflatex or lualatex (our case)
\RequirePackage[outline]{contour}
    \contourlength{0.12em}

    \newcommand*{\ctrw}[1]{% Black text, white contour
        \hypersetup{hidelinks}% Hide links, which might be colored
        \contour{white}{\textcolor{black}{#1}}%
    }%

    \newcommand*{\ctrb}[1]{% White text, black contour
        \hypersetup{hidelinks}% Hide links, which might be colored
        \contour{black}{\textcolor{white}{#1}}%
    }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Graphics + Path
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{graphicx}
    % Set a global standard path, so don't specify ourselves each time;
    % only do bitmaps here, vectors are handled by the svg package and its path specs
    \graphicspath{{images/bitmaps/}}

\RequirePackage{svg}
    % See also:
    % https://tex.stackexchange.com/a/158612/120853.
    % pdftexcmds package etc. no longer seems necessary.
    % svg package documentation states that it is a dependency, but done automatically.
    % https://tex.stackexchange.com/a/74693/120853

    % Build failed on my system due to lack of the 'canberra' module,
    % see for a fix: https://askubuntu.com/a/872397/978477

    % Running the document to generate the PDF and PDF_TEX file from the original SVG
    % will require SHELL ESCAPE (--shell-escape), aka elevation.
    % However, after the auxiliary images have been created, they only need to be input;
    % shell-escape will no longer be required.
    \svgpath{images/vectors/}% Analogous to \graphicspath{}
    \svgsetup{%
        inkscapepath=svgsubdir,% Put into subdirectory of where original SVG was found
        % In most cases, we include SVGs that contain no text, then add it in a
        % tikzpicture overlay. Therefore, don't generate *.pdf_tex file.
        % Toggle this back to true wherever needed, on a per-file basis
        inkscapelatex=false,
    }

    % When placing nodes over included SVGs using Tikz,
    % we require some help to debug the positions:
    \newcommand*{\debugtikzsvg}{%
        % This has to be evoked within a TikZ scope of:
        % `\begin{scope}[x={(image.south east)},y={(image.north west)}]`
        % The image we invoke the grid "on top of" needs to be labelled "image":
        \draw[help lines, xstep=0.02,ystep=0.02, opacity=0.5]
            (image.south west) grid (image.north east);
        \draw[gray, thick, xstep=0.1,ystep=0.1, opacity=0.8]
            (image.south west) grid (image.north east);
        %
        \foreach \posfraction in {%
            0, 0.1, ...,1%
        }{%
            \foreach \startpoint/\endpoint/\nodeorientation in {% 2D-grid
                south west/south east/below,%
                north west/north east/above,%
                south east/north east/right,%
                south west/north west/left%
            }{
                \node[\nodeorientation, opacity=0.5]
                    at ($(image.\startpoint)!\posfraction!(image.\endpoint)$)
                    {%
                        \pgfmathparse{int(\posfraction*10)}% Round result
                        \num{\pgfmathresult}%
                    };
            }%
        }%
    }%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Custom Symbols
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{scalerel}% Scale stuff relative to e.g. letters

% Wrapper to include vectors icons by filename and scale them
\newcommand*{\mtlbsmlkicon}[1]{%
    \scalerel*{%
        \includesvg{logos/matlab_simulink/#1}%
    }{%
        X% Scale first argument to height for capital X
    }%
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tikz + Plots
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{pgfplots}% Also loads Tikz

% For advanced table calcs, e.g. 'y expr' to mathematically process input data:
\RequirePackage{pgfplotstable}

\RequirePackage[edges]{forest}% Comprehensive trees

\RequirePackage{tikz-3dplot}

% Only use libraries as needed to keep compilation times low
\usetikzlibrary{%
    positioning,% Relative positioning etc.
    calc,% Calculate distances, coordinates etc.
    shapes, % For cross out
    backgrounds,% Draw on background layer
    fit,% Fit new node around existing coordinates
    decorations,
    arrows,
    arrows.spaced,
    intersections,
    trees,
    circuits.ee.IEC,% Electrical engineering circuits lib
    patterns,
    3d,
    tikzmark,% Marks/coordinates at arbitrary positions
}%
\usepgfplotslibrary{%
    colorbrewer,%
    units,%
    dateplot,
    fillbetween,
    groupplots,
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Colour Cycle for plots
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\pgfplotscreateplotcyclelist{mod RdYlBu3}{% Modify existing colorbrewer
    {rdylbu2},
    {black!50},
    {rdylbu5}% No comma or space here!
}%

\pgfplotscreateplotcyclelist{mod mark list}{% Modify predefined to start without mark
    every mark/.append style={solid,fill=\pgfplotsmarklistfill}\\
    every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=*\\
    every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=square*\\
    every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=triangle*\\
    every mark/.append style={solid},mark=star\\
    every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=diamond*\\
    every mark/.append style={solid,fill=\pgfplotsmarklistfill!40},mark=otimes*\\
    every mark/.append style={solid},mark=|\\
    every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=pentagon*\\
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Global plot settings
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\pgfplotstableset{col sep=comma}% If ALL files/tables are comma-separated

\pgfplotsset{%
    % Version this document was originally created with;
    % see also https://tex.stackexchange.com/a/81912/120853
    % Important for reproducibility
    compat=1.16,
    % In case nodes reach out of plot area, dont clip them off.
    % See: https://tex.stackexchange.com/a/127904/120853 and
    % https://tex.stackexchange.com/a/311194/120853
    clip mode=individual,
    label style={font=\small},% https://tex.stackexchange.com/a/300673/120853
    tick label style={%
        font=\small,%
        /pgf/number format/1000 sep={\,}% Small space instead of comma
    },
    cycle multi list={%
        mod mark list\nextlist% Just in case; likely never reached
        linestyles*\nextlist
        % Iterate through last one first; if at end,
        % start anew using next in parent (linestyles *):
        mod RdYlBu3%
    },%
    colormap/viridis,% For 3D/surf plots
    legend style={%
        at={(0.5,1.05)},% Center hor. (0.5), slightly out of drawing(>1 vert.)
        anchor=south,%
        legend columns=-1,% -1 means only rows, as many columns as required
        font=\footnotesize,%
        draw=none,% Do not draw box
        fill=none,% No white fill. Important for gray backgrounds
    },%
    % These comment lines (visual separation) are super important.
    % Empty lines will throw errors here!
    unit code/.code 2 args={\unit{#1#2}},% Use siunitx for units library
    unit markings={slash space},% The proper way... apparently?
    %
    % Fix micro unit display, see https://tex.stackexchange.com/a/224574/120853:
    x SI prefix/micro/.style={/pgfplots/axis base prefix={axis x base 6 prefix \micro}},
    y SI prefix/micro/.style={/pgfplots/axis base prefix={axis y base 6 prefix \micro}},
    z SI prefix/micro/.style={/pgfplots/axis base prefix={axis z base 6 prefix \micro}},
    %
    % Plot styles:
    regularplot/.style={% A broadly usable, regular plot
        ultra thick,
        axis line style=thick,
        ymajorgrids=true,
        xmajorgrids=true,
        grid style=dashed,
        axis lines=left,
        % scale only axis,% If off, labels are taken into account for size calculations
        ytick align=outside,% Puts ticks outside the plot itself
        xtick align=outside,%
        % Won't work if enlarge limits are invoked before 'axis lines left':
        enlargelimits=0.05,
    },%
    plainplot/.style={%
        % A clean, simple plot when numerical values and labels don't matter
        regularplot,
        xmajorgrids=false,
        ymajorgrids=false,
        ticks=none,% No ticks with numbers
    },
    tuftelike/.style={% https://tex.stackexchange.com/a/155210/120853
        axis line shift=10pt,% Also shifts label automatically
        try min ticks=3,% https://tex.stackexchange.com/a/95753/120853
        max space between ticks=50,% High number so ticks are far apart
        axis lines=left,
        ultra thick,
        axis line style = {semithick, -},% '-' suppresses arrow
        tick style = {semithick, black},%
        ytick align=inside,% Puts ticks inside the plot itself
        xtick align=inside,%
        xtick={%
            % Always set min, max and middle ticks;
            % if more desired, use 'extra x ticks={}'
            \pgfkeysvalueof{/pgfplots/xmin},
            \pgfkeysvalueof{/pgfplots/xmax},
            (\pgfkeysvalueof{/pgfplots/xmax}+\pgfkeysvalueof{/pgfplots/xmin})/2
        },
        ytick={% Same as x
            \pgfkeysvalueof{/pgfplots/ymin},
            \pgfkeysvalueof{/pgfplots/ymax},
            (\pgfkeysvalueof{/pgfplots/ymax}+\pgfkeysvalueof{/pgfplots/ymin})/2
        },
        clip = false,% https://tex.stackexchange.com/a/311194/120853
    },%
    % Unfortunately, decorations lib is relatively verbose:
    arrowplot/.style={
        decoration={
            markings,
            mark=at position 0.25 with {\arrow{#1}},
            mark=at position 0.5 with {\arrow{#1}},
            mark=at position 0.75 with {\arrow{#1}},
        },
        postaction=decorate,
    },
    %
    log x ticks with fixed point/.style={%
        % Logarithmic plot, but with linear labels instead of scientific notation
        % (10^2 becomes 100 etc.)
        % https://tex.stackexchange.com/a/139084/120853
        xticklabel={
            \pgfkeys{/pgf/fpu=true}
            \pgfmathparse{exp(\tick)}%
            \pgfmathprintnumber[fixed relative, precision=3]{\pgfmathresult}
            \pgfkeys{/pgf/fpu=false}
        }
    },
    %
    log y ticks with fixed point/.style={
        yticklabel={
            \pgfkeys{/pgf/fpu=true}
            \pgfmathparse{exp(\tick)}%
            \pgfmathprintnumber[fixed relative, precision=3]{\pgfmathresult}
            \pgfkeys{/pgf/fpu=false}
        }
    }
}

% Required in \tikset body for node placing at x style.
% Requires intersection lib
% https://tex.stackexchange.com/a/93968/120853
\def\parsenode[#1]#2\pgf@nil{%
    \tikzset{label node/.style={#1}}
    \def\nodetext{#2}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Various thermodynamic/mechanical/technical shapes, usable in regular TikZ graphics.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\tikzset{
    >=stealth',% Global arrow style
    %
    % Flow chart styles
    startstop/.style={%
        rectangle,
        rounded corners,
        minimum width=40mm,
        minimum height=1cm,
        text centered,
        draw=black,
        fill=red!30,
    },
    io/.style={%
        ellipse,
        minimum width=35mm,
        minimum height=10mm,
        text width=35mm,
        text centered,
        inner xsep=-1ex,
        draw=black,
        fill=blue!30,
    },
    process/.style={%
        rectangle,
        minimum width=40mm,
        minimum height=1cm,
        text centered,
        text width=40mm,
        draw=black,
        fill=orange!30,
    },
    decision/.style={%
        signal,
        signal to=east and west,
        minimum width=40mm,
        minimum height=1cm,
        text width=40mm,
        text centered,
        inner xsep=-1ex,
        draw=black,
        fill=green!30,
    },
    arrow/.style={%
        thick,
        ->,
        >=stealth,
    },
    %
    symmetrycross/.style={%
        % Style for a center-cross to mark symmetry in technical drawings.
        % Styles have one argument per default. Use it for size,
        % but also provide a default
        draw,
        cross out,% From shapes library
        thin,
        dashdotted,
        rotate=45,
        minimum size=#1,% This is an argument
    },
    symmetrycross/.default={2em},
    pipecrosssection/.style={
        circle,
        minimum size=#1,
        draw=black!90!red,
        ultra thick,% Simulate thick pipe around it
        fill=MediumFluid
    },
    pipecrosssection/.default={0.5em},
    arrowlabel/.style={ % Style for labels along arrows
        pos=#1,
        text=black,% Overwrite in case encapsulating draw command is white etc.
        draw=none,% Do not draw border
        fill=white,
        inner sep=1.5pt,
        rounded corners,
    },
    arrowlabel/.default={0.5}, % Default for position: middle
    wall/.style={ % For all walls, e.g. in crosssections of pipes, ...
        draw,
        thick,
        fill=#1,
        line join=round,
        rounded corners=0.5,
    },
    wall/.default={g5},
    fluid/.style={ % For all fluids
        fill=#1,
    },
    fluid/.default={MediumFluid},
    flowarrow/.style 2 args={% A style for squiggly arrows, for flows:
        ->,
        line join=round,
        thick,
        dashed,
        decorate,
        decoration={
            snake, % alternatives: snake, zigzag
            segment length=#1,
            amplitude=#2,
            % Stop with decoration at start and end by the given length and just draw
            % a line:
            pre=lineto,
            post=lineto,
            pre length=1em,
            post length=1em
        },
    },
    annotationarrow/.style={%
        % A style intended to point a line with a thick black dot at its end onto
        % elements to give further explanations.
        % Since we shorten the line START, any line using this style should originate
        % from the place where the shortening is supposed to take place.
        % Further explanation here:
        % https://tex.stackexchange.com/a/115268/120853
        % Simply call -* (or any other similar command) after annoationarrow if the
        % direction should be inverted.
        *-,
        shorten <=-(1.8pt + 1.4\pgflinewidth),%
    },
    flowarrow/.default={3em}{2em},% {<INVERSE FREQUENCY>}{<AMPLITUDE>}
    origindot/.style={ % A simple small dot for coordinate starts/origins
        circle,
        fill=#1,
        inner sep=0pt,
        minimum width=0.4em
    },
    origindot/.default={black},
    add node at x/.style 2 args={% https://tex.stackexchange.com/a/93968/120853
        % Add node on a plot by just specifying its x-position.
        % The corresponding y/value is computed automatically!
        name path global=plot line,
        /pgfplots/execute at end plot visualization/.append={
                \begingroup
                \@ifnextchar[{\parsenode}{\parsenode[]}#2\pgf@nil
            \path [name path global=position line #1-1]
                ({axis cs:#1,0}|-{rel axis cs:0,0}) --
                ({axis cs:#1,0}|-{rel axis cs:0,1});
            \path [xshift=1pt, name path global=position line #1-2]
                ({axis cs:#1,0}|-{rel axis cs:0,0}) --
                ({axis cs:#1,0}|-{rel axis cs:0,1});
            \path [
                name intersections={
                    of={plot line and position line #1-1},
                    name=left intersection
                },
                name intersections={
                    of={plot line and position line #1-2},
                    name=right intersection
                },
                label node/.append style={pos=1}
            ] (left intersection-1) -- (right intersection-1)
            node [label node]{\nodetext};
            \endgroup
        }
    },
    shorten <>/.style={% Allow shortening of both ends simultaneously
        shorten >=#1,
        shorten <=#1,
    },
    circlednum/.style={% Used for a custom circled number command
        shape=circle,
        draw,
        inner sep=2pt,
        fill=white
    }%,
    % A reusable little 'pic' for a common radiator.
    % Further down, we also declare a 'shape' for a radiator. A 'shape' is a node shape with anchors etc. and intended to be used to connect nodes together, like in a circuit diagram.
    % A 'pic' is really just a reusable picture that can be put anywhere, but it (by the package author) not intended to be connected etc.
    % This pic is prettier than the shape below. The pic should be used for large radiator images where more detail is desired.
    radiator/.pic={
        \tikzset{%
            every path/.style={
                    draw,
                    thick,
                    line join=round,
                    line cap=round,% End of lines
                    fill=g5,
                    pic actions,% Whatever is used in \pic[<drawing options>], e.g. dashed, is propagated to this drawing
                },
        }
        % Base measurements. Default unit is centimeter
        \pgfmathsetmacro{\radiatorheight}{2}
        \pgfmathsetmacro{\radiatorwidth}{3}
        \pgfmathsetmacro{\radiatordepth}{0.5}

        % Right surface:
        \begin{scope}[canvas is yz plane at x=\radiatorwidth]
            \draw[fill=g4] (0,0) rectangle (\radiatorheight,\radiatordepth);

            % Fake the thermostat a bit:
            \draw[fill=g3] (0.8*\radiatorheight,0.5*\radiatordepth) circle (0.2*\radiatordepth);

            % Generate some coordinates in analogy to regular tikz naming convetions:
            \foreach \yfrac/\zfrac/\coordname in {%
                    0.5/0.5/center,%
                    0/0.5/south,%
                    1/0.5/north,%
                    0.5/0/east,
                    0.5/1/west,
                    0/0/south east,%
                    0/1/south west,%
                    1/1/north east,%
                    1/0/north west,%
                    0.8/0.5/thermostat%
                }{
                    \coordinate (-right \coordname) at (\yfrac*\radiatorheight,\zfrac*\radiatordepth);
                }
        \end{scope}

        % Top surface:
        \begin{scope}[canvas is xz plane at y=\radiatorheight]
            \draw (0,0) rectangle (\radiatorwidth,\radiatordepth);

            % "Hollow space" inside the radiator:
            \draw[fill=g2, rounded corners=0.75] (0.05*\radiatorwidth,0.3*\radiatordepth) rectangle (0.95*\radiatorwidth,0.7*\radiatordepth);

            % Generate some coordinates in analogy to regular tikz naming convetions:
            \foreach \xfrac/\zfrac/\coordname in {%
                    0.5/0.5/center,%
                    0.5/1/south,%
                    0.5/0/north,%
                    1/0.5/east,
                    0/0.5/west,
                    1/1/south east,%
                    0/1/south west,%
                    1/0/north east,%
                    0/0/north west%
                }{
                    \coordinate (-top \coordname) at (\xfrac*\radiatorwidth,\zfrac*\radiatordepth);
                }
        \end{scope}

        % Front surface:
        \begin{scope}[canvas is xy plane at z=\radiatordepth]
            \draw (0,0) rectangle (\radiatorwidth,\radiatorheight);

            \foreach \posfraction in {0.1, 0.2, ..., 0.9}
                {%
                    \draw[
                        thick,
                        preaction={draw, ultra thick, g3},
                    ] (\posfraction*\radiatorwidth, 0.1*\radiatorheight) -- (\posfraction*\radiatorwidth, 0.9*\radiatorheight);
                }
            % Generate some coordinates in analogy to regular tikz naming convetions:
            \foreach \xfrac/\yfrac/\coordname in {%
                    0.5/0.5/center,%
                    0.5/0/south,%
                    0.5/1/north,%
                    1/0.5/east,
                    0/0.5/west,
                    1/0/south east,%
                    0/0/south west,%
                    1/1/north east,%
                    0/1/north west%
                }{
                    \coordinate (-front \coordname) at (\xfrac*\radiatorwidth,\yfrac*\radiatorheight);
                }
            \node at (-front center) {\ctrw{\tikzpictext}};% value of "pic text" key is stored in \tikzpictext macro
        \end{scope}

        % Coordinates for convenience:
        \coordinate (-thermostat) at (-right thermostat);
        \coordinate (-entry) at ($(-front north west)!0.2!(-front south west)$);
        \coordinate (-exit) at ($(-right south)!0.2!(-right north)$);
        \coordinate (-left center) at (-front west|--right center);% To have an exact opposite of the visible 'center right' position

        % Debugging coordinate system:
        % \draw[->] (0,0,0) -- (1,0,0) node[right] {\(x\)};
        % \draw[->] (0,0,0) -- (0,1,0) node[left] {\(y\)};
        % \draw[->] (0,0,0) -- (0,0,1) node[above] {\(z\)};
    },
    TUHHuman/.pic={% A human member of TUHH. Hilarious......
        \pgfmathsetmacro{\roundingradius}{0.4}
        \filldraw[pic actions] (0,0) circle (1);% Head
        %
        % Use arc over just specifying 'rounded corners', because rounded corners are absolute and aren't affected by 'scale'
        \filldraw[pic actions]
        (0,-1.2)% Below head
         -- ++ (2.5-\roundingradius,0) arc (90:0:\roundingradius)% Right shoulder
         -- ++ (0,{-(5 - 2*\roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(0.8 - 2*\roundingradius)},0) arc (270:180:\roundingradius) -- ++ (0,{4 - \roundingradius})% Right arm
         -- ++ (-0.25,0)% Right arm pit
         -- ++ (0,{-(8 - \roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(1 - 2*\roundingradius)},0) arc (270:180:\roundingradius) -- ++ (0,{4 - 2*\roundingradius}) arc (0:90:\roundingradius)% Right leg
         -- ++ ({-(1 - 2*\roundingradius)},0)% Gap between legs
         arc (90:180:\roundingradius) -- ++ (0,{-(4 - 2*\roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(1 - 2*\roundingradius)},0) arc (270:180:\roundingradius) -- ++ (0,{8 - \roundingradius})% Left leg
         -- ++ (-0.25,0)% Left arm pit
         -- ++ (0,{-(4 - \roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(0.8 - 2*\roundingradius},0) arc (270:180:\roundingradius) -- ++ (0,{5 - 2*\roundingradius})% Left arm
         arc (180:90:\roundingradius)-- cycle;% Left shoulder; cycle back to below head

        \node[right, transform shape] at (-1.25,-2.5) {\ctrw{\textcolor[RGB]{45,198,214}{\textbf{\textsf{TUHH}}}}};% Chest emblem; transform shape allows node to be affected by 'scale' option
        %
        % \draw[help lines] (-3,-11) grid (3,1);% Debugging grid
    },
    boilercylinder/.style={
        cylinder,% Shapes lib
        draw,
        thick,
        shape border rotate=90,
        aspect=0.3,% Flatten
        cylinder uses custom fill,
        % cylinder body fill=g5,% For regular filling, use these and comment out the colors at the bottom here
        % cylinder end fill=g4,%
        left color=HotFluid!70,
        middle color=orange!20,
        right color=g4,
        shading angle=180,
    },
    % Still use a pic so we can flexible add stuff to all boilers later one, like a burner on the bottom left side:
    boiler/.pic={
        \node[
            boilercylinder,
            minimum width=4em,
            minimum height=6em,
            pic actions,% Whatever is used in \pic[<drawing options>], e.g. dashed, is propagated to this drawing
        ] () {\ctrw{\tikzpictext}};% Empty coordinate is important for namespace stuff
    },
    equalizing tank/.style={
        circle split,
        draw,
        solid,% In case surrounding context is dashed etc.
        -,% As opposed to arrows etc.
        fill=white,
        double,
        minimum width=#1,
    },
    equalizing tank/.default={1.5em},
    pipe/.style={% (Water) pipes between devices. For a pipe without arrow line end, call it as e.g. \draw[pipe, -]
        line width=#1,
        double=MediumFluid,
        double distance={1*#1},
        -{Triangle Cap []. Fast Triangle[] Fast Triangle[] Fast Triangle[]},% dot represents line end
        line join=round,
    },
    pipe/.default={1.5pt},
    valve/.style={
        shape=valve,
        draw,
        solid,% In case surrounding context is dashed etc.
        -,% As opposed to arrows etc.
        fill=white,
        rounded corners=0.5,
        rotate=90,% We probably need the horizontal version more often. Also, this way, \draw ... node[midway, valve, sloped] {}; works out of the box
        minimum width=0.6*#1,% Fixed aspect ratio
        minimum height=#1,
    },
    valve/.default={1em},
    control valve/.style={% Same node style but different shape
        valve,
        % blue!10,
        shape=controlvalve,
    },
    threeway valve/.style={
        valve,
        shape=threeway valve,
        minimum width=0.85*#1,% Scale it a bit...
        minimum height=#1,
    },
    threeway valve/.default={1em},
    fourway valve/.style={
        valve,
        rotate=-90,% It's symmetrical, no need to rotate; undo inherited rotation
        shape=fourway valve,
        minimum width=#1,% Fixed aspect ratio, square
        minimum height=#1,
    },
    fourway valve/.default={1em},
    threeway control valve/.style={
        threeway valve,
        shape=threewaycontrolvalve,
    },
    radiator/.style={
        shape=radiator,
        draw,
        fill=g6,
        line join=round,
        minimum width=#1,
        minimum height=(2/3)*#1,% Fixed aspect ratio
    },
    radiator/.default={3em},
    vented radiator/.style={
        radiator,% Inherit from style
        shape=vented radiator,% Different shape
    },
    pump/.style={
        shape=pump,
        draw,
        solid,% In case surrounding context is dashed etc.
        -,% As opposed to arrows etc.
        fill=white,
        line join=round,
        minimum width=#1,
        rounded corners=0.5,% Alter rounded corners in case surrounding style has them
    },
    pump/.default={1.5em},
    compressor/.style={
        shape=compressor,
        draw,
        solid,
        -,
        fill=white,
        line join=round,
        minimum size=#1,
        sloped,% Because why not
    },
    compressor/.default={1.5em},
    heat exchanger/.style={
        shape=heat exchanger,
        draw,
        solid,
        -,
        fill=white,
        line join=round,
        rounded corners=0.5,
        minimum width=#1,
        minimum height=0.5*#1,% Fixed aspect ratio
        sloped,% Because why not
    },
    heat exchanger/.default={1.5em},
    simple heat exchanger/.style={
        shape=simple heat exchanger,
        draw,
        solid,
        -,
        fill=white,
        line join=round,
        minimum width=#1,
        minimum height=2/3*#1,% Fixed aspect ratio
        sloped,% Because why not
    },
    simple heat exchanger/.default={1.5em},
    sensor/.style={% A vertical stroke with with three horizontal lines of decreasing width underneath
        shape=sensor,
        draw,
        solid,
        -,
        line join=round,
        line cap=round,
        minimum width=#1,
        minimum height=2*#1
    },
    sensor/.default={0.5em},
    level indicator/.style={% An upside-down triangle with three horizontal lines of decreasing width underneath
        shape=levelindicator,
        draw,
        fill=white,
        solid,
        -,
        line join=round,
        line cap=round,
        minimum width=#1,
        minimum height=2*#1,
        inner sep=1.5pt,
    },
    level indicator/.default={0.25em}
}

\pgfdeclareshape{valve}{%
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    \backgroundpath{%
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % Construct main path, basically 'two triangles touching'
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
            \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
            \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
            \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
        \pgfpathclose
    }
}

\pgfdeclareshape{threeway valve}{
    % This is asymetrical and stuff, so inheriting from the base valve is a bit hopeless, I don't know how to do it properly

    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough
    \inheritanchorborder[from=rectangle]

    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    % These have shifted now, since the three-point valve middle is not the node center anymore:
    \anchor{center}{
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xa + 0.5*0.75*(\pgf@xb - \pgf@xa)}
        \pgfmathsetlength\pgf@y{\pgf@ya + 0.5*(\pgf@yb - \pgf@ya)}
    }
    \anchor{north}{
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \southwest \pgf@xa=\pgf@x
        \pgfmathsetlength\pgf@x{\pgf@xa + 0.5*0.75*(\pgf@xb - \pgf@xa)}
        \pgfmathsetlength\pgf@y{\pgf@yb}
    }
    \anchor{south}{
        \northeast \pgf@xb=\pgf@x
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xa + 0.5*0.75*(\pgf@xb - \pgf@xa)}
        \pgfmathsetlength\pgf@y{\pgf@ya}
    }

    % The triangles meeting at their middle, each with an aspect ratio of 0.75 (base) to 0.5 (height)
    \backgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        \pgfpathmoveto{\southwest}
        \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*(\pgf@xb - \pgf@xa)}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
        \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*0.5*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.5*(\pgf@yb - \pgf@ya)}}% Valve centerpoint
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}}
        \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*0.5*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.5*(\pgf@yb - \pgf@ya)}}% Valve centerpoint
        \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*(\pgf@xb - \pgf@xa)}{\pgf@ya}}
        \pgfpathclose
    }
}

\pgfdeclareshape{fourway valve}{%
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    \backgroundpath{%
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % This yields four triangles meeting in the middle, each with an aspect ratio of 0.6/1.
        % Construct main path, basically 'two triangles touching'
        \pgfpathmoveto{\pgfpoint{\pgf@xa + 0.2*(\pgf@xb - \pgf@xa)}{\pgf@ya}}
            \pgfpathlineto{\pgfpoint{\pgf@xa + 0.8*(\pgf@xb - \pgf@xa)}{\pgf@yb}}
            \pgfpathlineto{\pgfpoint{\pgf@xa + 0.2*(\pgf@xb - \pgf@xa)}{\pgf@yb}}
            \pgfpathlineto{\pgfpoint{\pgf@xa + 0.8*(\pgf@xb - \pgf@xa)}{\pgf@ya}}
        \pgfpathclose

        % Do the same again in the horizontal direction:
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}}
            \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}}
            \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}}
            \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}}
        \pgfpathclose
    }
}

\pgfdeclareshape{controlvalve}{
    \inheritsavedanchors[from=valve]
    \inheritanchorborder[from=valve]
    \inheritanchor[from=valve]{north}
    \inheritanchor[from=valve]{north west}
    \inheritanchor[from=valve]{north east}
    \inheritanchor[from=valve]{center}
    \inheritanchor[from=valve]{west}
    \inheritanchor[from=valve]{east}
    \inheritanchor[from=valve]{mid}
    \inheritanchor[from=valve]{mid west}
    \inheritanchor[from=valve]{mid east}
    \inheritanchor[from=valve]{base}
    \inheritanchor[from=valve]{base west}
    \inheritanchor[from=valve]{base east}
    \inheritanchor[from=valve]{south}
    \inheritanchor[from=valve]{south west}
    \inheritanchor[from=valve]{south east}

    \inheritbackgroundpath[from={valve}]

    \beforebackgroundpath{%
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % Extension line to control wheel:
        \pgfpathmoveto{\pgfpoint{(\pgf@xa + \pgf@xb)/2}{(\pgf@ya + \pgf@yb)/2}}
        \pgfpathlineto{\pgfpoint{\pgf@xb}{(\pgf@ya + \pgf@yb)/2}}

        % The factors 0.3, 0.4 and 0.3 need to add up to 1 to give a symmetrical, nice semicircle.
        % Factor 0.4 is divided by 2 to give the radius
        \pgfpathmoveto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.3*(\pgf@yb - \pgf@ya)}}
        \pgfpatharc{-90}{90}{0.4/2*(\pgf@yb - \pgf@ya)}
        \pgfpathclose
        \pgfsetfillcolor{black}
        \pgfusepath{fill, stroke}
    }
}

\pgfdeclareshape{pump}{%
    \inheritsavedanchors[from=circle]%
    \inheritanchorborder[from=circle]
    \inheritbackgroundpath[from={circle}]
    \inheritanchor[from=circle]{center}
    \inheritanchor[from=circle]{north}
    \inheritanchor[from=circle]{south}
    \inheritanchor[from=circle]{west}
    \inheritanchor[from=circle]{east}

    \beforebackgroundpath{
        % The simple-most approach:
        \pgfpathmoveto{\pgf@anchor@pump@west}
            \pgfpathlineto{\pgf@anchor@pump@north}
            \pgfpathlineto{\pgf@anchor@pump@east}
        \pgfusepath{stroke}
    }
}

\pgfdeclareshape{compressor}{%
    \inheritsavedanchors[from=circle]%
    \inheritanchorborder[from=circle]%
    \inheritbackgroundpath[from={circle}]%
    \inheritanchor[from=circle]{center}%
    \inheritanchor[from=circle]{north}%
    \inheritanchor[from=circle]{south}%
    \inheritanchor[from=circle]{west}%
    \inheritanchor[from=circle]{east}%

    % Circle has savedanchor of 'centerpoint' and saveddim of 'radius', that's it

    \beforebackgroundpath{
        \centerpoint \pgf@yc=\pgf@y

        % Pythagorean theorem is enough here.
        % Assumption is that default compressor shape 'points to the right'.
        % This is important to get coorect behaviour out of the 'sloped' node option!

        % Idea (Example for top right point):
        % 1. Go to center point.
        % 2. On y-axis, move a fraction of the radius up. This is the y-portion of our top-right coordinate point.
        % 3. On x-axis, move as far right as Pythagorean theorem dictates (hypotenuse is the radius vector, other known length is the y-length we just specified)
        % 4. Repeat process to draw and move accordingly; don't forget squares and sqrt() in correct places.

        \pgfmathsetmacro{\upperyfraction}{0.3}% y-coordinate of the upper points is \upperyfraction*\radius to the sides of the centerpoint
        \pgfmathsetmacro{\loweryfraction}{0.7}% y-coordinate of the lower points is \loweryfraction*\radius to the sides of the centerpoint

        \foreach \signdirection in {1, -1}{% For left and right side
            % Upper (always same x-dimension, only y switches sign):
            \pgfpathmoveto{\pgfpoint{sqrt(\radius^2 - (\pgf@yc + \upperyfraction*\radius)^2)}{\pgf@yc + \signdirection*\upperyfraction*\radius}}
            % Bottom (always same x-dimension, only y switches sign):
            \pgfpathlineto{\pgfpoint{-1*sqrt(\radius^2 - (\pgf@yc - \loweryfraction*\radius)^2)}{\pgf@yc + \signdirection*\loweryfraction*\radius}}
        }

        \pgfusepath{stroke}
    }
}

\pgfdeclareshape{heat exchanger}{
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast
    \inheritanchorborder[from=rectangle]
    % Doesn't hurt to also inherit specific anchors:
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    \inheritbackgroundpath[from={rectangle}]

    % Anchor to 'in' port of heat exchanger.
    % This code does not get executed necessarily; we cannot use the \pgfsetmacros from below.
    % A solution is probably \pgfkeys, but this will do for now.
    % IT NEEDS MANUAL ADJUSTING IF THE SHAPE IS CHANGED.
    \anchor{in}{%
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xa + (1 - 0.7)/2*(\pgf@xb - \pgf@xa)}
        \pgfmathsetlength\pgf@y{\pgf@ya - 0.3*(\pgf@yb - \pgf@ya)}
    }
    \anchor{out}{%
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xb - (1 - 0.7)/2*(\pgf@xb - \pgf@xa)}
        \pgfmathsetlength\pgf@y{\pgf@ya - 0.3*(\pgf@yb - \pgf@ya)}
    }

    \beforebackgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        \pgfmathsetmacro{\heatsymbolextension}{0.3}% How far out the 'legs' extend out of the rectangle as a fraction of the overall node's height
        \pgfmathsetmacro{\heatsymbolwidth}{0.7}% The inner drawing's width as a fraction of the node's overall width
        \pgfmathsetmacro{\heatsymbolheight}{0.8}% How high the inner drawing reaches as a fraction of the node's overall height (at 1, it touches the upper rectangle border)
        \pgfmathsetmacro{\heatsymbolindentation}{0.3}% How 'indented' the triangle is, i.e. the vertical distance between the inner drawings highest point and the triangle's down-pointing 'tip'

        \pgfpathmoveto{\pgfpoint{\pgf@xa + (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya - \heatsymbolextension*(\pgf@yb - \pgf@ya)}}% Bottom left corner
        \pgfpathlineto{\pgfpoint{\pgf@xa + (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \heatsymbolheight*(\pgf@yb - \pgf@ya)}}% Straight line up
        \pgfpathlineto{\pgfpoint{\pgf@xa + 0.5*(\pgf@xb - \pgf@xa)}{\pgf@ya + (\heatsymbolheight - \heatsymbolindentation)*(\pgf@yb - \pgf@ya)}}% Line down, to the right; x-coordinate is the middle of the node
        \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \heatsymbolheight*(\pgf@yb - \pgf@ya)}}% Line up, to the right
        \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya - \heatsymbolextension*(\pgf@yb - \pgf@ya)}}% Line straight down
        \pgfusepath{stroke}
    }
}

\pgfdeclareshape{simple heat exchanger}{% Just a cross-out rectangle
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast
    \inheritanchorborder[from=rectangle]
    % Doesn't hurt to also inherit specific anchors:
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    \inheritbackgroundpath[from={rectangle}]

    \beforebackgroundpath{
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Top left corner
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}% Bottom right corner
        \pgfusepath{stroke}
    }
}

\pgfkeys{/pgf/.cd,
    radiator offset x/.initial=0.3em,
    radiator offset y/.initial=0.3em
}
\pgfdeclareshape{radiator}{%
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast
    \inheritanchorborder[from=rectangle]
    % Doesn't hurt to also inherit specific anchors:
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    \saveddimen{\xoffset}{% https://tex.stackexchange.com/a/181283/120853
        \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/radiator offset x}}
    }
    \saveddimen{\yoffset}{
        \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/radiator offset y}}
    }

    % In the middle of the right surface:
    \anchor{right}{%
        \southwest \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xb + \xoffset/2}
        \pgfmathsetlength\pgf@y{(\pgf@ya + \pgf@yb)/2 + \yoffset/2}
    }
    % In the middle of the top surface:
    \anchor{top}{%
        \southwest \pgf@xa=\pgf@x
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{(\pgf@xa + \pgf@xb)/2 + \xoffset/2}
        \pgfmathsetlength\pgf@y{\pgf@yb + \yoffset/2}
    }
    % Exit at the thermostat:
    \anchor{exit}{%
        \southwest \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xb + \xoffset/2}
        \pgfmathsetlength\pgf@y{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya) + \yoffset/2}
    }
    % Lower exit on the right side, below the thermostat:
    \anchor{lower exit}{%
        \southwest \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xb + \xoffset/2}
        \pgfmathsetlength\pgf@y{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya) + \yoffset/2}
    }
    % Entry in the bottom left somewhere:
    \anchor{lower entry}{%
    \northeast \pgf@yb=\pgf@y
    \southwest \pgf@ya=\pgf@y% x is now given implicitly
    \pgfmathsetlength\pgf@y{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}
    }

    % Alternative entry in the top left somewhere:
    \anchor{upper entry}{%
        \northeast \pgf@yb=\pgf@y
        \southwest \pgf@ya=\pgf@y% x is now given implicitly
        \pgfmathsetlength\pgf@y{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}
    }

    % Front surface is inherited from rectangle:
    \inheritbackgroundpath[from={rectangle}]

    % Background is inherited already, so add behind background path:
    \behindbackgroundpath{%
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % Top surface:
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Top left
        \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@yb}}{\pgfqpoint{\xoffset}{\yoffset}}}% Top left plus offset vector
        \pgfpathlineto{\pgfpointadd{\northeast}{\pgfqpoint{\xoffset}{\yoffset}}}% Top right (northeast) plus offset vector
        \pgfpathlineto{\northeast}
        \pgfpathclose

        % Access current fillcolor as specified by user
        % Make sides darker than current fill color for some 3D effect
        \colorlet{currentfill}{\tikz@fillcolor}
        \pgfsetfillcolor{currentfill!90!black}
        \pgfusepath{fill, stroke}

        % Right surface:
        \pgfpathmoveto{\northeast}
        \pgfpathlineto{\pgfpointadd{\northeast}{\pgfqpoint{\xoffset}{\yoffset}}}% Top right corner plus offset vector
        \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya}}{\pgfqpoint{\xoffset}{\yoffset}}}% Bottom right corner plus offset vector
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}% Bottom right corner
        \pgfpathclose
        \pgfsetfillcolor{currentfill!80!black}% Even darker than top surface
        \pgfusepath{fill, stroke}

        % Draw an ellipse to fake a thermostat or pipe exit.
        % Position it at 0.8 / 80% height
        % Ellipse axes are confusing and I did not do it properly fully
        \pgfpathellipse{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}}{\pgfpointscale{0.5}{\pgfqpoint{\xoffset}{\yoffset}}}}{\pgfpoint{0.2*\xoffset}{0.2*\yoffset}}{\pgfpoint{0pt}{1pt}}
        \pgfsetfillcolor{black}
        \pgfusepath{fill}
    }
    % Background is already the inherited rectangle. Draw on top of it with beforebackgroundpath
    \beforebackgroundpath{
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        % Draw vertical lines on top of front surface:
        \foreach \posfraction in {0.2, 0.4, ..., 0.8}{
            \pgfpathmoveto{\pgfpoint{\pgf@xa + \posfraction*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}}
            \pgfpathlineto{\pgfpoint{\pgf@xa + \posfraction*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}}
            \pgfusepath{stroke}
        }
    }
}

\pgfdeclareshape{vented radiator}{
    \inheritsavedanchors[from=radiator]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast
    \inheritanchorborder[from=radiator]
    % Doesn't hurt to also inherit specific anchors:
    \inheritanchor[from=radiator]{north}
    \inheritanchor[from=radiator]{north west}
    \inheritanchor[from=radiator]{north east}
    \inheritanchor[from=radiator]{center}
    \inheritanchor[from=radiator]{west}
    \inheritanchor[from=radiator]{east}
    \inheritanchor[from=radiator]{mid}
    \inheritanchor[from=radiator]{mid west}
    \inheritanchor[from=radiator]{mid east}
    \inheritanchor[from=radiator]{base}
    \inheritanchor[from=radiator]{base west}
    \inheritanchor[from=radiator]{base east}
    \inheritanchor[from=radiator]{south}
    \inheritanchor[from=radiator]{south west}
    \inheritanchor[from=radiator]{south east}

    % Inherit our special nodes:
    \inheritanchor[from=radiator]{right}
    \inheritanchor[from=radiator]{top}
    \inheritanchor[from=radiator]{exit}
    \inheritanchor[from=radiator]{lower entry}
    \inheritanchor[from=radiator]{upper entry}

    % Inherit all stuff from base radiator:
    \inheritbackgroundpath[from={radiator}]
    \inheritbehindbackgroundpath[from={radiator}]
    \inheritbeforebackgroundpath[from={radiator}]

    % Anchor for the ventilation point.
    % I tried with \savedanchor, but it didn't work so we have to repeat the calculations for the ventilation device
    \anchor{ventilation}{%
        \southwest \pgf@xa=\pgf@x
        \northeast \pgf@yb=\pgf@y
        \pgfmathsetlength\pgf@x{\pgf@xa - 3pt}
        \pgfmathsetlength\pgf@y{\pgf@yb - 3pt}
    }

    \behindforegroundpath{
        \southwest \pgf@xa=\pgf@x
        \northeast \pgf@yb=\pgf@y

        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Top left corner
        \pgfpatharc{90}{270}{3pt}% Arc from top-top left corner down with specified radius in last argument
        \pgfsetfillcolor{black}
        \pgfusepath{fill}
    }
}

\pgfdeclareshape{sensor}{
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast
    \inheritanchorborder[from=rectangle]
    % Doesn't hurt to also inherit specific anchors:
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    \backgroundpath{
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        \pgfpathmoveto{\pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@yb}}% Upper middle
        \pgfpathlineto{\pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@ya + 0.3*(\pgf@yb - \pgf@ya)}}% Down the middle, to 1/4 of the node height

        % These are percentages of the node height.
        % At each percentage/fraction of the height, draw a centered line with a width of a certain percentage (fractionlength) of the overall node width
        \foreach \fractionheight/\fractionlength in {
            0.3/1,%
            0.15/0.75,%
            0/0.5%
        }{
            % One horizontal line on this height:
            \pgfpathmoveto{\pgfpoint{\pgf@xa + (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}}
            \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}}
        }
    }
}

\pgfdeclareshape{levelindicator}{
    \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast
    \inheritanchorborder[from=rectangle]
    % Doesn't hurt to also inherit specific anchors:
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    % \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}

    % When no other anchor is specified, nodes are placed by their 'center' anchor.
    % Change it here to be the lower pointy triangle bit, as opposed to the rectangle center.
    % That way, the triangle always points onto the fluid surface if placed as a node on a drawn line representing this surface
    \anchor{center}{%
        \southwest \pgf@xa=\pgf@x
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
        % Lower pointy bit of triangle, as below:
        \pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@yb - sqrt(3)*((\pgf@xb - \pgf@xa)/2)}
    }

    \backgroundpath{
        % Store lower left in xa/ya and upper right in xb/yb
        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Upper left corner
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}% Upper right corner
        \pgfpathlineto{\pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@yb - sqrt(3)*((\pgf@xb - \pgf@xa)/2)}}% Forming an equilateral triangle
        \pgfpathclose

        % These are percentages of the node height.
        % At each percentage/fraction of the height, draw a centered line with a width of a certain percentage (fractionlength) of the overall node width
        \foreach \fractionheight/\fractionlength in {
            0.3/1,%
            0.15/0.75,%
            0/0.5%
        }{
            % One horizontal line on this height:
            \pgfpathmoveto{\pgfpoint{\pgf@xa + (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}}
            \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}}
        }
    }
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Scientifics Typesetting
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{chemmacros}% \ch{}, \chcpd[]{compound} etc.
    \chemsetup{%
        formula=chemformula,%
        chemformula/font-family=tgpl,% Use math font family
    }

    % Some new custom environments. Very simple definitions that behave just like the
    % widely known AMSMath math environment as specified in the last argument.
    \NewChemReaction{reactionsgather}{gather}% Like AMSmath's `gather`
    \NewChemReaction{reactionsgather*}{gather*}

    % Sort reaction counter underneath chapter, see
    % https://tex.stackexchange.com/questions/530210/how-to-cross-reference-reactions-in-chemmacros-chapter#comment1340793_530210
    \renewcommand*{\thereaction}{\thechapter.\arabic{reaction}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{siunitx}% Typesetting physical units correctly
    \sisetup{%
        % For siunitx v3, the following block replaces what used to be
        % `detect-all` (removed in that release, see
        % https://github.com/josephwright/siunitx/blob/main/CHANGELOG.md#v300 ).
        % It allows the `siunitx` output to match surrounding text/math (italics/bold/...,
        % roman/sans/... etc. as much as possible)
        mode=match,
        propagate-math-font=true,
        reset-math-version=false,
        reset-text-family=false,
        reset-text-series=false,
        reset-text-shape=false,% Not part of official fix, but still added (see https://collaborating.tuhh.de/alex/latex-cookbook/-/issues/8)
        text-family-to-math=true,
        text-series-to-math=true,
        %
        % Requires siunitx v3+, see also https://tex.stackexchange.com/a/468031/120853,
        % https://github.com/josephwright/siunitx/issues/532 :
        text-font-command=\unitnumberfont,
        %
        % Alternative range-phrase:
        % en-dash via '--', but inside \text{}, so it's not 'two minus signs'
        % range-phrase={\,\text{--}\,},
        range-units=single,% single: Print unit only once, at end
        per-mode=symbol,
    }%
    % Second setup step, with locales. See also
    % https://tex.stackexchange.com/a/46979/120853
    \gappto{\blockextras@german}{%
        \sisetup{locale=DE}
    }
    \gappto{\blockextras@english}{%
        \sisetup{locale=US}
    }

    % Declare units ourselves:
    % Set as text so it stays a hyphen in math mode, as opposed to minus sign
    \DeclareSIUnit{\volpercent}{Vol.\text{-}\%}
    \DeclareSIUnit{\watthour}{Wh}%
    \DeclareSIUnit{\annum}{a}%
    \DeclareSIUnit{\atmosphere}{atm}%
    \DeclareSIUnit{\partspermillion}{ppm}%
    \DeclareSIUnit{\bar}{bar}% https://tex.stackexchange.com/a/598473/120853

    % Unit qualifiers, i.e. subscripts.
    % We already have a dedicated system (bib file with glossaries-extra) for subscripts
    % for symbols, so use those (just format, don't index) also for units here.
    \DeclareSIQualifier{\dryair}{% for moist air context
        \glsfmtname{sub.dry}\glsfmtname{sub.air}%
    }
    \DeclareSIQualifier{\water}{%
        \glsfmtname{sub.water}%
    }
    \DeclareSIQualifier{\thermal}{%
        \glsfmtname{sub.thermal}%
    }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Hyperref and PDFs appearance
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage[pdfusetitle]{hyperref}% Loads url-package internally
    \hypersetup{%
        % Unicode settings are automatically true for luatex engine,
        % don't specify manually
        colorlinks=true,% No ugly frames, but still colored
        allcolors=darklink,%
        % hidelinks,% Toggle here!
        plainpages=false,%
        pdfsubject={%
            Comprehensive LaTeX template with examples for theses, books
            and more, employing the 'latest and greatest'.
        },
        pdfkeywords={%
            latex,%
            template,%
            modern,%
            thesis,%
            phd,%
            master,%
            bachelor,%
            best practices,%
        },
        pdfcreator={%
            LaTeX with hyperref,
            glossaries-extra/bib2gls
            and biblatex/biber
            [\GitRefName{}@\GitShortSHA{}]%
        }
Download .txt
gitextract_sv1rvnjz/

├── .devcontainer/
│   ├── README.md
│   ├── devcontainer.json
│   └── image/
│       ├── Dockerfile
│       ├── README.md
│       ├── config/
│       │   ├── .wgetrc
│       │   └── texlive.profile
│       └── texlive.sh
├── .gitattributes
├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── .latexmkrc
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── acp.cls
├── bib/
│   ├── README.md
│   ├── bibliography.bib
│   └── glossaries/
│       ├── abbreviations.bib
│       ├── constants.bib
│       ├── index/
│       │   ├── names.bib
│       │   └── terms.bib
│       └── symbols/
│           ├── greek.bib
│           ├── other.bib
│           ├── roman.bib
│           └── subscripts.bib
├── chapters/
│   ├── README.md
│   ├── backmatter.tex
│   ├── frontmatter/
│   │   ├── abstract.tex
│   │   ├── authorship_declaration.tex
│   │   ├── colophon.tex
│   │   ├── preface.tex
│   │   └── task.tex
│   ├── frontmatter.tex
│   ├── mainmatter/
│   │   ├── base-features.tex
│   │   ├── code-listings.tex
│   │   ├── floats.tex
│   │   └── usage.tex
│   └── mainmatter.tex
├── cookbook.tex
├── data/
│   ├── README.md
│   ├── diffuser.csv
│   ├── matlab2tikz_table_example.tex
│   └── matlab2tikz_table_example_data.csv
├── images/
│   ├── bitmaps/
│   │   └── README.md
│   └── vectors/
│       └── README.md
├── lib/
│   ├── README.md
│   └── example.lua
├── pandoc/
│   ├── README.md
│   ├── defaults.yaml
│   ├── metadata.yaml
│   └── promote-headers.lua
└── tests/
    ├── Makefile
    ├── README.md
    ├── config.yml
    ├── pyproject.toml
    └── tests/
        ├── __init__.py
        ├── conftest.py
        ├── test_pdfs.py
        ├── test_self.py
        └── utils.py
Download .txt
SYMBOL INDEX (18 symbols across 4 files)

FILE: tests/tests/conftest.py
  function pytest_make_parametrize_id (line 9) | def pytest_make_parametrize_id(config, val, argname):

FILE: tests/tests/test_pdfs.py
  class Rect (line 41) | class Rect(NamedTuple):
  function et_project_root_files (line 46) | def et_project_root_files(suffix: str) -> Generator[Path, None, None]:
  function config (line 51) | def config() -> dict[str, Any]:
  function pdf (line 57) | def pdf(request: FixtureRequest) -> Generator[pymupdf.Document, None, No...
  function test_page_numbers (line 64) | def test_page_numbers(pdf: pymupdf.Document, config: dict[str, Any]) -> ...
  function test_bookmarks (line 83) | def test_bookmarks(pdf: pymupdf.Document, config: dict[str, Any]) -> None:
  function test_required_strings (line 93) | def test_required_strings(pdf: pymupdf.Document, config: dict[str, Any])...
  function test_file_size (line 102) | def test_file_size(pdf: pymupdf.Document, config: dict[str, Any]) -> None:
  function test_metadata (line 113) | def test_metadata(pdf: pymupdf.Document, config: dict[str, Any]) -> None:
  function test_freshness (line 138) | def test_freshness(pdf: pymupdf.Document, config: dict[str, Any]) -> None:
  function test_page_size (line 178) | def test_page_size(pdf: pymupdf.Document, config: dict[str, Any]) -> None:

FILE: tests/tests/test_self.py
  function test_parse_size (line 50) | def test_parse_size(size, n):
  function test_fix_tzoffset (line 79) | def test_fix_tzoffset(raw_date, date):
  function test_parse_duration (line 158) | def test_parse_duration(raw_duration, duration):

FILE: tests/tests/utils.py
  function parse_size (line 13) | def parse_size(size: str) -> int:
  function fix_tzoffset (line 44) | def fix_tzoffset(date: str) -> str:
  function parse_duration (line 77) | def parse_duration(duration: str) -> datetime.timedelta:
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (546K chars).
[
  {
    "path": ".devcontainer/README.md",
    "chars": 288,
    "preview": "# Remote: Containers for VSCode\n\nThis directory contains all files required to enable [working *inside* of containers](h"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 4015,
    "preview": "{\n    \"name\": \"LaTeX\",\n    // Instead of *building* the accompanying Dockerfile and its whole context, like:\n    //\n    "
  },
  {
    "path": ".devcontainer/image/Dockerfile",
    "chars": 12054,
    "preview": "# ARGs before the first FROM are global and usable in all stages\n\nARG BASE_OS=\"debian\"\n\n# Tag of the base OS image\nARG O"
  },
  {
    "path": ".devcontainer/image/README.md",
    "chars": 18741,
    "preview": "# Docker image with custom, almost-full TeXLive distribution & various tools\n\n[![Docker Pulls](https://img.shields.io/do"
  },
  {
    "path": ".devcontainer/image/config/.wgetrc",
    "chars": 1150,
    "preview": "# wget config file\n\n# TeXLive uses wget. Make wget as robust as possible here.\n# Make downloading as robust as possible "
  },
  {
    "path": ".devcontainer/image/config/texlive.profile",
    "chars": 6733,
    "preview": "# -------------------------------------------------------------------------------\n# TeX Live profile to configure the in"
  },
  {
    "path": ".devcontainer/image/texlive.sh",
    "chars": 4630,
    "preview": "#!/bin/bash\n\n# Script to fetch `install-tl` script from different sources, depending on argument\n# given.\n\nset -ueo pipe"
  },
  {
    "path": ".gitattributes",
    "chars": 408,
    "preview": "# bib -> latex does not help much, since it is also not valid latex, but at\n# least highlights comments (%) correctly\n*."
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 1558,
    "preview": "name: Building and testing\non: [push]\njobs:\n  building:\n    runs-on: ubuntu-latest\n    container:\n      image: alexpovel"
  },
  {
    "path": ".gitignore",
    "chars": 6210,
    "preview": "# This file tells git what files *not* to track in its version control.\n# Specific files, general suffixes, whole direct"
  },
  {
    "path": ".latexmkrc",
    "chars": 7541,
    "preview": "#!/bin/env perl\n\n# This file contains instructions and configurations for the `latexmk` program.\n# That program is somew"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 489,
    "preview": "{\n\t// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.\n\t// Extension identif"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 1042,
    "preview": "{\n    \"latex-workshop.latex.recipes\": [\n        {\n            \"name\": \"latexmk\",\n            \"tools\": [\n                "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 6242,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2022 Alex Povel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "Makefile",
    "chars": 9453,
    "preview": "# This file contains instructions for the GNU `make` program: https://www.gnu.org/software/make/\n#\n# The program is quit"
  },
  {
    "path": "README.md",
    "chars": 7517,
    "preview": "# LaTeX Cookbook\n\n[![Download PDF](https://img.shields.io/badge/Download-PDF-blue.svg)][download]\n\nThis repo contains a "
  },
  {
    "path": "acp.cls",
    "chars": 143979,
    "preview": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% LuaLaTeX based on KOMA-Script\n%\n% Author (2021): Alex Povel"
  },
  {
    "path": "bib/README.md",
    "chars": 424,
    "preview": "# **Bib**liographical data\n\nThis directory contains:\n\n1. The [bibliography itself](bibliography.bib).\n    This is auto-g"
  },
  {
    "path": "bib/bibliography.bib",
    "chars": 7199,
    "preview": "\n@book{baehrThermodynamikGrundlagenUnd2016,\n  title = {Thermodynamik: Grundlagen und technische Anwendungen},\n  shorttit"
  },
  {
    "path": "bib/glossaries/abbreviations.bib",
    "chars": 2154,
    "preview": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% IT\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
  },
  {
    "path": "bib/glossaries/constants.bib",
    "chars": 365,
    "preview": "@number{pi,\n    name={\\ensuremath{\\pi}},\n    description={Pi},\n    value={\\num{3.14159}\\dots{}},\n    unit={},\n}\n@number{"
  },
  {
    "path": "bib/glossaries/index/names.bib",
    "chars": 905,
    "preview": "% Encoding: UTF-8\n\nIn bib files, there are no comment characters (like %).\nHowever, any entry outside the regular (at)ty"
  },
  {
    "path": "bib/glossaries/index/terms.bib",
    "chars": 594,
    "preview": "% Encoding: UTF-8\n\nIn bib files, there are no comment characters (%).\nHowever, any entry outside the regular (at)type{.."
  },
  {
    "path": "bib/glossaries/symbols/greek.bib",
    "chars": 1177,
    "preview": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% Thermodynamics\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
  },
  {
    "path": "bib/glossaries/symbols/other.bib",
    "chars": 1622,
    "preview": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% Math Operators:\n% REQUIRED for the built-i"
  },
  {
    "path": "bib/glossaries/symbols/roman.bib",
    "chars": 4669,
    "preview": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% Thermodynamic state\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
  },
  {
    "path": "bib/glossaries/symbols/subscripts.bib",
    "chars": 390,
    "preview": "@symbol{inferior,\n    name={\\text{i}},\n    description={inferior},\n}\n@symbol{water,\n    name={\\text{w}},\n    description"
  },
  {
    "path": "chapters/README.md",
    "chars": 351,
    "preview": "# Content files\n\nThis directory contains all the source `tex` files with the document content.\nSplitting up files, putti"
  },
  {
    "path": "chapters/backmatter.tex",
    "chars": 14831,
    "preview": "% For the order of things here (appendix, indices, bibliographies, ...) and their\n% numbering, see also https://tex.stac"
  },
  {
    "path": "chapters/frontmatter/abstract.tex",
    "chars": 168,
    "preview": "% Use built-in macro for internationalization\n\\chapter*{\\abstractname}\n\n\\Blindtext\n\n\\begin{itemize}\n    \\item We found t"
  },
  {
    "path": "chapters/frontmatter/authorship_declaration.tex",
    "chars": 320,
    "preview": "% Put page onto its own _recto_ page. It is a page intended to be signed and stamped.\n% Therefore, it cannot be verso, s"
  },
  {
    "path": "chapters/frontmatter/colophon.tex",
    "chars": 1553,
    "preview": "% No \\cleardoubleoddpage shenanigans: the colophon page is supposed to be on the verso\n% behind the title.\n\n\\thispagesty"
  },
  {
    "path": "chapters/frontmatter/preface.tex",
    "chars": 3289,
    "preview": "\\addchap{Preface}\n\nThis document is not a beginner guide.\nThere is a wide choice of those out there already, both free a"
  },
  {
    "path": "chapters/frontmatter/task.tex",
    "chars": 457,
    "preview": "\\chapter*{\\TransTask{}}\n\n\\makeatletter\n    \\begin{tabular}{\n        l\n        p{0.7\\linewidth}\n    }\n        \\TransFor{}"
  },
  {
    "path": "chapters/frontmatter.tex",
    "chars": 3333,
    "preview": "% Helper file that pulls subchapters together.\n\n% Set initial pages to alpha, so that they do not collide with later Ara"
  },
  {
    "path": "chapters/mainmatter/base-features.tex",
    "chars": 56741,
    "preview": "\\chapter{Base Features}\n\\label{ch:base-features}\n\nLet us first go through some of the base features offered by \\LaTeX{} "
  },
  {
    "path": "chapters/mainmatter/code-listings.tex",
    "chars": 16535,
    "preview": "\\chapter{Code Syntax Highlighting}\n\\label{ch:code-listings}\n\nTo properly typeset code in \\LaTeX{}, we use the \\ctanpacka"
  },
  {
    "path": "chapters/mainmatter/floats.tex",
    "chars": 88424,
    "preview": "\\chapter{Float Features}\n\nExamples for floats were already shown in \\cref{fig:censorbox,tab:main_font_examples}.\nThese a"
  },
  {
    "path": "chapters/mainmatter/usage.tex",
    "chars": 29266,
    "preview": "\\chapter{Usage}\n\nThis document \\enquote{requires}%\n\\footnote{\n    It does not \\emph{technically} require Docker, but I h"
  },
  {
    "path": "chapters/mainmatter.tex",
    "chars": 561,
    "preview": "\\mainmatter\n\n% Uncomment the following if you'd like vertical space (with no indentation) between\n% paragraphs, instead "
  },
  {
    "path": "cookbook.tex",
    "chars": 2830,
    "preview": "% Magic Comment: this template requires LuaLaTeX. The following 'magic comment' is\n% recognized by editors and will ensu"
  },
  {
    "path": "data/README.md",
    "chars": 142,
    "preview": "# (Raw) data\n\nThis directory contains data used inside the main document, e.g. CSV data for `pgfplots`.\nYou can put all "
  },
  {
    "path": "data/diffuser.csv",
    "chars": 3159,
    "preview": "R,M,Pi,Theta,Rho,alpha,R_pres\n1,0.8,1,1,1,15,1\n1.016666667,0.783683071,1.015164946,1.004602799,1.010513754,14.86740098,1"
  },
  {
    "path": "data/matlab2tikz_table_example.tex",
    "chars": 7984,
    "preview": "% This file was created by matlab2tikz.\n%\n%The latest updates can be retrieved from\n%  http://www.mathworks.com/matlabce"
  },
  {
    "path": "data/matlab2tikz_table_example_data.csv",
    "chars": 6967,
    "preview": "Pressure, Temperature, Reynolds, Drag_Coefficient, Drag_Coefficient_Error_Pos, Drag_Coefficient_Error_Neg\n9, 30, 91450.4"
  },
  {
    "path": "images/bitmaps/README.md",
    "chars": 457,
    "preview": "# Bitmaps Graphics Directory\n\nThis directory holds bitmaps (JPG, PNG, ...), to be used with `\\includegraphics{}`.\nIf the"
  },
  {
    "path": "images/vectors/README.md",
    "chars": 315,
    "preview": "# Vector Graphics Directory\n\nThis directory holds vector graphics SVG files, to be used with `\\includesvg{}`.\nIf there's"
  },
  {
    "path": "lib/README.md",
    "chars": 685,
    "preview": "# Library code\n\nThis directory might contain, for example:\n\n- Lua files for usage alongside `lualatex`.\n    Embedding Lu"
  },
  {
    "path": "lib/example.lua",
    "chars": 3787,
    "preview": "--[[\n    The following import is not required since in LuaTeX's `\\directlua` environment,\n    `token` etc. is already av"
  },
  {
    "path": "pandoc/README.md",
    "chars": 322,
    "preview": "# Pandoc\n\n`pandoc` is a tool almost completely separate from LaTeX, but goes hand-in-hand with it.\nIt is not relevant to"
  },
  {
    "path": "pandoc/defaults.yaml",
    "chars": 1778,
    "preview": "# Instead of command-line options, configure pandoc here and point it to this file.\n# See also: https://pandoc.org/MANUA"
  },
  {
    "path": "pandoc/metadata.yaml",
    "chars": 138,
    "preview": "author: [Alex Povel]\nsubject: \"Advantages of a workflow using LaTeX with GitLab, GitHub Actions etc.\"\nkeywords: [LaTeX, "
  },
  {
    "path": "pandoc/promote-headers.lua",
    "chars": 1003,
    "preview": "-- From https://stackoverflow.com/a/56005271/11477374:\n-- Automatically get \"Document Title\" from Markdown top-level hea"
  },
  {
    "path": "tests/Makefile",
    "chars": 913,
    "preview": "# Get this file's directory, allows this Makefile to be run on its own or via\n# `include` from a root Makefile. From:\n# "
  },
  {
    "path": "tests/README.md",
    "chars": 1726,
    "preview": "# Automated Testing\n\nThis sub-project contains Python-based code for testing the PDF output produced by\nearlier CI stage"
  },
  {
    "path": "tests/config.yml",
    "chars": 885,
    "preview": "metadata:\n  encryption: null  # why tho\n  pdf_version: \"1.5\"  # Versions are strings, not floats (see semantic versionin"
  },
  {
    "path": "tests/pyproject.toml",
    "chars": 465,
    "preview": "\n[build-system]\nrequires = [\"hatchling >= 1.26\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"tests\"\nversion = \""
  },
  {
    "path": "tests/tests/__init__.py",
    "chars": 85,
    "preview": "\"\"\"Strictly required for `pytest` to find this Python package and import from it.\"\"\"\n"
  },
  {
    "path": "tests/tests/conftest.py",
    "chars": 1021,
    "preview": "\"\"\"File to configure pytest, e.g. to implement hooks.\nSee also: https://stackoverflow.com/q/34466027/11477374\nList of ho"
  },
  {
    "path": "tests/tests/test_pdfs.py",
    "chars": 8818,
    "preview": "\"\"\"Tests whether PDFs documents fulfill certain criteria.\n\nThis is a bit backwards: `pytest` ordinarily tests functions/"
  },
  {
    "path": "tests/tests/test_self.py",
    "chars": 5590,
    "preview": "from tests.utils import parse_size, fix_tzoffset, parse_duration\nfrom datetime import timedelta as td\nimport pytest\n\n\n@p"
  },
  {
    "path": "tests/tests/utils.py",
    "chars": 3561,
    "preview": "import datetime\nimport logging\nimport re\nimport string\nfrom pathlib import Path\n\n_THIS_DIR = Path(__file__).parent\n\n# `r"
  }
]

About this extraction

This page contains the full source code of the alexpovel/latex-cookbook GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (508.9 KB), approximately 139.9k tokens, and a symbol index with 18 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!