mirror of
https://github.com/Smaug123/static-site-pipeline
synced 2025-10-21 07:38:41 +00:00
Compare commits
10 Commits
1f3e107106
...
bootstrap
Author | SHA1 | Date | |
---|---|---|---|
|
6b0b0f2bcb | ||
|
8d1459f98b | ||
|
b73c8a45c2 | ||
|
c1a7981451 | ||
|
cd6752d220 | ||
|
d459266f21 | ||
|
9b71477f59 | ||
|
2ffff26dcb | ||
|
e4127066af | ||
|
dd3713f40e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ hugo/static/misc/TokyoEntrance2016/
|
||||
.DS_Store
|
||||
|
||||
.idea/
|
||||
.profile*
|
||||
|
30
build.sh
30
build.sh
@@ -26,25 +26,23 @@ docker build docker/hugo -t build-hugo || exit 1
|
||||
|
||||
echo Building thumbnails.
|
||||
docker run --user "$(id -u):$(id -g)" -v "$IMAGES:/output" build-pictures sh -c "/build.sh /output" || exit 1
|
||||
while read -r d
|
||||
do
|
||||
mkdir -p "$HUGO/$d" || exit 1
|
||||
DESIRED_LOCATION=$(basename "$d")
|
||||
DEST=$(dirname "$d")
|
||||
cp -r "$IMAGES/$DESIRED_LOCATION" "$HUGO/$DEST"
|
||||
done < "$IMAGES/image-targets.txt"
|
||||
while read -r d; do
|
||||
mkdir -p "$HUGO/$d" || exit 1
|
||||
DESIRED_LOCATION=$(basename "$d")
|
||||
DEST=$(dirname "$d")
|
||||
cp -r "$IMAGES/$DESIRED_LOCATION" "$HUGO/$DEST"
|
||||
done <"$IMAGES/image-targets.txt"
|
||||
|
||||
echo Building LaTeX.
|
||||
docker run --user "$(id -u):$(id -g)" -v "$PDFS:/inputs" build-latex sh -c "/build.sh /inputs" || exit 1
|
||||
while read -r texfile
|
||||
do
|
||||
DIR="$HUGO"/$(dirname "$texfile")
|
||||
TEXFILE_BASE=$(basename "$texfile")
|
||||
PDFFILE=$(basename "$texfile" .tex).pdf
|
||||
mkdir -p "$DIR"
|
||||
cp "$PDFS/$TEXFILE_BASE" "$DIR/"
|
||||
cp "$PDFS/$PDFFILE" "$DIR/"
|
||||
done < "$PDFS/pdf-targets.txt"
|
||||
while read -r texfile; do
|
||||
DIR="$HUGO"/$(dirname "$texfile")
|
||||
TEXFILE_BASE=$(basename "$texfile")
|
||||
PDFFILE=$(basename "$texfile" .tex).pdf
|
||||
mkdir -p "$DIR"
|
||||
cp "$PDFS/$TEXFILE_BASE" "$DIR/"
|
||||
cp "$PDFS/$PDFFILE" "$DIR/"
|
||||
done <"$PDFS/pdf-targets.txt"
|
||||
|
||||
echo Building site.
|
||||
docker run --user "$(id -u):$(id -g)" -v "$HUGO:/hugo" -v "$OUTPUT:/output" build-hugo sh -c "/build.sh /hugo /output" || exit 1
|
||||
|
61
build/all.sh
61
build/all.sh
@@ -8,33 +8,31 @@ katex=$5
|
||||
extraContent=$6
|
||||
|
||||
echo "Linking PDFs: $PDF_FOLDER/pdf-targets.txt"
|
||||
while IFS= read -r texfile || [[ -n "$r" ]]
|
||||
do
|
||||
DIR=$(dirname "$texfile")
|
||||
TEXFILE_BASE=$(basename "$texfile")
|
||||
if [ -z "${TEXFILE_BASE}" ]; then
|
||||
echo "Skipping empty line"
|
||||
else
|
||||
PDFFILE=$(basename "$texfile" .tex).pdf
|
||||
mkdir -p "$DIR"
|
||||
echo "$TEXFILE_BASE"
|
||||
echo "$PDFFILE"
|
||||
cp "${pdfs}/$TEXFILE_BASE" "$texfile"
|
||||
cp "${pdfs}/$PDFFILE" "$DIR/"
|
||||
fi
|
||||
done < "${pdfs}/pdf-targets.txt"
|
||||
while IFS= read -r texfile || [[ -n $r ]]; do
|
||||
DIR=$(dirname "$texfile")
|
||||
TEXFILE_BASE=$(basename "$texfile")
|
||||
if [ -z "${TEXFILE_BASE}" ]; then
|
||||
echo "Skipping empty line"
|
||||
else
|
||||
PDFFILE=$(basename "$texfile" .tex).pdf
|
||||
mkdir -p "$DIR"
|
||||
echo "$TEXFILE_BASE"
|
||||
echo "$PDFFILE"
|
||||
cp "${pdfs}/$TEXFILE_BASE" "$texfile"
|
||||
cp "${pdfs}/$PDFFILE" "$DIR/"
|
||||
fi
|
||||
done <"${pdfs}/pdf-targets.txt"
|
||||
|
||||
echo "Linking thumbnails."
|
||||
while IFS= read -r d || [[ -n "$d" ]]
|
||||
do
|
||||
if [ -n "${d}" ]; then
|
||||
DIR=$(dirname "$d")
|
||||
mkdir -p "$DIR" || exit 1
|
||||
DESIRED_LOCATION=$(basename "$d")
|
||||
echo "$d -> $DESIRED_LOCATION"
|
||||
cp -r "${images}/$DESIRED_LOCATION" "$d"
|
||||
fi
|
||||
done < "${images}/image-targets.txt"
|
||||
while IFS= read -r d || [[ -n $d ]]; do
|
||||
if [ -n "${d}" ]; then
|
||||
DIR=$(dirname "$d")
|
||||
mkdir -p "$DIR" || exit 1
|
||||
DESIRED_LOCATION=$(basename "$d")
|
||||
echo "$d -> $DESIRED_LOCATION"
|
||||
cp -r "${images}/$DESIRED_LOCATION" "$d"
|
||||
fi
|
||||
done <"${images}/image-targets.txt"
|
||||
|
||||
echo "Linking Anki decks."
|
||||
mkdir static/AnkiDecks && cp -R "${ankiDecks}/." static/AnkiDecks
|
||||
@@ -47,12 +45,11 @@ cp -r "$katex/dist/contrib" themes/anatole/assets/contrib
|
||||
cp "$katex"/dist/*.js themes/anatole/assets/
|
||||
cp "$katex"/dist/*.css themes/anatole/assets/
|
||||
|
||||
while IFS= read -r file_to_copy
|
||||
do
|
||||
echo "$file_to_copy"
|
||||
sourcefile=$(echo "$file_to_copy" | cut -d ' ' -f 1)
|
||||
destfile=$(echo "$file_to_copy" | cut -d ' ' -f 2-)
|
||||
cp "$extraContent/$sourcefile" "$destfile"
|
||||
done < "$extraContent/map.txt"
|
||||
while IFS= read -r file_to_copy; do
|
||||
echo "$file_to_copy"
|
||||
sourcefile=$(echo "$file_to_copy" | cut -d ' ' -f 1)
|
||||
destfile=$(echo "$file_to_copy" | cut -d ' ' -f 2-)
|
||||
cp "$extraContent/$sourcefile" "$destfile"
|
||||
done <"$extraContent/map.txt"
|
||||
|
||||
/bin/sh "${buildHugo}/run.sh" . ./output
|
||||
|
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
find /work -type f -name 'Dockerfile' -print0 | xargs -0 -n1 hadolint
|
||||
find /work -type f -name 'Dockerfile' -print0 | xargs -0 -n1 hadolint
|
||||
|
@@ -3,5 +3,5 @@
|
||||
SOURCE_DIR=$(readlink -f "$1")
|
||||
OUTPUT_DIR=$(readlink -f "$2")
|
||||
|
||||
rm -rf "${OUTPUT_DIR:?}/*" && \
|
||||
hugo --minify --source "$SOURCE_DIR" --destination "$OUTPUT_DIR"
|
||||
rm -rf "${OUTPUT_DIR:?}/*" &&
|
||||
hugo --minify --source "$SOURCE_DIR" --destination "$OUTPUT_DIR"
|
||||
|
@@ -7,4 +7,4 @@ cp -Rf /git/. /output || exit 1
|
||||
|
||||
chmod -R a+rw /output || exit 1
|
||||
|
||||
touch /sentinels/load.txt
|
||||
touch /sentinels/load.txt
|
||||
|
108
flake.lock
generated
108
flake.lock
generated
@@ -25,7 +25,9 @@
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"scripts": "scripts"
|
||||
},
|
||||
"locked": {
|
||||
@@ -96,34 +98,46 @@
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"scripts": "scripts_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1696067098,
|
||||
"narHash": "sha256-EJzgliSlIVcKGNF80gdqENn7AvC0Mbn0OILofVEdhxA=",
|
||||
"path": "/Users/patrick/Desktop/website/static-site-images",
|
||||
"type": "path"
|
||||
"lastModified": 1696175612,
|
||||
"narHash": "sha256-8V8klzc7T3EdAdS4r8RRjNvTTytQOsvfi7DfK6NFK6M=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "ac0b0180304bce7683dc8b4466a6e92b339c0b7e",
|
||||
"revCount": 15,
|
||||
"type": "git",
|
||||
"url": "file:/Users/patrick/Desktop/website/static-site-images"
|
||||
},
|
||||
"original": {
|
||||
"path": "/Users/patrick/Desktop/website/static-site-images",
|
||||
"type": "path"
|
||||
"type": "git",
|
||||
"url": "file:/Users/patrick/Desktop/website/static-site-images"
|
||||
}
|
||||
},
|
||||
"katex-source": {
|
||||
"flake": false,
|
||||
"katex": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1691244098,
|
||||
"narHash": "sha256-hDHo7JQAo+fGxQvY5OtXlfh+e6PjlVIQPTyCa3Fjg0Y=",
|
||||
"owner": "KaTeX",
|
||||
"lastModified": 1696151934,
|
||||
"narHash": "sha256-8kihcqdgYjoVuGozfgfcWh81yqMUvns4+C/fgkn+RNQ=",
|
||||
"owner": "Smaug123",
|
||||
"repo": "KaTeX",
|
||||
"rev": "4f1d9166749ca4bd669381b84b45589f1500a476",
|
||||
"rev": "ac1f9b30441f63ea20216a36ffa7148dc0e9a9b3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "KaTeX",
|
||||
"owner": "Smaug123",
|
||||
"ref": "nix",
|
||||
"repo": "KaTeX",
|
||||
"rev": "4f1d9166749ca4bd669381b84b45589f1500a476",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -158,68 +172,22 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1688392541,
|
||||
"narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1688392541,
|
||||
"narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_5": {
|
||||
"locked": {
|
||||
"lastModified": 1688392541,
|
||||
"narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pdfs": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": "nixpkgs_5",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"scripts": "scripts_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1696031212,
|
||||
"narHash": "sha256-Aymg9vvPksYIbE5ahOzusmKN8w65n64lv9lY+W+I9nw=",
|
||||
"lastModified": 1696190787,
|
||||
"narHash": "sha256-bO/NInpwVefs5Iey8WVwPFnXPt/3WN7WvYXTxzLKmGQ=",
|
||||
"owner": "Smaug123",
|
||||
"repo": "static-site-pdfs",
|
||||
"rev": "97c35066c1661d2c88c3833c4686f37a9fd7588e",
|
||||
"rev": "a36d3025b9625cc50fc5bd2eca867eacd8a5bcb9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -234,8 +202,8 @@
|
||||
"extra-content": "extra-content",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"images": "images",
|
||||
"katex-source": "katex-source",
|
||||
"nixpkgs": "nixpkgs_4",
|
||||
"katex": "katex",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"pdfs": "pdfs",
|
||||
"scripts": "scripts_4"
|
||||
}
|
||||
|
134
flake.nix
134
flake.nix
@@ -9,20 +9,24 @@
|
||||
url = "path:/Users/patrick/Desktop/website/extra-site-content";
|
||||
flake = false;
|
||||
};
|
||||
katex-source = {
|
||||
url = "github:KaTeX/KaTeX/4f1d9166749ca4bd669381b84b45589f1500a476";
|
||||
flake = false;
|
||||
katex = {
|
||||
url = "github:Smaug123/KaTeX/nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
images = {
|
||||
url = "path:/Users/patrick/Desktop/website/static-site-images";
|
||||
url = "git+file:/Users/patrick/Desktop/website/static-site-images";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
pdfs = {
|
||||
url = "github:Smaug123/static-site-pdfs";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
anki-decks = {
|
||||
url = "github:Smaug123/anki-decks";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
};
|
||||
@@ -31,7 +35,7 @@
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
katex-source,
|
||||
katex,
|
||||
images,
|
||||
pdfs,
|
||||
anki-decks,
|
||||
@@ -40,71 +44,77 @@
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in let
|
||||
buildHugo = scripts.lib.createShellScript pkgs "hugo" ./docker/hugo/build.sh;
|
||||
in let
|
||||
katex-parts = pkgs.stdenv.mkDerivation {
|
||||
__contentAddressed = true;
|
||||
pname = "katex";
|
||||
version = "0.1.0";
|
||||
src = katex.outputs.packages.${system}.default;
|
||||
|
||||
installPhase = ''
|
||||
mkdir "$out"
|
||||
ls -la .
|
||||
cp -r ./libexec/katex/dist "$out/dist"
|
||||
'';
|
||||
};
|
||||
in let
|
||||
website = pkgs.stdenv.mkDerivation {
|
||||
__contentAddressed = true;
|
||||
pname = "patrickstevens.co.uk";
|
||||
version = "0.1.0";
|
||||
|
||||
src = ./hugo;
|
||||
|
||||
buildInputs = [
|
||||
pkgs.hugo
|
||||
pkgs.html-tidy
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
${scripts.lib.createShellScript pkgs "all" ./build/all.sh}/run.sh "${pdfs.packages.${system}.default}" "${images.packages.${system}.default}" "${anki-decks.packages.${system}.default}" "${buildHugo}" "${katex-parts}" "${extra-content}"
|
||||
'';
|
||||
|
||||
checkPhase = ''
|
||||
echo "Linting HTML."
|
||||
${pkgs.html-tidy}/bin/tidy
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mv output $out
|
||||
'';
|
||||
};
|
||||
in rec {
|
||||
packages = flake-utils.lib.flattenTree {
|
||||
gitAndTools = pkgs.gitAndTools;
|
||||
default = website;
|
||||
};
|
||||
defaultPackage =
|
||||
let
|
||||
buildHugo = scripts.lib.createShellScript pkgs "hugo" ./docker/hugo/build.sh;
|
||||
in let
|
||||
katex = pkgs.stdenv.mkDerivation {
|
||||
__contentAddressed = true;
|
||||
pname = "katex";
|
||||
version = "0.1.0";
|
||||
src = katex-source;
|
||||
|
||||
buildInputs = [pkgs.nodejs pkgs.yarn];
|
||||
|
||||
buildPhase = ''
|
||||
export HOME=$(mktemp -d)
|
||||
yarn --immutable
|
||||
yarn build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p "$out/fonts"
|
||||
cp ./fonts/* "$out/fonts"
|
||||
cp -r ./dist "$out/dist"
|
||||
'';
|
||||
};
|
||||
in let
|
||||
extraContent = pkgs.stdenv.mkDerivation {
|
||||
__contentAddressed = true;
|
||||
pname = "patrickstevens.co.uk-extraContent";
|
||||
version = "0.1.0";
|
||||
src = extra-content;
|
||||
buildInputs = [];
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r ./. $out
|
||||
'';
|
||||
};
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
__contentAddressed = true;
|
||||
pname = "patrickstevens.co.uk";
|
||||
version = "0.1.0";
|
||||
|
||||
src = ./hugo;
|
||||
|
||||
buildInputs = [
|
||||
pkgs.hugo
|
||||
pkgs.html-tidy
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
${scripts.lib.createShellScript pkgs "all" ./build/all.sh}/run.sh "${pdfs.packages.${system}.default}" "${images}" "${anki-decks.packages.${system}.default}" "${buildHugo}" "${katex}" "${extraContent}"
|
||||
'';
|
||||
|
||||
checks = {
|
||||
fmt-check = pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "fmt-check";
|
||||
src = ./.;
|
||||
nativeBuildInputs = [pkgs.alejandra pkgs.shellcheck pkgs.shfmt];
|
||||
checkPhase = ''
|
||||
echo "Linting HTML."
|
||||
${pkgs.html-tidy}/bin/tidy
|
||||
find . -type f -name '*.sh' | xargs shfmt -d -s -i 2 -ci
|
||||
alejandra -c .
|
||||
find . -type f -name '*.sh' -exec shellcheck -x {} \;
|
||||
'';
|
||||
installPhase = "mkdir $out";
|
||||
dontBuild = true;
|
||||
doCheck = true;
|
||||
};
|
||||
|
||||
installPhase = ''
|
||||
mv output $out
|
||||
website-check = pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "website-check";
|
||||
src = website;
|
||||
installPhase = "mkdir $out";
|
||||
dontBuild = true;
|
||||
doCheck = true;
|
||||
checkPhase = ''
|
||||
${pkgs.bash}/bin/bash ${scripts.lib.createShellScript pkgs "linkcheck" ./linkcheck.sh}/run.sh ${pkgs.lynx}/bin/lynx
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@@ -10,9 +10,9 @@ I have deleted almost all of the Anki decks on this page, because I think they w
|
||||
They were made during a time when I didn't really know how to use Anki appropriately.
|
||||
Any remaining decks here are CC-BY-SA.
|
||||
|
||||
* [Geography]. You can filter out the `london-tube` tag if you like, or `world-capitals`, or `american-geography`.
|
||||
* [Geography] (the deck has a misleading name; it's actually a general Geography deck). You can filter out the `london-tube` tag if you like, or `world-capitals`, or `american-geography`.
|
||||
|
||||
<a href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB" rel="license"><img style="border-width: 0;" alt="Creative Commons Licence" src="https://licensebuttons.net/l/by-sa/3.0/88x31.png" /></a>
|
||||
This work by <a href="/anki-decks" rel="cc:attributionURL">Patrick Stevens</a> is licensed under a <a href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB" rel="license">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.
|
||||
|
||||
[Geography]: /AnkiDecks/Geography.apkg
|
||||
[Geography]: /AnkiDecks/CapitalsOfTheWorld.apkg
|
@@ -14,7 +14,7 @@ summary: "A fairly long and winding way through a proof of the three Sylow theor
|
||||
---
|
||||
(This post is mostly to set up a kind of structure for the website; in particular, to be the first in a series of posts summarising some mathematical results I stumble across.)
|
||||
|
||||
EDIT: There is now [an Anki deck](/AnkiDecks/SylowTheoremsProof.apkg) of this proof, and a [collection of poems][sylow sonnets] summarising it.
|
||||
EDIT: There is now a [collection of poems][sylow sonnets] summarising this proof.
|
||||
|
||||
In Part IB of the Mathematical Tripos (that is, second-year material), there is a course called Groups, Rings and Modules. I took it in the academic year 2012-2013, when it was lectured by [Imre Leader](https://en.wikipedia.org/wiki/Imre_Leader). He told us that there were three main proofs of the [Sylow theorems](https://en.wikipedia.org/wiki/Sylow_theorems), two of which were horrible and one of which was nice; he presented the "nice" one. At the time, I thought this was the most beautiful proof of anything I'd ever seen, although other people have told me it's a disgusting proof.
|
||||
|
||||
|
@@ -12,7 +12,7 @@ aliases:
|
||||
title: Sum-of-two-squares theorem
|
||||
---
|
||||
|
||||
*Wherein I detail the most beautiful proof of a theorem I've ever seen, in a bite-size form suitable for an Anki deck. I attach the [Anki deck], which contains the bulleted lines of this post as flashcards.*
|
||||
*Wherein I detail the most beautiful proof of a theorem I've ever seen, in a bite-size form suitable for an Anki deck.
|
||||
|
||||
# Statement
|
||||
There's no particularly nice way to motivate this in this context, I'm afraid, so we'll just dive in. I have found this method extremely hard to motivate - a few of the steps are a glorious magic.
|
||||
@@ -32,8 +32,6 @@ Additionally, we'll call a number which is the sum of two squares a **nice** num
|
||||
## First implication: if primes 3 mod 4 appear only to even powers…
|
||||
We prove the result first for the primes, and will then show that niceness is preserved on taking products.
|
||||
|
||||
|
||||
|
||||
* Let \\(p=2\\). Then \\(p\\) is trivially the sum of two squares: it is \\(1+1\\).
|
||||
* Let \\(p\\) be 1 mod 4.
|
||||
* Then modulo \\(p\\), we have \\(-1\\) is square.
|
||||
@@ -81,5 +79,4 @@ That ends the proof. Its beauty lies in the way it regards sums of two squares a
|
||||
[Gaussian integers]: https://en.wikipedia.org/wiki/Gaussian_integers
|
||||
[UFD]: https://en.wikipedia.org/wiki/Unique_factorization_domain
|
||||
[irreducible]: https://en.wikipedia.org/wiki/Irreducible_element
|
||||
[prime]: https://en.wikipedia.org/wiki/Prime_element
|
||||
[Anki deck]: {{< baseurl >}}AnkiDecks/SumOfTwoSquaresTheorem.apkg
|
||||
[prime]: https://en.wikipedia.org/wiki/Prime_element
|
@@ -1,8 +1,8 @@
|
||||
---
|
||||
lastmod: "2023-09-28T00:15:00.0000000+01:00"
|
||||
lastmod: "2023-10-01T00:15:00.0000000+01:00"
|
||||
author: patrick
|
||||
categories:
|
||||
- programming
|
||||
- mathematical_summary
|
||||
date: "2023-09-28T00:15:00Z"
|
||||
title: The tiny proof that primes 1 mod 4 are sums of two squares
|
||||
summary: "Exploding the incredibly terse proof into a bunch of exposition."
|
||||
|
18
hugo/content/posts/2023-10-01-property-based-test-talk.md
Normal file
18
hugo/content/posts/2023-10-01-property-based-test-talk.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
lastmod: "2023-10-01T20:53:00.0000000+01:00"
|
||||
author: patrick
|
||||
categories:
|
||||
- programming
|
||||
- g-research
|
||||
date: "2023-10-01T20:53:00.0000000+01:00"
|
||||
title: Property-based testing introduction
|
||||
summary: "A talk I gave at work introducing property-based testing and then giving some more advanced techniques."
|
||||
---
|
||||
|
||||
A linkpost for [the slides for a talk](/misc/DogeConfPBT/DogeConfPBT.pdf) I gave in 2019 at G-Research.
|
||||
I've put it up now because I keep on losing it and wanting to look stuff up in it.
|
||||
|
||||
We first cover what [property-based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing) is and why you might want to use it.
|
||||
Then we discuss more advanced techniques: how to check that the distribution is sane from which you're drawing tests, and what to do about it if the distribution turns out not to be sane.
|
||||
We next consider how to test stateful systems by modelling the transitions you want it to undergo (ultimately perhaps even progressing to a full alternative immutable implementation of the system, where the property is "the system under test behaves exactly like this reference implementation").
|
||||
Finally we give a warning that while it's possible to sink arbitrary amounts of time and cleverness into testing every corner of your system, you can do much better than most people if you simply start small and stop whenever you think it's worth stopping.
|
77
hugo/content/posts/2023-10-05-nix-fireside-chat.md
Normal file
77
hugo/content/posts/2023-10-05-nix-fireside-chat.md
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
lastmod: "2023-10-05T20:00:00.0000000+01:00"
|
||||
author: patrick
|
||||
categories:
|
||||
- programming
|
||||
- g-research
|
||||
date: "2023-10-05T20:00:00.0000000+01:00"
|
||||
title: Nix fireside chat outline
|
||||
summary: "A talk I gave at work about the Nix build system."
|
||||
---
|
||||
|
||||
This is simply an outline, with no actual content.
|
||||
|
||||
The source of truth remains [Eelco Dolstra's thesis](https://edolstra.github.io/pubs/phd-thesis.pdf).
|
||||
|
||||
# Why Nix
|
||||
|
||||
* "Works on my machine"
|
||||
* Rollbacks and deletion
|
||||
* Multiple simultaneous installations of things
|
||||
* Deduplicate precisely what can be deduplicated
|
||||
|
||||
# Basic ideas
|
||||
|
||||
* Every package describes its build- and run-time dependencies precisely
|
||||
* Cryptographic hashing to identify dependencies
|
||||
* A package is identified by a hash which encompasses itself and all its dependencies
|
||||
* Can find uses of a dependencies by dumb search for hash strings! This… actually works in practice (empirically)!
|
||||
* Lots of rewriting of e.g. hashbangs, library loads, etc
|
||||
* Can dynamically link, but you must know at build time precisely what you'll be dynamically linking
|
||||
* Atomic changes
|
||||
* The *Nix store* holds every package
|
||||
* So you can't just assume something will be in `/usr/bin`
|
||||
* Dynamic linker is intentionally crippled
|
||||
* Notionally read-only and contains the entire world (garbage-collector required)
|
||||
* Reproducible builds
|
||||
* Can cache build results centrally and then download them, rather than rebuilding from source
|
||||
* Upcoming feature: content-addressed Nix store
|
||||
|
||||
# NixOS (and Guix)
|
||||
|
||||
* Key insight: an operating system is just another package
|
||||
* Kernel
|
||||
* Bootloader
|
||||
* Systemd jobs
|
||||
* Shell
|
||||
* All symlinks into the Nix store
|
||||
* Benefits:
|
||||
* Trivial rollback
|
||||
* Can create the new version during normal operation, and then atomically switch to it by flipping a symlink when it's ready
|
||||
* (asterisk: systemd restarts etc)
|
||||
* Same for user environments: `$PATH` is set to a single symlink, and then the target of that symlink is atomically changed for each update
|
||||
* Very unlike most other Linuxes!
|
||||
|
||||
# How a Nix installation works
|
||||
|
||||
* Daemon controls the store, you ask it to build stuff
|
||||
* `/nix/store` is notionally infinite but you can only store finite chunks of it
|
||||
* Database stores:
|
||||
* which parts of the infinite `/nix/store` are known to be correctly instantiated locally
|
||||
* cache of reference graphs
|
||||
* mapping of "which derivation caused each path to be reified on disk"
|
||||
* content hashes, to detect tampering
|
||||
|
||||
# How a package is built
|
||||
|
||||
* Write a Nix expression describing the package
|
||||
* *Instantiate* that expression into a *store derivation*, and put in store
|
||||
* Low-level build instructions for the package
|
||||
* *Realise* (build) that derivation into the store
|
||||
* Download any build artefacts (sources, compilers)
|
||||
* Build e.g. any compilers recursively if necessary, and put in store
|
||||
* Put sources directly into store
|
||||
* Execute the package's builder with the inputs that now exist
|
||||
* Place result in store
|
||||
|
||||
# Flakes (if we have time)
|
70
hugo/content/posts/2023-10-06-smullyan-chess.md
Normal file
70
hugo/content/posts/2023-10-06-smullyan-chess.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
lastmod: "2023-10-06T20:53:00.0000000+01:00"
|
||||
author: patrick
|
||||
categories:
|
||||
- uncategorized
|
||||
date: "2023-10-06T20:53:00.0000000+01:00"
|
||||
title: Raymond Smullyan chess problem walkthrough
|
||||
summary: "The thought process behind solving a particular Raymond Smullyan chess retrograde analysis puzzle."
|
||||
---
|
||||
|
||||

|
||||
|
||||
Raymond Smullyan apparently asked: in the above board, there is one piece missing, the white king.
|
||||
Where is the white king?
|
||||
|
||||
# Thought process
|
||||
|
||||
## Whose move is it?
|
||||
This has to be the first question.
|
||||
|
||||
If it's white to move, then the black king on d1 can't be in check (there's no way it can legally be your move and you're giving check).
|
||||
So the white king would have to be on b3 to block the check.
|
||||
But how could the white king be in check in two different ways, from the rook and bishop?
|
||||
There is no possible way: either the rook, king, or bishop must have moved last (there are no other black pieces), and none of them could have got to where they are while causing a discovered check (or two discovered checks, if it was the king moving!).
|
||||
|
||||
So it's Black to move, and the most recent move was by White.
|
||||
|
||||
## Which piece most recently moved?
|
||||
|
||||
It's either the white king or the white bishop.
|
||||
|
||||
The bishop is very limited in where it could have come from.
|
||||
The black rook and king prevent it coming from anywhere except b3 or c2.
|
||||
But if it came from b3 or c2, then it must have been giving check on the board immediately before it moved (there's no way the white king could be in the way), so the board state wasn't legal.
|
||||
|
||||
So the most recent move was the white king, and it has just moved so as to give check.
|
||||
|
||||
## What was the most recent move?
|
||||
|
||||
The white king *must* have been on b3 so as to reveal the check from the bishop (otherwise the white bishop was giving check throughout the duration of White's last move, which isn't legal).
|
||||
That means it is now on c3 or a3.
|
||||
|
||||
## What is surprising about the king being on b3?
|
||||
|
||||
It's in check, twice!
|
||||
That means Black's most recent move was to give check, in *two* different ways.
|
||||
|
||||
We've already discussed that the discovered checks can't have been set up by moving the rook or bishop: that same reasoning was how we determined that it's currently Black to move.
|
||||
So there must have been a third black piece on the board, which Black moved most recently, and which was taken in White's most recent move.
|
||||
Moreover, the moving of that third piece must have somehow caused a discovered check both from the black bishop and rook.
|
||||
|
||||
## What is the only way that a single piece moving can cause two discovered checks?
|
||||
|
||||
To discover checks along both a vertical and a diagonal, it's necessary to move two pieces in one move.
|
||||
|
||||
* Castling moves two pieces, but we already know the black king has moved, so it wasn't Black castling.
|
||||
* A standard capture does move two pieces, but it leaves the capturing piece in the same place as the captured piece, so it can't reveal two checks.
|
||||
* Moving a piece without capturing moves one piece, and can only reveal one check.
|
||||
* Promoting a pawn could conceivably have had this effect if this were all happening on the back rank: a pawn promoting to a knight can both discover a check from a bishop and cause check with the new knight. But both the pieces which are giving check are in the middle of the board, with neither on the back rank.
|
||||
|
||||
There is exactly one other kind of move in the game: capturing en passant.
|
||||
This can clear a file and a diagonal at the same time.
|
||||
|
||||
## The solution
|
||||
|
||||
* Black's most recent move was to capture a white pawn on c4 en passant using the black pawn on b4. This discovered two checks on the white king which was on b3.
|
||||
* White responded with the move Kxc3+, which is where it is now.
|
||||
|
||||
This is deeply cute!
|
||||
Many thanks to Tim Gowers for retweeting it.
|
58
hugo/content/posts/2023-10-08-guix-bootstrap.md
Normal file
58
hugo/content/posts/2023-10-08-guix-bootstrap.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
lastmod: "2023-10-08T11:43:00.0000000+01:00"
|
||||
author: patrick
|
||||
categories:
|
||||
- programming
|
||||
date: "2023-10-18T11:43:00.0000000+01:00"
|
||||
title: The GUIX bootstrap
|
||||
summary: "Notes for a talk I gave at work on the GUIX bootstrap."
|
||||
---
|
||||
|
||||
This is simply an outline, with no actual content.
|
||||
|
||||
# Why bootstrap?
|
||||
|
||||
* Auditing and security
|
||||
* Seminal paper: [Reflections on Trusting Trust](https://www.cs.cmu.edu/~rdriley/487/papers/Thompson_1984_ReflectionsonTrustingTrust.pdf)
|
||||
|
||||
# How is a system normally installed?
|
||||
|
||||
* Massive binary blob (250MB of gcc, binutils etc) to start a bootstrap
|
||||
* Or an even massiver blob (Windows installer)
|
||||
|
||||
# Necessary tools
|
||||
|
||||
* A C compiler e.g. [TCC](https://bellard.org/tcc/)
|
||||
* Text manipulation e.g. `sed`
|
||||
|
||||
# GUIX Full-Source Bootstrap
|
||||
|
||||
[Official docs](https://guix.gnu.org/en/manual/devel/en/html_node/Full_002dSource-Bootstrap.html).
|
||||
|
||||
## Stage-0
|
||||
|
||||
[Main repo](https://github.com/oriansj/stage0-posix); [kaemfile](https://github.com/oriansj/stage0-posix-x86/blob/e86bf7d304bae5ce5ccc88454bb60cf0837e941f/mescc-tools-mini-kaem.kaem#L97).
|
||||
|
||||
The kernel is trusted; eventually they would like to make no syscalls at all and run on bare metal.
|
||||
(GNU Guix bootstrap kernel is still 25MB.)
|
||||
|
||||
* Base: a [tiny self-hosted assembler](https://github.com/oriansj/bootstrap-seeds/blob/master/POSIX/x86/hex0_x86.hex0) of 357 bytes, incredibly strict language, human-verifiable
|
||||
* [hex1](https://github.com/oriansj/stage0-posix-x86/blob/e86bf7d304bae5ce5ccc88454bb60cf0837e941f/hex1_x86.hex0): a slightly more powerful assembler, better hex parsing, single-character labels and some jumps
|
||||
* [hex2](https://github.com/oriansj/stage0-posix-x86/blob/e86bf7d304bae5ce5ccc88454bb60cf0837e941f/hex2_x86.hex1): an assembler with labels and absolute memory addresses
|
||||
* [catm](https://github.com/oriansj/stage0-posix-x86/blob/e86bf7d304bae5ce5ccc88454bb60cf0837e941f/catm_x86.hex2): an implementation of `cat`
|
||||
* [M0](https://github.com/oriansj/stage0-posix-x86/blob/e86bf7d304bae5ce5ccc88454bb60cf0837e941f/M0_x86.hex2): a C-style preprocessor and a bona-fide assembler which recognises a language you might recognise
|
||||
* [cc-x86](https://github.com/oriansj/stage0-posix-x86/blob/e86bf7d304bae5ce5ccc88454bb60cf0837e941f/cc_x86.M1): a C compiler! (only a subset of C though)
|
||||
* M2-Planet: a slightly better C compiler
|
||||
* [blood-elf-0](https://github.com/oriansj/mescc-tools/blob/master/blood-elf.c): writes [DWARF](https://en.wikipedia.org/wiki/DWARF) stubs for debug tables (but no actual implementation of those stubs)
|
||||
* M1: a better C compiler which is debuggable and implements some optimisations (TODO: example?)
|
||||
* Rebuild earlier inputs now that we have an optimising compiler
|
||||
* blood-elf again: provides implementations for the stubs `blood-elf-0` wrote (TODO: is that true? Understand the nature of the stubs and implementation)
|
||||
* A variety of nice things like `sha256sum`, `mkdir`, `untar`, primitive `cp`, `chmod`
|
||||
* [kaem](https://github.com/oriansj/kaem/tree/master): a tiny build system (anagram of `make`)
|
||||
|
||||
## GNU Mes
|
||||
|
||||
[Mes](https://www.gnu.org/software/mes/) is an intertwined pair of a C compiler and Scheme interpreter; its source is mirrored [on GitHub](https://github.com/gnu-mirror-unofficial/mes).
|
||||
It can be built with `kaem`, and the resulting C compiler can build [TCC](https://bellard.org/tcc/), which can then build early GCC, which can bootstrap later GCCs and hence support for other languages and architectures.
|
||||
|
||||
As of a few years ago, they were experimenting with using the Mes Scheme compiler to compile [Gash](https://savannah.nongnu.org/projects/gash), an interpreted Scheme POSIX shell which could replace some of the binary blob.
|
37
linkcheck.sh
Normal file
37
linkcheck.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
bad=0
|
||||
|
||||
LYNX=$1
|
||||
|
||||
evaluate_file() {
|
||||
target=$1
|
||||
links=$("$LYNX" -dump --listonly -image_links --nonumbers -hiddenlinks=listonly "$target" | awk '
|
||||
/Visible links/ {
|
||||
found=1
|
||||
next
|
||||
}
|
||||
found { print }
|
||||
' | grep 'file:' | cut -d '/' -f 3- | grep -v '#')
|
||||
|
||||
# hurr durrr accidentally quadratic
|
||||
for link in $links; do
|
||||
filename=".$link"
|
||||
if [ -d "$filename" ]; then
|
||||
filename="$filename/index.html"
|
||||
fi
|
||||
|
||||
if ! [ -e "$filename" ]; then
|
||||
echo "File does not exist, while parsing '$target': $filename" >&2
|
||||
bad=1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
while IFS= read -d '' -u3 -r file; do
|
||||
evaluate_file "$file"
|
||||
done 3< <(find . -type f -name '*.html' -print0)
|
||||
|
||||
if [ $bad -eq 1 ]; then
|
||||
exit $bad
|
||||
fi
|
Reference in New Issue
Block a user