about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-10-04 13:48:21 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-10-04 13:48:21 +0200
commit0a269caba85895d86ab2caf6aa5f0bd14643b4b1 (patch)
treebebffe87939587b992139aac311f591c353a0cf3
parentrefactor(common/scritps/latex/extract_text_from_all): Remove (diff)
downloadflake-templates-0a269caba85895d86ab2caf6aa5f0bd14643b4b1.tar.gz
flake-templates-0a269caba85895d86ab2caf6aa5f0bd14643b4b1.zip
chore(build): Recreate
-rwxr-xr-xbuild/awk/scripts/optimize_images.sh123
-rwxr-xr-xbuild/c/scripts/optimize_images.sh123
-rwxr-xr-xbuild/latex/academia/build.sh4
-rw-r--r--build/latex/academia/headers/preamble.tex1
-rw-r--r--build/latex/academia/headers/preamble/academia/index.tex (renamed from build/latex/academia/headers/preamble/core/index.tex)0
-rw-r--r--build/latex/academia/headers/preamble/academia/mod.tex1
-rw-r--r--build/latex/academia/headers/preamble/core/mod.tex1
-rw-r--r--build/latex/academia/headers/preamble/mod.tex3
-rwxr-xr-xbuild/latex/academia/scripts/extract_text_from_all.sh8
-rwxr-xr-xbuild/latex/academia/scripts/optimize_images.sh123
-rwxr-xr-xbuild/latex/letter/build.sh4
-rwxr-xr-xbuild/latex/letter/scripts/extract_text_from_all.sh8
-rwxr-xr-xbuild/latex/letter/scripts/optimize_images.sh123
-rw-r--r--build/latex/presentation/%INIT_APPLICATION_NAME.tex5
-rwxr-xr-xbuild/latex/presentation/build.sh4
-rw-r--r--build/latex/presentation/content/static/questions.tex2
-rw-r--r--build/latex/presentation/content/static/title.tex4
-rw-r--r--build/latex/presentation/headers/preamble.tex1
-rw-r--r--build/latex/presentation/headers/preamble/core/index.tex8
-rw-r--r--build/latex/presentation/headers/preamble/core/mod.tex1
-rw-r--r--build/latex/presentation/headers/preamble/mod.tex9
-rw-r--r--build/latex/presentation/lpm.toml4
-rw-r--r--build/latex/presentation/resources/images/logo.pdfbin0 -> 39677 bytes
-rwxr-xr-xbuild/latex/presentation/scripts/optimize_images.sh123
-rwxr-xr-xbuild/rust/scripts/optimize_images.sh123
-rwxr-xr-xbuild/shell/scripts/optimize_images.sh123
26 files changed, 884 insertions, 45 deletions
diff --git a/build/awk/scripts/optimize_images.sh b/build/awk/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/awk/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"
diff --git a/build/c/scripts/optimize_images.sh b/build/c/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/c/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"
diff --git a/build/latex/academia/build.sh b/build/latex/academia/build.sh
index 1ff2b6e..80ecc57 100755
--- a/build/latex/academia/build.sh
+++ b/build/latex/academia/build.sh
@@ -46,8 +46,8 @@ fd . "$root/figures" --type file --extension tex | while read -r figure; do
         echo "   -> Didn't change, not re-compiling."
     else
         echo "$figure_hash" >"$dst/figures/$figure_name/$figure_name.sha256sum_hash"
-        pdflatex -output-directory="$dst" -file-line-error -jobname="figures/$figure_name/$figure_name" "$figure"
+        pdflatex -output-directory="$dst" -file-line-error -jobname="figures/$figure_name/$figure_name" "$figure" || exit 1
     fi
-done
+done || exit 1
 
 latexmk -outdir="$dst" -file-line-error -pdflatex -recorder "$file"
diff --git a/build/latex/academia/headers/preamble.tex b/build/latex/academia/headers/preamble.tex
index d45262a..d10a02e 100644
--- a/build/latex/academia/headers/preamble.tex
+++ b/build/latex/academia/headers/preamble.tex
@@ -1,2 +1 @@
 \input{headers/preamble/mod.tex}
-\input{headers/preamble_local.tex}
diff --git a/build/latex/academia/headers/preamble/core/index.tex b/build/latex/academia/headers/preamble/academia/index.tex
index 3efbfc4..3efbfc4 100644
--- a/build/latex/academia/headers/preamble/core/index.tex
+++ b/build/latex/academia/headers/preamble/academia/index.tex
diff --git a/build/latex/academia/headers/preamble/academia/mod.tex b/build/latex/academia/headers/preamble/academia/mod.tex
index 39b9230..1f2cd71 100644
--- a/build/latex/academia/headers/preamble/academia/mod.tex
+++ b/build/latex/academia/headers/preamble/academia/mod.tex
@@ -1,4 +1,5 @@
 % derived from:
 % https://github.com/gillescastel/lecture-notes/blob/929672a96abc27eaeb6fa58b1d277b3582d28532/group-theory/preamble.tex
+\input{headers/preamble/academia/index.tex}
 \input{headers/preamble/academia/theorems/mod.tex}
 \input{headers/preamble/academia/visuals.tex}
diff --git a/build/latex/academia/headers/preamble/core/mod.tex b/build/latex/academia/headers/preamble/core/mod.tex
index 403ce58..7eaa1c0 100644
--- a/build/latex/academia/headers/preamble/core/mod.tex
+++ b/build/latex/academia/headers/preamble/core/mod.tex
@@ -7,7 +7,6 @@
 \input{headers/preamble/core/date_and_time.tex}
 \input{headers/preamble/core/encoding.tex}
 \input{headers/preamble/core/graphics_and_floats.tex}
-\input{headers/preamble/core/index.tex}
 \input{headers/preamble/core/linting.tex}
 \input{headers/preamble/core/margindate.tex}
 \input{headers/preamble/core/math.tex}
diff --git a/build/latex/academia/headers/preamble/mod.tex b/build/latex/academia/headers/preamble/mod.tex
index 91ae2d7..dcdd92a 100644
--- a/build/latex/academia/headers/preamble/mod.tex
+++ b/build/latex/academia/headers/preamble/mod.tex
@@ -1,2 +1,3 @@
-\input{headers/preamble/academia/mod.tex}
 \input{headers/preamble/core/mod.tex}
+
+\input{headers/preamble/academia/mod.tex}
diff --git a/build/latex/academia/scripts/extract_text_from_all.sh b/build/latex/academia/scripts/extract_text_from_all.sh
deleted file mode 100755
index 11b2ac4..0000000
--- a/build/latex/academia/scripts/extract_text_from_all.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#! /usr/bin/env sh
-
-grep 'INPUT ./' ./build/main.fls | uniq | sed 's/INPUT //' | while read -r file; do
-    if ! [ "$(basename "$file")" = preamble.tex ] && ! [ "$(basename "$file")" = gymnasium.png ]; then
-        printf "\n%% Filename: %s\n" "$file"
-        grep -v '^\s*%' "$file"
-    fi
-done
diff --git a/build/latex/academia/scripts/optimize_images.sh b/build/latex/academia/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/latex/academia/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"
diff --git a/build/latex/letter/build.sh b/build/latex/letter/build.sh
index 1ff2b6e..80ecc57 100755
--- a/build/latex/letter/build.sh
+++ b/build/latex/letter/build.sh
@@ -46,8 +46,8 @@ fd . "$root/figures" --type file --extension tex | while read -r figure; do
         echo "   -> Didn't change, not re-compiling."
     else
         echo "$figure_hash" >"$dst/figures/$figure_name/$figure_name.sha256sum_hash"
-        pdflatex -output-directory="$dst" -file-line-error -jobname="figures/$figure_name/$figure_name" "$figure"
+        pdflatex -output-directory="$dst" -file-line-error -jobname="figures/$figure_name/$figure_name" "$figure" || exit 1
     fi
-done
+done || exit 1
 
 latexmk -outdir="$dst" -file-line-error -pdflatex -recorder "$file"
diff --git a/build/latex/letter/scripts/extract_text_from_all.sh b/build/latex/letter/scripts/extract_text_from_all.sh
deleted file mode 100755
index 11b2ac4..0000000
--- a/build/latex/letter/scripts/extract_text_from_all.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#! /usr/bin/env sh
-
-grep 'INPUT ./' ./build/main.fls | uniq | sed 's/INPUT //' | while read -r file; do
-    if ! [ "$(basename "$file")" = preamble.tex ] && ! [ "$(basename "$file")" = gymnasium.png ]; then
-        printf "\n%% Filename: %s\n" "$file"
-        grep -v '^\s*%' "$file"
-    fi
-done
diff --git a/build/latex/letter/scripts/optimize_images.sh b/build/latex/letter/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/latex/letter/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"
diff --git a/build/latex/presentation/%INIT_APPLICATION_NAME.tex b/build/latex/presentation/%INIT_APPLICATION_NAME.tex
index a04a7dd..dc63700 100644
--- a/build/latex/presentation/%INIT_APPLICATION_NAME.tex
+++ b/build/latex/presentation/%INIT_APPLICATION_NAME.tex
@@ -19,7 +19,7 @@
 \SetYears{%INIT_YEAR}
 \SetAuthors{%INIT_AUTHOR_NAME}
 
-\logo{\includegraphics[height=1cm]{references/images/logo}}
+\logo{\includegraphics[height=1cm]{resources/images/logo}}
 
 \usetheme[block=fill]{moloch}
 
@@ -36,7 +36,7 @@
 \hypersetup{
   pdftitle={\@title},
   pdfsubject={},
-  pdfauthor={\@authors},
+  pdfauthor={\AuthorList},
   pdfkeywords={TODO},
 }
 \makeatother
@@ -55,6 +55,5 @@
 \appendix
 \begin{frame}
 	\printbibliography
-	\printindex
 \end{frame}
 \end{document}
diff --git a/build/latex/presentation/build.sh b/build/latex/presentation/build.sh
index 1ff2b6e..80ecc57 100755
--- a/build/latex/presentation/build.sh
+++ b/build/latex/presentation/build.sh
@@ -46,8 +46,8 @@ fd . "$root/figures" --type file --extension tex | while read -r figure; do
         echo "   -> Didn't change, not re-compiling."
     else
         echo "$figure_hash" >"$dst/figures/$figure_name/$figure_name.sha256sum_hash"
-        pdflatex -output-directory="$dst" -file-line-error -jobname="figures/$figure_name/$figure_name" "$figure"
+        pdflatex -output-directory="$dst" -file-line-error -jobname="figures/$figure_name/$figure_name" "$figure" || exit 1
     fi
-done
+done || exit 1
 
 latexmk -outdir="$dst" -file-line-error -pdflatex -recorder "$file"
diff --git a/build/latex/presentation/content/static/questions.tex b/build/latex/presentation/content/static/questions.tex
index 40c3803..21126c5 100644
--- a/build/latex/presentation/content/static/questions.tex
+++ b/build/latex/presentation/content/static/questions.tex
@@ -5,6 +5,6 @@
 
 \begin{frame}[standout]
 	% TODO change to your needed language
-	\shadowtext{Questions?}
+	Questions?
 \end{frame}
 }
diff --git a/build/latex/presentation/content/static/title.tex b/build/latex/presentation/content/static/title.tex
index 30ad3d9..9078b0c 100644
--- a/build/latex/presentation/content/static/title.tex
+++ b/build/latex/presentation/content/static/title.tex
@@ -15,13 +15,11 @@
 		\url{%INIT_HOME_PAGE}
 	\end{center}
 
-	\makeatletter
-	Copyright \textcopyright{} \@authors{} \@years{}\\
+	Copyright \textcopyright{} \AuthorList{} \YearList{}\\
 	\ \\
 	This work is licensed under the terms of the %INIT_SPDX_LICENSE_IDENTIFIER licence.
 	The licence text can be found online at \url{%INIT_LICENSE_URL}.
 	\
-	\makeatother
 
 	% TODO match the logo to your real license
 	\begin{center}\ccbysa\end{center}
diff --git a/build/latex/presentation/headers/preamble.tex b/build/latex/presentation/headers/preamble.tex
index d45262a..d10a02e 100644
--- a/build/latex/presentation/headers/preamble.tex
+++ b/build/latex/presentation/headers/preamble.tex
@@ -1,2 +1 @@
 \input{headers/preamble/mod.tex}
-\input{headers/preamble_local.tex}
diff --git a/build/latex/presentation/headers/preamble/core/index.tex b/build/latex/presentation/headers/preamble/core/index.tex
deleted file mode 100644
index 3efbfc4..0000000
--- a/build/latex/presentation/headers/preamble/core/index.tex
+++ /dev/null
@@ -1,8 +0,0 @@
-\usepackage{index} % Helps to create an index
-\makeindex
-
-\ifdraft{
-	\usepackage{showidx}
-} {
-	\message {Draft option not enabled, 'showidx' not loaded.}
-}
diff --git a/build/latex/presentation/headers/preamble/core/mod.tex b/build/latex/presentation/headers/preamble/core/mod.tex
index 403ce58..7eaa1c0 100644
--- a/build/latex/presentation/headers/preamble/core/mod.tex
+++ b/build/latex/presentation/headers/preamble/core/mod.tex
@@ -7,7 +7,6 @@
 \input{headers/preamble/core/date_and_time.tex}
 \input{headers/preamble/core/encoding.tex}
 \input{headers/preamble/core/graphics_and_floats.tex}
-\input{headers/preamble/core/index.tex}
 \input{headers/preamble/core/linting.tex}
 \input{headers/preamble/core/margindate.tex}
 \input{headers/preamble/core/math.tex}
diff --git a/build/latex/presentation/headers/preamble/mod.tex b/build/latex/presentation/headers/preamble/mod.tex
index a8d5fc7..0a00086 100644
--- a/build/latex/presentation/headers/preamble/mod.tex
+++ b/build/latex/presentation/headers/preamble/mod.tex
@@ -1,2 +1,9 @@
-\input{headers/preamble/beamer/mod.tex}
 \input{headers/preamble/core/mod.tex}
+
+% This makes it possible to import this preamble in the `standalone` class. Useful for
+% external figures.
+\ifcsname setbeamercolor\endcsname
+	\input{headers/preamble/beamer/mod.tex}
+\else
+	% Don't input it
+\fi
diff --git a/build/latex/presentation/lpm.toml b/build/latex/presentation/lpm.toml
index 56e40fb..a689e78 100644
--- a/build/latex/presentation/lpm.toml
+++ b/build/latex/presentation/lpm.toml
@@ -14,13 +14,13 @@ section = '''
 \end{frame}
 '''
 
-chapter = """
+chapter = '''
 %! TEX root = ../../../%INIT_APPLICATION_NAME.tex
 % LTeX: language=%INIT_LANGUAGE
 
 % Chapter (lpm::current_date)
 \section{lpm::new_chapter_name}
-"""
+'''
 
 figure = '''
 % LTeX: language=%INIT_LANGUAGE
diff --git a/build/latex/presentation/resources/images/logo.pdf b/build/latex/presentation/resources/images/logo.pdf
new file mode 100644
index 0000000..57c500a
--- /dev/null
+++ b/build/latex/presentation/resources/images/logo.pdf
Binary files differdiff --git a/build/latex/presentation/scripts/optimize_images.sh b/build/latex/presentation/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/latex/presentation/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"
diff --git a/build/rust/scripts/optimize_images.sh b/build/rust/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/rust/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"
diff --git a/build/shell/scripts/optimize_images.sh b/build/shell/scripts/optimize_images.sh
new file mode 100755
index 0000000..0f48e4b
--- /dev/null
+++ b/build/shell/scripts/optimize_images.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env nix
+#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
+# shellcheck shell=dash
+
+# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images
+
+PROJECT_DIR="$(git rev-parse --show-toplevel)"
+
+cd "$PROJECT_DIR" || {
+    echo "No '$PROJECT_DIR' ?!"
+    exit 1
+}
+
+PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
+JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
+SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'
+
+# The extension is the part after the first dot in the filename:
+#
+# For example:
+# file.png    => png
+# file.tar.gz => tar.gz
+find_files_by_extension() {
+    wanted_extension="$1"
+    tmp="$(mktemp)"
+
+    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
+        extension="${file#*.}"
+        if [ "$extension" = "$wanted_extension" ]; then
+            echo "$file"
+        else
+            :
+            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
+        fi
+    done >"$tmp"
+
+    echo "$tmp"
+}
+
+size_of() {
+    du -b "$1" | cut -f1
+}
+
+bytes_human() {
+    number="$1"
+
+    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
+}
+
+# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
+# Native POSIX solution using string manipulation (assumes integer inputs).
+percent() {
+    DP="$1"
+    SDC="$2"
+
+    # Special case when DP is zero.
+    [ "$DP" = "0" ] && echo "0.00" && return
+
+    #                                  # e.g. round down   e.g. round up
+    #                                  # DP=1 SDC=3        DP=2 SDC=3
+    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
+    Whole=${Percent%???}               # Whole=33          Whole=66
+    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
+    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
+    echo "$Percent"
+}
+
+TOTAL=0
+TOTAL_SAVED=0
+
+optimize_files() {
+    FILTER="$1"
+    PROGRAM="$2"
+
+    printf "%s" "Processing $FILTER files:"
+
+    FILES="$(find_files_by_extension "$FILTER")"
+    COUNT=$(wc -l <"$FILES")
+
+    if [ "$COUNT" -eq 0 ]; then
+        echo " no files found!"
+        return
+    fi
+
+    echo ""
+
+    I=1
+
+    TOTAL_INNER=0
+    TOTAL_SAVED_INNER=0
+
+    while IFS= read -r f; do
+        printf "%-2s/${COUNT} $f ... " "$I"
+
+        SIZE="$(size_of "$f")"
+
+        $PROGRAM "$f"
+
+        NEW_SIZE="$(size_of "$f")"
+        DIFF=$((SIZE - NEW_SIZE))
+
+        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"
+
+        TOTAL_INNER=$((TOTAL_INNER + SIZE))
+        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))
+
+        I=$((I + 1))
+    done <"$FILES"
+    rm "$FILES"
+
+    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
+    echo ""
+
+    TOTAL=$((TOTAL + TOTAL_INNER))
+    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
+}
+
+optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
+optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
+optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"
+
+echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"