diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..679e84c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+site/photos/*.html
+site/photos/*/*.html
+site/photos/*/mid
+site/photos/*/thm
+photos/*.html
+photos/*/*.html
+photos/*/mid
+photos/*/thm
+www/*
+code/*
+site/uugcal/*
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..eb81376
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,120 @@
+WWW = ${PWD}/www
+SITE = ${PWD}/site
+SCRIPTS = ${PWD}/scripts
+LOCAL = /var/www/htdocs
+REMOTE = sdk@codevoid.de:/home/www/htdocs/shagen
+
+# do everything by default
+all: build-and-upload-all
+ @echo "done."
+
+# Create the photo galleries and create the index and preview html
+# pages in site/, so they get parsed in the compile step
+PHOTODIRS != find photos/* -maxdepth 0 -mindepth 0 -type d
+photos: ${PHOTODIRS}
+ mkdir -p ${SITE}/photos
+ cd photos && sh ${SCRIPTS}/mkphotoindex.sh > index.html
+ find photos -type f -not -name "*.html" -exec install -D {} www/{} \;
+ find photos -type f -name "*.html" -exec install -D {} site/{} \;
+
+optimize:
+ find photos -name "*.jpg" -type f -exec jpegoptim -w 12 --all-progressive --strip-all "{}" +
+
+calendar:
+ mkdir -p ${SITE}/uugcal
+ cd ${SITE}/uugcal && sh ${SCRIPTS}/mkuugcalendar.sh > index.html
+
+${PHOTODIRS}:
+ cd "$@" && sh ${SCRIPTS}/mkphotos.sh > index.html
+
+# invoke zod and compile the website into the www/ dir
+compile:
+ mkdir -p ${WWW}
+ zod ${SITE} ${WWW}
+
+# after mixing different generators in the compile step, let's tidy and
+# indent the output properly (XXX is there a tool that does _only_
+# indent?)
+tidy:
+ find ${WWW} -type f -name "*.html" \
+ -exec tidy -q -i -m -c -w 120 -f /dev/null {} \;
+ find ${WWW} -type f -name "*.html" \
+ -exec sed -i '/.*meta name="generator".*/d' {} \;
+
+# create gzip variants of text files, so they can be served by httpds
+# gzip-static extension
+gzip:
+ find ${WWW} -type f \
+ \( -name "*.html" -o -name "*.css" \) \
+ -exec gzip -kf9 {} \;
+
+# set permissions so the web server can read the file
+fixperms:
+ doas chown -R sdk:www ${WWW}
+ doas chmod -R ugo+wrX,go-w ${WWW}
+
+# we can upload to the local and the remote webserver at the same time
+upload-local: stagit
+ doas rsync -a --delete ${WWW}/ ${LOCAL}/
+upload-remote: stagit
+ doas rsync -a --delete -e ssh ${WWW}/ ${REMOTE}/
+upload-all: upload-local upload-remote
+
+build:
+ make clean; \
+ make photos; \
+ make stagit; \
+ make calendar; \
+ make compile; \
+ make tidy; \
+ make fixperms;
+
+build-and-upload-all:
+ make build; \
+ make upload-all;
+
+# deploy to the local webserver for preview
+local:
+ make build; \
+ make upload-local;
+remote:
+ make build; \
+ make upload-remote
+
+# clean up temporary files and everything that can be regenerated very fast
+clean:
+ rm -rf ${WWW}/photos
+ rm -rf ${SITE}/photos
+ rm -f photos/index.html
+ rm -f photos/*/*.html
+ rm -rf ${SITE}/uugcal
+ rm -rf ${WWW}
+
+# clean and also delete all generated images
+realclean: clean
+ rm -rf photos/*/{thm,mid}
+
+
+### TARGETS BELOW ARE ONLY FOR CONVENIENCE
+
+stagit:
+ scripts/reposync.sh
+
+git-add:
+ find site/photos -type f \
+ -not -name "*.html" \
+ -not -path "*/thm/*" \
+ -not -path "*/mid/*" \
+ -exec git add "{}" +
+
+# watch files and rebuild automatically
+notify:
+ ulimit -n 1024; \
+ find ${SITE} ${SCRIPTS} -not -path "*/photos/*" -type f \
+ | inotifywait -m -e modify --fromfile - \
+ | while read line; \
+ do \
+ make; \
+ done
+
+.PHONY: ${PHOTODIRS} ${REPOS}
diff --git a/config b/config
new file mode 100644
index 0000000..0c4ce33
--- /dev/null
+++ b/config
@@ -0,0 +1,11 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+[remote "origin"]
+ url = git@github.com:c0dev0id/website.git
+ fetch = +refs/heads/*:refs/remotes/origin/*
+[branch "main"]
+ remote = origin
+ merge = refs/heads/main
diff --git a/scripts/mkphotoindex.sh b/scripts/mkphotoindex.sh
new file mode 100644
index 0000000..b2a57f4
--- /dev/null
+++ b/scripts/mkphotoindex.sh
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+
+echo "
My Photos "
+[ -f index.txt ] && cat index.txt
+
+
+makelink() {
+ _text="$(echo "$1" | sed 's/-/ /g;s/_/ - /g;s/\(....\) \(..\) \(..\)/\1-\2-\3/')"
+ echo "${_text} "
+}
+
+echo "Events: "
+
+echo ""
+find * -maxdepth 0 -mindepth 0 -type d \
+ | grep "^20" \
+ | grep -v "unlisted" \
+ | sort -r \
+ | while read _dir
+do
+ makelink "$_dir"
+done
+echo " "
+
+echo "Collections: "
+
+echo ""
+find * -maxdepth 0 -mindepth 0 -type d \
+ | grep -v "^20" \
+ | grep -v "unlisted" \
+ | sort -r \
+ | while read _dir
+do
+ makelink "$_dir"
+done
+echo " "
diff --git a/scripts/mkphotos.sh b/scripts/mkphotos.sh
new file mode 100644
index 0000000..77d2000
--- /dev/null
+++ b/scripts/mkphotos.sh
@@ -0,0 +1,90 @@
+#!/bin/sh -e
+
+## settings
+
+DIR="$(basename "$PWD")"
+TITLE="$(basename "$PWD" |sed 's/unlisted-//g' | cut -d"_" -f2- | tr '-' ' ')"
+
+mkdir -p thm mid
+
+echo "$TITLE "
+[ -f index.txt ] && cat index.txt
+
+echo ""
+echo "
"
+echo ""
+
+_count=0
+find * -maxdepth 0 -mindepth 0 -type f \( -iname "*.jpg" \
+ -o -iname "*.jpeg" \
+ -o -iname "*.png" \
+ -o -iname "*.gif" \
+ \) \
+ | sort -r | while read _file
+do
+ _file_thm="thm/${_file%%.*}.jpg"
+ _file_mid="mid/${_file%%.*}.jpg"
+ _file_html="${_file%%.*}.html"
+ _file_descr="${_file%%.*}.txt"
+
+ # increase file counter
+ _count=$(( _count + 1))
+
+ if [ ! -f "${_file_thm}" ]
+ then
+ convert -quality 73 \
+ -sharpen 2x2 \
+ -auto-orient \
+ -define jpeg:size=440x440 \
+ "$_file" \
+ -thumbnail 220x220^ \
+ -gravity center \
+ -extent 220x220 \
+ "${_file_thm}" \
+ >/dev/null 2>&1 &
+ fi
+
+ if [ ! -f "${_file_mid}" ]
+ then
+ convert -quality 83 \
+ -sharpen 2x2 \
+ -auto-orient \
+ -define jpeg:size=1440x2400 \
+ "$_file" \
+ -thumbnail 720x1600 \
+ "${_file_mid}" \
+ >/dev/null 2>&1 &
+ fi
+ if [ ! -f "${_file_html}" ]
+ then
+ echo "$TITLE " > "${_file_html}"
+ echo "File: ${_file} (Open Original )
" >> "${_file_html}"
+ echo "
" >> "${_file_html}"
+ [ -f "${_file_descr}" ] && cat "${_file_descr}" >> "${_file_html}"
+ echo "Back to Index
" >> "${_file_html}"
+ fi
+
+ echo " "
+ if [ $(( _count % 3 )) -eq 0 ]
+ then
+ echo " "
+ fi
+
+ while [ $(pgrep convert | wc -l) -ge 15 ]
+ do sleep 0.3; done
+
+done
+echo " "
+echo "
"
+echo ""
+
+echo "Back to the gallery index
"
+echo "section: photos" > dir.meta
+
+wait
+
+# it looks like wait doesn't catch processes spawned
+# in a subshell. So we check explicitely for running
+# convert processes. XXX
+while [ $(pgrep convert | wc -l) -ge 1 ]
+do sleep 1; done
diff --git a/scripts/mkuugcalendar.sh b/scripts/mkuugcalendar.sh
new file mode 100644
index 0000000..b859d89
--- /dev/null
+++ b/scripts/mkuugcalendar.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+REM=$(curl -s "https://raw.githubusercontent.com/c0dev0id/dotfiles/main/.reminders/uugrn.rem")
+rm -f uugrn-calendar.*
+
+echo "$REM" | remind -b1 -p24 - 2>/dev/null | rem2pdf > uugrn-calendar.pdf
+echo "$REM" | remind -b1 -p24 - 2>/dev/null | rem2html --nostyle --tableonly > uugrn-calendar.html
+echo "$REM" | remind -b1 -p24 - 2>/dev/null | rem2ics > uugrn-calendar.ics
+
+echo "UUGRN Calendar "
+echo ""
+
diff --git a/scripts/reposync.sh b/scripts/reposync.sh
new file mode 100755
index 0000000..9a098cb
--- /dev/null
+++ b/scripts/reposync.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+add_repo() {(
+ _dir="$(basename "$1")"
+ if [ -d "code/${_dir}" ]
+ then
+ ( cd code/${_dir} && git pull )
+ else
+ ( cd code && git clone "https://$1" )
+ fi
+
+ _fulldir=$(readlink -f "code/${_dir}")
+ mkdir -p www/code/${_dir}
+ cp site/code/*.{css,png} www/code/${_dir}/
+ cd www/code/${_dir}
+ stagit -u https://stefanhagen.de/code ${_fulldir}
+)}
+
+mkdir -p code
+add_repo "github.com/c0dev0id/dotfiles"
+add_repo "github.com/c0dev0id/mkpicindex"
+add_repo "github.com/c0dev0id/mystuff"
+add_repo "github.com/c0dev0id/website"
+add_repo "github.com/c0dev0id/xpick"
+add_repo "github.com/luakit/luakit"
+
+
+_repos="$(find code/* -mindepth 0 -maxdepth 0 -type d)"
+
+stagit-index ${_repos} > www/code/index.html
diff --git a/scripts/tikz.lua b/scripts/tikz.lua
new file mode 100644
index 0000000..0d1e64b
--- /dev/null
+++ b/scripts/tikz.lua
@@ -0,0 +1,65 @@
+local system = require 'pandoc.system'
+
+local tikz_doc_template = [[
+\documentclass{standalone}
+\usepackage[pdftex]{graphics}
+\usepackage[pdftex]{graphicx}
+\usepackage{xcolor}
+\usepackage{tikz}
+\begin{document}
+\nopagecolor
+%s
+\end{document}
+]]
+
+local function tikz2image(src, filetype, outfile)
+ system.with_temporary_directory('tikz2image', function (tmpdir)
+ system.with_working_directory(tmpdir, function()
+ local f = io.open('tikz.tex', 'w')
+ f:write(tikz_doc_template:format(src))
+ f:close()
+ os.execute('pdflatex tikz.tex >/dev/null 2>&1')
+ if filetype == 'pdf' then
+ os.rename('tikz.pdf', outfile)
+ else
+ os.execute('pdf2svg tikz.pdf ' .. outfile .. '>/dev/null 2>&1')
+ end
+ end)
+ end)
+end
+
+extension_for = {
+ html = 'svg',
+ html4 = 'svg',
+ html5 = 'svg',
+ latex = 'pdf',
+ beamer = 'pdf' }
+
+local function file_exists(name)
+ local f = io.open(name, 'r')
+ if f ~= nil then
+ io.close(f)
+ return true
+ else
+ return false
+ end
+end
+
+local function starts_with(start, str)
+ return str:sub(1, #start) == start
+end
+
+
+function RawBlock(el)
+ if starts_with('\\begin{tikzpicture}', el.text) then
+ local filetype = extension_for[FORMAT] or 'svg'
+ local fbasename = pandoc.sha1(el.text) .. '.' .. filetype
+ local fname = system.get_working_directory() .. '/' .. fbasename
+ if not file_exists(fname) then
+ tikz2image(el.text, filetype, fname)
+ end
+ return pandoc.Para({pandoc.Image({}, fbasename)})
+ else
+ return el
+ end
+end
diff --git a/site/.zod/config b/site/.zod/config
new file mode 100644
index 0000000..17b3246
--- /dev/null
+++ b/site/.zod/config
@@ -0,0 +1,47 @@
+; This is an example zodiac configuration file
+; A line starting with a `;` is a comment and is ignored.
+
+; The `parse` section is for page templates that will not be converted to
+; HTML via an external utility.
+;
+; [parse]
+; extension,extension
+; extension
+; ...
+;
+
+
+; [parse]
+; htm
+; html
+
+
+; The `parse_convert` section is for page templates that will be converted
+; to HTML via an external utility.
+;
+; By default, page templates with the `md` extension are piped through the
+; built-in awk implementation of Markdown.
+;
+; [parse_convert]
+; extension,extension command
+; extension command
+; ...
+
+
+[parse_convert]
+sh sh
+md discount
+adoc asciidoctor -r asciidoctor-diagram -a data-uri -a allow-uri-read -a svg-embed -a diagram-svg-type=inline -a showtitle -a icons=image -a icontype=svg -a iconsdir=site/images/icons -s -
+tex pandoc --embed-resources --lua-filter scripts/tikz.lua
+; md,markdown discount
+; txt asciidoc -s -
+
+
+; The `ignore` section is for patterns that zodiac will ignore when
+; searching the project directory. Ignored files will not be parsed or
+; copied to the target directory.
+;
+; [ignore]
+; pattern
+; pattern
+; ...
diff --git a/site/asciidoctor.css b/site/asciidoctor.css
new file mode 100644
index 0000000..4b0a83d
--- /dev/null
+++ b/site/asciidoctor.css
@@ -0,0 +1,2068 @@
+/* This is (was) the default asciidoctor.css file from
+ * https://github.com/asciidoctor/asciidoctor
+ *
+ * XXX Frankly, I'm just fiddling around here so it doesn't interfere with the
+ * site layout too much. I'd would rather not have it at all and gradually pick
+ * what is needed into the site.css.
+ */
+
+abbr {
+ font-size: 0.9em;
+}
+
+abbr[title] {
+ cursor: help;
+ border-bottom: 1px dotted #dddddf;
+ text-decoration: none;
+}
+
+b,
+strong {
+ font-weight: bold;
+ line-height: inherit;
+}
+
+strong strong {
+ font-weight: 400;
+}
+
+code,
+kbd,
+pre {
+ font-size: 1em;
+}
+
+code {
+ font-weight: 400;
+}
+
+pre {
+ line-height: 1.45;
+ text-rendering: optimizeSpeed;
+ white-space: pre-wrap;
+}
+
+dfn {
+ font-style: italic;
+}
+
+em,
+i {
+ font-style: italic;
+ line-height: inherit;
+}
+
+em em {
+ font-style: normal;
+}
+
+hr {
+ border: solid #dddddf;
+ border-width: 1px 0 0;
+ clear: both;
+ height: 0;
+ margin: 1.25em 0 1.1875em;
+}
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+p {
+ line-height: 1.6;
+ margin-bottom: 1.25rem;
+ text-rendering: optimizeLegibility;
+}
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+small {
+ font-size: 60%;
+ line-height: inherit;
+}
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+img,
+object[type^="image/"],
+svg {
+ display: inline-block;
+ height: auto;
+ max-width: 100%;
+ vertical-align: middle;
+}
+
+img {
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+
+object {
+ max-width: 100%;
+}
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+figure {
+ margin: 0;
+}
+
+audio,
+video {
+ display: inline-block;
+}
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+.left {
+ float: left !important;
+}
+
+.right {
+ float: right !important;
+}
+
+.text-left {
+ text-align: left !important;
+}
+
+.text-right {
+ text-align: right !important;
+}
+
+.text-center {
+ text-align: center !important;
+}
+
+.text-justify {
+ text-align: justify !important;
+}
+
+.hide {
+ display: none;
+}
+
+.subheader,
+.admonitionblock td.content > .title,
+.audioblock > .title,
+.exampleblock > .title,
+.imageblock > .title,
+.listingblock > .title,
+.literalblock > .title,
+.stemblock > .title,
+.openblock > .title,
+.paragraph > .title,
+.quoteblock > .title,
+table.tableblock > .title,
+.verseblock > .title,
+.videoblock > .title,
+.dlist > .title,
+.olist > .title,
+.ulist > .title,
+.qlist > .title,
+.hdlist > .title {
+ line-height: 1.45;
+ color: #7a2518;
+ font-weight: 400;
+ margin-top: 0;
+ margin-bottom: 0.25em;
+}
+
+p aside {
+ font-size: 0.875em;
+ line-height: 1.35;
+ font-style: italic;
+}
+
+ul li ul,
+ul li ol {
+ margin-left: 1.25em;
+ margin-bottom: 0;
+}
+
+ul.circle {
+ list-style-type: circle;
+}
+
+ul.disc {
+ list-style-type: disc;
+}
+
+ul.square {
+ list-style-type: square;
+}
+
+ul.circle ul:not([class]),
+ul.disc ul:not([class]),
+ul.square ul:not([class]) {
+ list-style: inherit;
+}
+
+ol li ul,
+ol li ol {
+ margin-left: 1.25em;
+ margin-bottom: 0;
+}
+
+dl dt {
+ margin-bottom: 0.3125em;
+ font-weight: bold;
+}
+
+dl dd {
+ margin-bottom: 1.25em;
+ margin-left: 1.125em;
+}
+
+blockquote {
+ margin: 0 0 1.25em;
+ padding: 0.5625em 1.25em 0 1.1875em;
+ border-left: 1px solid #ddd;
+}
+
+blockquote,
+blockquote p {
+ line-height: 1.6;
+ color: rgb(0 0 0 / 0.85);
+}
+
+@media screen and (min-width: 768px) {
+ h1 {
+ font-size: 2.75em;
+ }
+
+ h2 {
+ font-size: 2.3125em;
+ }
+
+ h3,
+ #toctitle,
+ .sidebarblock > .content > .title {
+ font-size: 1.6875em;
+ }
+
+ h4 {
+ font-size: 1.4375em;
+ }
+}
+
+table {
+ background: #fff;
+ border: 1px solid #dedede;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-bottom: 1.25em;
+ word-wrap: normal;
+}
+
+table thead,
+table tfoot {
+ background: #f7f8f7;
+}
+
+table thead tr th,
+table thead tr td,
+table tfoot tr th,
+table tfoot tr td {
+ padding: 0.5em 0.625em 0.625em;
+ font-size: inherit;
+ color: rgb(0 0 0 / 0.8);
+ text-align: left;
+}
+
+table tr th,
+table tr td {
+ padding: 0.5625em 0.625em;
+ font-size: inherit;
+ color: rgb(0 0 0 / 0.8);
+}
+
+table tr.even,
+table tr.alt {
+ background: #f8f8f7;
+}
+
+table thead tr th,
+table tfoot tr th,
+table tbody tr td,
+table tr td,
+table tfoot tr td {
+ line-height: 1.6;
+}
+
+h1 strong,
+h2 strong,
+h3 strong,
+#toctitle strong,
+.sidebarblock > .content > .title strong,
+h4 strong,
+h5 strong,
+h6 strong {
+ font-weight: 400;
+}
+
+.center {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.stretch {
+ width: 100%;
+}
+
+.clearfix::before,
+.clearfix::after,
+.float-group::before,
+.float-group::after {
+ content: "";
+ display: table;
+}
+
+.clearfix::after,
+.float-group::after {
+ clear: both;
+}
+
+:not(pre).nobreak {
+ word-wrap: normal;
+}
+
+:not(pre).nowrap {
+ white-space: nowrap;
+}
+
+:not(pre).pre-wrap {
+ white-space: pre-wrap;
+}
+
+:not(pre):not([class^=L]) > code {
+ font-size: 0.9375em;
+ font-style: normal !important;
+ letter-spacing: 0;
+ padding: 0.1em 0.5ex;
+ word-spacing: -0.15em;
+ background: #f7f7f8;
+ border-radius: 4px;
+ line-height: 1.45;
+ text-rendering: optimizeSpeed;
+}
+
+pre code,
+pre pre {
+ color: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+pre > code {
+ display: block;
+}
+
+pre.nowrap,
+pre.nowrap pre {
+ white-space: pre;
+ word-wrap: normal;
+}
+
+.keyseq {
+ color: rgb(51 51 51 / 0.8);
+}
+
+kbd {
+ display: inline-block;
+ color: rgb(0 0 0 / 0.8);
+ font-size: 0.65em;
+ line-height: 1.45;
+ background: #f7f7f7;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ box-shadow: 0 1px 0 rgb(0 0 0 / 0.2), 0 0 0 0.1em #fff inset;
+ margin: 0 0.15em;
+ padding: 0.2em 0.5em;
+ vertical-align: middle;
+ position: relative;
+ top: -0.1em;
+ white-space: nowrap;
+}
+
+.keyseq kbd:first-child {
+ margin-left: 0;
+}
+
+.keyseq kbd:last-child {
+ margin-right: 0;
+}
+
+.menuseq,
+.menuref {
+ color: #000;
+}
+
+.menuseq b:not(.caret),
+.menuref {
+ font-weight: inherit;
+}
+
+.menuseq {
+ word-spacing: -0.02em;
+}
+
+.menuseq b.caret {
+ font-size: 1.25em;
+ line-height: 0.8;
+}
+
+.menuseq i.caret {
+ font-weight: bold;
+ text-align: center;
+ width: 0.45em;
+}
+
+b.button::before,
+b.button::after {
+ position: relative;
+ top: -1px;
+ font-weight: 400;
+}
+
+b.button::before {
+ content: "[";
+ padding: 0 3px 0 2px;
+}
+
+b.button::after {
+ content: "]";
+ padding: 0 2px 0 3px;
+}
+
+p a > code:hover {
+ color: rgb(0 0 0 / 0.9);
+}
+
+body > div[id] {
+ margin: 0 auto;
+ max-width: 62.5em;
+ position: relative;
+ padding-left: 0.9375em;
+ padding-right: 0.9375em;
+ width: 100%;
+}
+
+body > div[id]::before,
+body > div[id]::after,
+#content #footnotes::before {
+ content: "";
+ display: table;
+ clear: both;
+}
+
+#content {
+ margin-top: 1.25em;
+ margin-bottom: 0.625em;
+}
+
+#content::before {
+ content: none;
+}
+
+#header > h1:first-child {
+ color: rgb(0 0 0 / 0.85);
+ margin-top: 2.25rem;
+ margin-bottom: 0;
+}
+
+#header > h1:first-child + #toc {
+ margin-top: 8px;
+ border-top: 1px solid #dddddf;
+}
+
+#header > h1:only-child,
+body.toc2 #header > h1:nth-last-child(2) {
+ border-bottom: 1px solid #dddddf;
+ padding-bottom: 8px;
+}
+
+#header .details {
+ border-bottom: 1px solid #dddddf;
+ line-height: 1.45;
+ padding-top: 0.25em;
+ padding-bottom: 0.25em;
+ padding-left: 0.25em;
+ color: rgb(0 0 0 / 0.6);
+ display: flex;
+ flex-flow: row wrap;
+}
+
+#header .details span:first-child {
+ margin-left: -0.125em;
+}
+
+#header .details span.email a {
+ color: rgb(0 0 0 / 0.85);
+}
+
+#header .details br {
+ display: none;
+}
+
+#header .details br + span::before {
+ content: "\00a0\2013\00a0";
+}
+
+#header .details br + span.author::before {
+ content: "\00a0\22c5\00a0";
+ color: rgb(0 0 0 / 0.85);
+}
+
+#header .details br + span#revremark::before {
+ content: "\00a0|\00a0";
+}
+
+#header #revnumber {
+ text-transform: capitalize;
+}
+
+#header #revnumber::after {
+ content: "\00a0";
+}
+
+#content > h1:first-child:not([class]) {
+ color: rgb(0 0 0 / 0.85);
+ border-bottom: 1px solid #dddddf;
+ padding-bottom: 8px;
+ margin-top: 0;
+ padding-top: 1rem;
+ margin-bottom: 1.25rem;
+}
+
+#toc {
+ border-bottom: 1px solid #e7e7e9;
+ padding-bottom: 0.5em;
+}
+
+#toc > ul {
+ margin-left: 0.125em;
+}
+
+#toc ul.sectlevel0 > li > a {
+ font-style: italic;
+}
+
+#toc ul.sectlevel0 ul.sectlevel1 {
+ margin: 0.5em 0;
+}
+
+#toc ul {
+ list-style-type: none;
+}
+
+#toc li {
+ line-height: 1.3334;
+ margin-top: 0.3334em;
+}
+
+#toc a {
+ text-decoration: none;
+}
+
+#toc a:active {
+ text-decoration: underline;
+}
+
+#toctitle {
+ color: #7a2518;
+ font-size: 1.2em;
+}
+
+@media screen and (min-width: 768px) {
+ #toctitle {
+ font-size: 1.375em;
+ }
+
+ body.toc2 {
+ padding-left: 15em;
+ padding-right: 0;
+ }
+
+ #toc.toc2 {
+ margin-top: 0 !important;
+ background: #f8f8f7;
+ position: fixed;
+ width: 15em;
+ left: 0;
+ top: 0;
+ border-right: 1px solid #e7e7e9;
+ border-top-width: 0 !important;
+ border-bottom-width: 0 !important;
+ z-index: 1000;
+ padding: 1.25em 1em;
+ height: 100%;
+ overflow: auto;
+ }
+
+ #toc.toc2 #toctitle {
+ margin-top: 0;
+ margin-bottom: 0.8rem;
+ font-size: 1.2em;
+ }
+
+ #toc.toc2 > ul {
+ font-size: 0.9em;
+ margin-bottom: 0;
+ }
+
+ #toc.toc2 ul ul {
+ margin-left: 0;
+ padding-left: 1em;
+ }
+
+ #toc.toc2 ul.sectlevel0 ul.sectlevel1 {
+ padding-left: 0;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+
+ body.toc2.toc-right {
+ padding-left: 0;
+ padding-right: 15em;
+ }
+
+ body.toc2.toc-right #toc.toc2 {
+ border-right-width: 0;
+ border-left: 1px solid #e7e7e9;
+ left: auto;
+ right: 0;
+ }
+}
+
+@media screen and (min-width: 1280px) {
+ body.toc2 {
+ padding-left: 20em;
+ padding-right: 0;
+ }
+
+ #toc.toc2 {
+ width: 20em;
+ }
+
+ #toc.toc2 #toctitle {
+ font-size: 1.375em;
+ }
+
+ #toc.toc2 > ul {
+ font-size: 0.95em;
+ }
+
+ #toc.toc2 ul ul {
+ padding-left: 1.25em;
+ }
+
+ body.toc2.toc-right {
+ padding-left: 0;
+ padding-right: 20em;
+ }
+}
+
+#content #toc {
+ border: 1px solid #e0e0dc;
+ margin-bottom: 1.25em;
+ padding: 1.25em;
+ background: #f8f8f7;
+ border-radius: 4px;
+}
+
+#footer {
+ max-width: none;
+ background: rgb(0 0 0 / 0.8);
+ padding: 1.25em;
+}
+
+#footer-text {
+ color: rgb(255 255 255 / 0.8);
+ line-height: 1.44;
+}
+
+.sect1, .sect0 {
+ padding: 0;
+}
+
+div#preamble {
+ padding: 0;
+}
+
+@media screen and (min-width: 768px) {
+
+#content h1 > a.anchor,
+h2 > a.anchor,
+h3 > a.anchor,
+#toctitle > a.anchor,
+.sidebarblock > .content > .title > a.anchor,
+h4 > a.anchor,
+h5 > a.anchor,
+h6 > a.anchor {
+ position: absolute;
+ z-index: 1001;
+ width: 1.5ex;
+ margin-left: -1.5ex;
+ display: block;
+ text-decoration: none !important;
+ visibility: hidden;
+ text-align: center;
+ font-weight: 400;
+}
+
+#content h1 > a.anchor::before,
+h2 > a.anchor::before,
+h3 > a.anchor::before,
+#toctitle > a.anchor::before,
+.sidebarblock > .content > .title > a.anchor::before,
+h4 > a.anchor::before,
+h5 > a.anchor::before,
+h6 > a.anchor::before {
+ content: "\00A7";
+ font-size: 0.85em;
+ display: block;
+ padding-top: 0.1em;
+}
+
+#content h1:hover > a.anchor,
+#content h1 > a.anchor:hover,
+h2:hover > a.anchor,
+h2 > a.anchor:hover,
+h3:hover > a.anchor,
+#toctitle:hover > a.anchor,
+.sidebarblock > .content > .title:hover > a.anchor,
+h3 > a.anchor:hover,
+#toctitle > a.anchor:hover,
+.sidebarblock > .content > .title > a.anchor:hover,
+h4:hover > a.anchor,
+h4 > a.anchor:hover,
+h5:hover > a.anchor,
+h5 > a.anchor:hover,
+h6:hover > a.anchor,
+h6 > a.anchor:hover {
+ visibility: visible;
+}
+
+#content h1 > a.link,
+h2 > a.link,
+h3 > a.link,
+#toctitle > a.link,
+.sidebarblock > .content > .title > a.link,
+h4 > a.link,
+h5 > a.link,
+h6 > a.link {
+ color: #ba3925;
+ text-decoration: none;
+}
+
+#content h1 > a.link:hover,
+h2 > a.link:hover,
+h3 > a.link:hover,
+#toctitle > a.link:hover,
+.sidebarblock > .content > .title > a.link:hover,
+h4 > a.link:hover,
+h5 > a.link:hover,
+h6 > a.link:hover {
+ color: #a53221;
+}
+
+details,
+.audioblock,
+.imageblock,
+.literalblock,
+.listingblock,
+.stemblock,
+.videoblock {
+ margin-bottom: 1.25em;
+}
+
+details {
+ margin-left: 1.25rem;
+}
+
+details > summary {
+ cursor: pointer;
+ display: block;
+ position: relative;
+ line-height: 1.6;
+ margin-bottom: 0.625rem;
+ outline: none;
+ -webkit-tap-highlight-color: transparent;
+}
+
+details > summary::-webkit-details-marker {
+ display: none;
+}
+
+details > summary::before {
+ content: "";
+ border: solid transparent;
+ border-left-color: currentColor;
+ border-width: 0.3em 0 0.3em 0.5em;
+ position: absolute;
+ top: 0.5em;
+ left: -1.25rem;
+ transform: translateX(15%);
+}
+
+details[open] > summary::before {
+ border: solid transparent;
+ border-top-color: currentColor;
+ border-width: 0.5em 0.3em 0;
+ transform: translateY(15%);
+}
+
+details > summary::after {
+ content: "";
+ width: 1.25rem;
+ height: 1em;
+ position: absolute;
+ top: 0.3em;
+ left: -1.25rem;
+}
+
+.admonitionblock td.content > .title,
+.audioblock > .title,
+.exampleblock > .title,
+.imageblock > .title,
+.listingblock > .title,
+.literalblock > .title,
+.stemblock > .title,
+.openblock > .title,
+.paragraph > .title,
+.quoteblock > .title,
+table.tableblock > .title,
+.verseblock > .title,
+.videoblock > .title,
+.dlist > .title,
+.olist > .title,
+.ulist > .title,
+.qlist > .title,
+.hdlist > .title {
+ text-rendering: optimizeLegibility;
+ text-align: left;
+ font-size: 1rem;
+ font-style: italic;
+}
+
+table.tableblock.fit-content > caption.title {
+ white-space: nowrap;
+ width: 0;
+}
+
+.admonitionblock > table {
+ border-collapse: separate;
+ border: 0;
+ background: none;
+ width: 100%;
+}
+
+.admonitionblock > table td.icon {
+ text-align: center;
+ width: 80px;
+}
+
+.admonitionblock > table td.icon img {
+ max-width: none;
+}
+
+.admonitionblock > table td.icon .title {
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+.admonitionblock > table td.content {
+ padding-left: 1.125em;
+ padding-right: 1.25em;
+ border-left: 1px solid #dddddf;
+ color: rgb(0 0 0 / 0.6);
+ word-wrap: anywhere;
+}
+
+.admonitionblock > table td.content > :last-child > :last-child {
+ margin-bottom: 0;
+}
+
+.exampleblock > .content {
+ border: 1px solid #e0e0dc;
+ margin-bottom: 1.25em;
+ padding: 1.25em;
+ background: #fffef7;
+ border-radius: 4px;
+ box-shadow: 0 1px 4px #e0e0dc;
+}
+
+.sidebarblock {
+ border: 1px solid #dbdbd6;
+ margin-bottom: 1.25em;
+ padding: 1.25em;
+ background: #f3f3f2;
+ border-radius: 4px;
+}
+
+.sidebarblock > .content > .title {
+ color: #7a2518;
+ margin-top: 0;
+ text-align: center;
+}
+
+#content #toc > :first-child,
+.exampleblock > .content > :first-child,
+.sidebarblock > .content > :first-child {
+ margin-top: 0;
+}
+
+#content #toc > :last-child,
+.exampleblock > .content > :last-child,
+.exampleblock > .content > :last-child > :last-child,
+.exampleblock > .content .olist > ol > li:last-child > :last-child,
+.exampleblock > .content .ulist > ul > li:last-child > :last-child,
+.exampleblock > .content .qlist > ol > li:last-child > :last-child,
+.sidebarblock > .content > :last-child,
+.sidebarblock > .content > :last-child > :last-child,
+.sidebarblock > .content .olist > ol > li:last-child > :last-child,
+.sidebarblock > .content .ulist > ul > li:last-child > :last-child,
+.sidebarblock > .content .qlist > ol > li:last-child > :last-child {
+ margin-bottom: 0;
+}
+
+.literalblock pre,
+.listingblock > .content > pre {
+ border-radius: 4px;
+ overflow-x: auto;
+ padding: 1em;
+ font-size: 0.8125em;
+}
+
+@media screen and (min-width: 768px) {
+ .literalblock pre,
+ .listingblock > .content > pre {
+ font-size: 0.90625em;
+ }
+}
+
+@media screen and (min-width: 1280px) {
+ .literalblock pre,
+ .listingblock > .content > pre {
+ font-size: 1em;
+ }
+}
+
+.literalblock pre,
+.listingblock > .content > pre:not(.highlight),
+.listingblock > .content > pre[class=highlight],
+.listingblock > .content > pre[class^="highlight "] {
+ background: #f7f7f8;
+}
+
+.literalblock.output pre {
+ color: #f7f7f8;
+ background: rgb(0 0 0 / 0.9);
+}
+
+.listingblock > .content {
+ position: relative;
+}
+
+.listingblock code[data-lang]::before {
+ display: none;
+ content: attr(data-lang);
+ position: absolute;
+ font-size: 0.75em;
+ top: 0.425rem;
+ right: 0.5rem;
+ line-height: 1;
+ text-transform: uppercase;
+ color: inherit;
+ opacity: 0.5;
+}
+
+.listingblock:hover code[data-lang]::before {
+ display: block;
+}
+
+.listingblock.terminal pre .command::before {
+ content: attr(data-prompt);
+ padding-right: 0.5em;
+ color: inherit;
+ opacity: 0.5;
+}
+
+.listingblock.terminal pre .command:not([data-prompt])::before {
+ content: "$";
+}
+
+.listingblock pre.highlightjs {
+ padding: 0;
+}
+
+.listingblock pre.highlightjs > code {
+ padding: 1em;
+ border-radius: 4px;
+}
+
+.listingblock pre.prettyprint {
+ border-width: 0;
+}
+
+.prettyprint {
+ background: #f7f7f8;
+}
+
+pre.prettyprint .linenums {
+ line-height: 1.45;
+ margin-left: 2em;
+}
+
+pre.prettyprint li {
+ background: none;
+ list-style-type: inherit;
+ padding-left: 0;
+}
+
+pre.prettyprint li code[data-lang]::before {
+ opacity: 1;
+}
+
+pre.prettyprint li:not(:first-child) code[data-lang]::before {
+ display: none;
+}
+
+table.linenotable {
+ border-collapse: separate;
+ border: 0;
+ margin-bottom: 0;
+ background: none;
+}
+
+table.linenotable td[class] {
+ color: inherit;
+ vertical-align: top;
+ padding: 0;
+ line-height: inherit;
+ white-space: normal;
+}
+
+table.linenotable td.code {
+ padding-left: 0.75em;
+}
+
+table.linenotable td.linenos {
+ width: 0.01%;
+}
+
+table.linenotable td.linenos,
+pre.pygments .linenos,
+pre.rouge .linenos {
+ border-right: 1px solid;
+ opacity: 0.35;
+ padding-right: 0.5em;
+ user-select: none;
+}
+
+pre.pygments span.linenos,
+pre.rouge span.linenos {
+ display: inline-block;
+ margin-right: 0.75em;
+}
+
+.quoteblock {
+ margin: 0 1em 1.25em 1.5em;
+ display: table;
+}
+
+.quoteblock:not(.excerpt) > .title {
+ margin-left: -1.5em;
+ margin-bottom: 0.75em;
+}
+
+.quoteblock blockquote,
+.quoteblock p {
+ color: rgb(0 0 0 / 0.85);
+ font-size: 1.15rem;
+ line-height: 1.75;
+ word-spacing: 0.1em;
+ letter-spacing: 0;
+ font-style: italic;
+ text-align: justify;
+}
+
+.quoteblock blockquote {
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+
+.quoteblock blockquote::before {
+ content: "\201c";
+ float: left;
+ font-size: 2.75em;
+ font-weight: bold;
+ line-height: 0.6em;
+ margin-left: -0.6em;
+ color: #7a2518;
+ text-shadow: 0 1px 2px rgb(0 0 0 / 0.1);
+}
+
+.quoteblock blockquote > .paragraph:last-child p {
+ margin-bottom: 0;
+}
+
+.quoteblock .attribution {
+ margin-top: 0.75em;
+ margin-right: 0.5ex;
+ text-align: right;
+}
+
+.verseblock {
+ margin: 0 1em 1.25em;
+}
+
+.verseblock pre {
+ font-size: 1.15rem;
+ color: rgb(0 0 0 / 0.85);
+ font-weight: 300;
+ text-rendering: optimizeLegibility;
+}
+
+.verseblock pre strong {
+ font-weight: 400;
+}
+
+.verseblock .attribution {
+ margin-top: 1.25rem;
+ margin-left: 0.5ex;
+}
+
+.quoteblock .attribution,
+.verseblock .attribution {
+ font-size: 0.9375em;
+ line-height: 1.45;
+ font-style: italic;
+}
+
+.quoteblock .attribution br,
+.verseblock .attribution br {
+ display: none;
+}
+
+.quoteblock .attribution cite,
+.verseblock .attribution cite {
+ display: block;
+ letter-spacing: -0.025em;
+ color: rgb(0 0 0 / 0.6);
+}
+
+.quoteblock.abstract blockquote::before,
+.quoteblock.excerpt blockquote::before,
+.quoteblock .quoteblock blockquote::before {
+ display: none;
+}
+
+.quoteblock.abstract blockquote,
+.quoteblock.abstract p,
+.quoteblock.excerpt blockquote,
+.quoteblock.excerpt p,
+.quoteblock .quoteblock blockquote,
+.quoteblock .quoteblock p {
+ line-height: 1.6;
+ word-spacing: 0;
+}
+
+.quoteblock.abstract {
+ margin: 0 1em 1.25em;
+ display: block;
+}
+
+.quoteblock.abstract > .title {
+ margin: 0 0 0.375em;
+ font-size: 1.15em;
+ text-align: center;
+}
+
+.quoteblock.excerpt > blockquote,
+.quoteblock .quoteblock {
+ padding: 0 0 0.25em 1em;
+ border-left: 0.25em solid #dddddf;
+}
+
+.quoteblock.excerpt,
+.quoteblock .quoteblock {
+ margin-left: 0;
+}
+
+.quoteblock.excerpt blockquote,
+.quoteblock.excerpt p,
+.quoteblock .quoteblock blockquote,
+.quoteblock .quoteblock p {
+ color: inherit;
+}
+
+.quoteblock.excerpt .attribution,
+.quoteblock .quoteblock .attribution {
+ color: inherit;
+ font-size: 0.85rem;
+ text-align: left;
+ margin-right: 0;
+}
+
+p.tableblock:last-child {
+ margin-bottom: 0;
+}
+
+td.tableblock > .content {
+ margin-bottom: 1.25em;
+ word-wrap: anywhere;
+}
+
+td.tableblock > .content > :last-child {
+ margin-bottom: -1.25em;
+}
+
+table.tableblock,
+th.tableblock,
+td.tableblock {
+ border: 0 solid #dedede;
+}
+
+table.grid-all > * > tr > * {
+ border-width: 1px;
+}
+
+table.grid-cols > * > tr > * {
+ border-width: 0 1px;
+}
+
+table.grid-rows > * > tr > * {
+ border-width: 1px 0;
+}
+
+table.frame-all {
+ border-width: 1px;
+}
+
+table.frame-ends {
+ border-width: 1px 0;
+}
+
+table.frame-sides {
+ border-width: 0 1px;
+}
+
+table.frame-none > colgroup + * > :first-child > *,
+table.frame-sides > colgroup + * > :first-child > * {
+ border-top-width: 0;
+}
+
+table.frame-none > :last-child > :last-child > *,
+table.frame-sides > :last-child > :last-child > * {
+ border-bottom-width: 0;
+}
+
+table.frame-none > * > tr > :first-child,
+table.frame-ends > * > tr > :first-child {
+ border-left-width: 0;
+}
+
+table.frame-none > * > tr > :last-child,
+table.frame-ends > * > tr > :last-child {
+ border-right-width: 0;
+}
+
+table.stripes-all > * > tr,
+table.stripes-odd > * > tr:nth-of-type(odd),
+table.stripes-even > * > tr:nth-of-type(even),
+table.stripes-hover > * > tr:hover {
+ background: #f8f8f7;
+}
+
+th.halign-left,
+td.halign-left {
+ text-align: left;
+}
+
+th.halign-right,
+td.halign-right {
+ text-align: right;
+}
+
+th.halign-center,
+td.halign-center {
+ text-align: center;
+}
+
+th.valign-top,
+td.valign-top {
+ vertical-align: top;
+}
+
+th.valign-bottom,
+td.valign-bottom {
+ vertical-align: bottom;
+}
+
+th.valign-middle,
+td.valign-middle {
+ vertical-align: middle;
+}
+
+table thead th,
+table tfoot th {
+ font-weight: bold;
+}
+
+tbody tr th {
+ background: #f7f8f7;
+}
+
+tbody tr th,
+tbody tr th p,
+tfoot tr th,
+tfoot tr th p {
+ color: rgb(0 0 0 / 0.8);
+ font-weight: bold;
+}
+
+p.tableblock > code:only-child {
+ background: none;
+ padding: 0;
+}
+
+p.tableblock {
+ font-size: 1em;
+}
+
+ol {
+ margin-left: 1.75em;
+}
+
+ul li ol {
+ margin-left: 1.5em;
+}
+
+dl dd:last-child,
+dl dd:last-child > :last-child {
+ margin-bottom: 0;
+}
+
+li p,
+ul dd,
+ol dd,
+.olist .olist,
+.ulist .ulist,
+.ulist .olist,
+.olist .ulist {
+ margin-bottom: 0.625em;
+}
+
+ul.checklist,
+ul.none,
+ol.none,
+ul.no-bullet,
+ol.no-bullet,
+ol.unnumbered,
+ul.unstyled,
+ol.unstyled {
+ list-style-type: none;
+}
+
+ul.no-bullet,
+ol.no-bullet,
+ol.unnumbered {
+ margin-left: 0.625em;
+}
+
+ul.unstyled,
+ol.unstyled {
+ margin-left: 0;
+}
+
+li > p:empty:only-child::before {
+ content: "";
+ display: inline-block;
+}
+
+ul.checklist > li > p:first-child {
+ margin-left: -1em;
+}
+
+ul.checklist > li > p:first-child > .fa-square-o:first-child,
+ul.checklist > li > p:first-child > .fa-check-square-o:first-child {
+ width: 1.25em;
+ font-size: 0.8em;
+ position: relative;
+ bottom: 0.125em;
+}
+
+ul.checklist > li > p:first-child > input[type=checkbox]:first-child {
+ font: inherit;
+ margin: 0 0.25em 0 0;
+ padding: 0;
+}
+
+ul.inline {
+ display: flex;
+ flex-flow: row wrap;
+ list-style: none;
+ margin: 0 0 0.625em -1.25em;
+}
+
+ul.inline > li {
+ margin-left: 1.25em;
+}
+
+.unstyled dl dt {
+ font-weight: 400;
+ font-style: normal;
+}
+
+ol.arabic {
+ list-style-type: decimal;
+}
+
+ol.decimal {
+ list-style-type: decimal-leading-zero;
+}
+
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+ol.lowergreek {
+ list-style-type: lower-greek;
+}
+
+.hdlist > table,
+.colist > table {
+ border: 0;
+ background: none;
+}
+
+.hdlist > table > tbody > tr,
+.colist > table > tbody > tr {
+ background: none;
+}
+
+td.hdlist1,
+td.hdlist2 {
+ vertical-align: top;
+ padding: 0 0.625em;
+}
+
+td.hdlist1 {
+ font-weight: bold;
+ padding-bottom: 1.25em;
+}
+
+td.hdlist2 {
+ word-wrap: anywhere;
+}
+
+.literalblock + .colist,
+.listingblock + .colist {
+ margin-top: -0.5em;
+}
+
+.colist td:not([class]):first-child {
+ padding: 0.4em 0.75em 0;
+ line-height: 1;
+ vertical-align: top;
+}
+
+.colist td:not([class]):first-child img {
+ max-width: none;
+}
+
+.colist td:not([class]):last-child {
+ padding: 0.25em 0;
+}
+
+.thumb,
+.th {
+ line-height: 0;
+ display: inline-block;
+ border: 4px solid #fff;
+ box-shadow: 0 0 0 1px #ddd;
+}
+
+.imageblock.left {
+ margin: 0.25em 0.625em 1.25em 0;
+}
+
+.imageblock.right {
+ margin: 0.25em 0 1.25em 0.625em;
+}
+
+.imageblock > .title {
+ margin-bottom: 0;
+}
+
+.imageblock.thumb,
+.imageblock.th {
+ border-width: 6px;
+}
+
+.imageblock.thumb > .title,
+.imageblock.th > .title {
+ padding: 0 0.125em;
+}
+
+.image.left,
+.image.right {
+ margin-top: 0.25em;
+ margin-bottom: 0.25em;
+ display: inline-block;
+ line-height: 0;
+}
+
+.image.left {
+ margin-right: 0.625em;
+}
+
+.image.right {
+ margin-left: 0.625em;
+}
+
+a.image {
+ text-decoration: none;
+ display: inline-block;
+}
+
+a.image object {
+ pointer-events: none;
+}
+
+sup.footnote,
+sup.footnoteref {
+ font-size: 0.875em;
+ position: static;
+ vertical-align: super;
+}
+
+sup.footnote a,
+sup.footnoteref a {
+ text-decoration: none;
+}
+
+sup.footnote a:active,
+sup.footnoteref a:active {
+ text-decoration: underline;
+}
+
+#footnotes {
+ padding-top: 0.75em;
+ padding-bottom: 0.75em;
+ margin-bottom: 0.625em;
+}
+
+#footnotes hr {
+ width: 20%;
+ min-width: 6.25em;
+ margin: -0.25em 0 0.75em;
+ border-width: 1px 0 0;
+}
+
+#footnotes .footnote {
+ padding: 0 0.375em 0 0.225em;
+ line-height: 1.3334;
+ font-size: 0.875em;
+ margin-left: 1.2em;
+ margin-bottom: 0.2em;
+}
+
+#footnotes .footnote a:first-of-type {
+ font-weight: bold;
+ text-decoration: none;
+ margin-left: -1.05em;
+}
+
+#footnotes .footnote:last-of-type {
+ margin-bottom: 0;
+}
+
+#content #footnotes {
+ margin-top: -0.625em;
+ margin-bottom: 0;
+ padding: 0.75em 0;
+}
+
+div.page-break {
+ display: none;
+}
+
+div.unbreakable {
+ page-break-inside: avoid;
+}
+
+.big {
+ font-size: larger;
+}
+
+.small {
+ font-size: smaller;
+}
+
+.underline {
+ text-decoration: underline;
+}
+
+.overline {
+ text-decoration: overline;
+}
+
+.line-through {
+ text-decoration: line-through;
+}
+
+.aqua {
+ color: #00bfbf;
+}
+
+.aqua-background {
+ background: #00fafa;
+}
+
+.black {
+ color: #000;
+}
+
+.black-background {
+ background: #000;
+}
+
+.blue {
+ color: #0000bf;
+}
+
+.blue-background {
+ background: #0000fa;
+}
+
+.fuchsia {
+ color: #bf00bf;
+}
+
+.fuchsia-background {
+ background: #fa00fa;
+}
+
+.gray {
+ color: #606060;
+}
+
+.gray-background {
+ background: #7d7d7d;
+}
+
+.green {
+ color: #006000;
+}
+
+.green-background {
+ background: #007d00;
+}
+
+.lime {
+ color: #00bf00;
+}
+
+.lime-background {
+ background: #00fa00;
+}
+
+.maroon {
+ color: #600000;
+}
+
+.maroon-background {
+ background: #7d0000;
+}
+
+.navy {
+ color: #000060;
+}
+
+.navy-background {
+ background: #00007d;
+}
+
+.olive {
+ color: #606000;
+}
+
+.olive-background {
+ background: #7d7d00;
+}
+
+.purple {
+ color: #600060;
+}
+
+.purple-background {
+ background: #7d007d;
+}
+
+.red {
+ color: #bf0000;
+}
+
+.red-background {
+ background: #fa0000;
+}
+
+.silver {
+ color: #909090;
+}
+
+.silver-background {
+ background: #bcbcbc;
+}
+
+.teal {
+ color: #006060;
+}
+
+.teal-background {
+ background: #007d7d;
+}
+
+.white {
+ color: #bfbfbf;
+}
+
+.white-background {
+ background: #fafafa;
+}
+
+.yellow {
+ color: #bfbf00;
+}
+
+.yellow-background {
+ background: #fafa00;
+}
+
+span.icon > .fa {
+ cursor: default;
+}
+
+a span.icon > .fa {
+ cursor: inherit;
+}
+
+.admonitionblock td.icon [class^="fa icon-"] {
+ font-size: 2.5em;
+ text-shadow: 1px 1px 2px rgb(0 0 0 / 0.5);
+ cursor: default;
+}
+
+.admonitionblock td.icon .icon-note::before {
+ content: "\f05a";
+ color: #19407c;
+}
+
+.admonitionblock td.icon .icon-tip::before {
+ content: "\f0eb";
+ text-shadow: 1px 1px 2px rgb(155 155 0 / 0.8);
+ color: #111;
+}
+
+.admonitionblock td.icon .icon-warning::before {
+ content: "\f071";
+ color: #bf6900;
+}
+
+.admonitionblock td.icon .icon-caution::before {
+ content: "\f06d";
+ color: #bf3400;
+}
+
+.admonitionblock td.icon .icon-important::before {
+ content: "\f06a";
+ color: #bf0000;
+}
+
+.conum[data-value] {
+ display: inline-block;
+ color: #fff !important;
+ background: rgb(0 0 0 / 0.8);
+ border-radius: 50%;
+ text-align: center;
+ font-size: 0.75em;
+ width: 1.67em;
+ height: 1.67em;
+ line-height: 1.67em;
+ font-style: normal;
+ font-weight: bold;
+}
+
+.conum[data-value] * {
+ color: #fff !important;
+}
+
+.conum[data-value] + b {
+ display: none;
+}
+
+.conum[data-value]::after {
+ content: attr(data-value);
+}
+
+pre .conum[data-value] {
+ position: relative;
+ top: -0.125em;
+}
+
+b.conum * {
+ color: inherit !important;
+}
+
+.conum:not([data-value]):empty {
+ display: none;
+}
+
+dt,
+th.tableblock,
+td.content,
+div.footnote {
+ text-rendering: optimizeLegibility;
+}
+
+p,
+td.content,
+span.alt,
+summary {
+ letter-spacing: -0.01em;
+}
+
+p strong,
+td.content strong,
+div.footnote strong {
+ letter-spacing: -0.005em;
+}
+
+.sidebarblock p,
+.sidebarblock dt,
+.sidebarblock td.content,
+p.tableblock {
+ font-size: 1em;
+}
+
+.print-only {
+ display: none !important;
+}
+
+@page {
+ margin: 1.25cm 0.75cm;
+}
+
+@media print {
+ * {
+ box-shadow: none !important;
+ text-shadow: none !important;
+ }
+
+ html {
+ font-size: 80%;
+ }
+
+ a {
+ color: inherit !important;
+ text-decoration: underline !important;
+ }
+
+ a.bare,
+ a[href^="#"],
+ a[href^="mailto:"] {
+ text-decoration: none !important;
+ }
+
+ a[href^="http:"]:not(.bare)::after,
+ a[href^="https:"]:not(.bare)::after {
+ content: "(" attr(href) ")";
+ display: inline-block;
+ font-size: 0.875em;
+ padding-left: 0.25em;
+ }
+
+ abbr[title] {
+ border-bottom: 1px dotted;
+ }
+
+ abbr[title]::after {
+ content: " (" attr(title) ")";
+ }
+
+ pre,
+ blockquote,
+ tr,
+ img,
+ object,
+ svg {
+ page-break-inside: avoid;
+ }
+
+ thead {
+ display: table-header-group;
+ }
+
+ p,
+ blockquote,
+ dt,
+ td.content {
+ font-size: 1em;
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3,
+ #toctitle,
+ .sidebarblock > .content > .title {
+ page-break-after: avoid;
+ }
+
+ body > div[id] {
+ max-width: none;
+ }
+
+ #toc,
+ .sidebarblock,
+ .exampleblock > .content {
+ background: none !important;
+ }
+
+ #toc {
+ border-bottom: 1px solid #dddddf !important;
+ padding-bottom: 0 !important;
+ }
+
+ body.book #header {
+ text-align: center;
+ }
+
+ body.book #header > h1:first-child {
+ border: 0 !important;
+ margin: 2.5em 0 1em;
+ }
+
+ body.book #header .details {
+ border: 0 !important;
+ display: block;
+ padding: 0 !important;
+ }
+
+ body.book #header .details span:first-child {
+ margin-left: 0 !important;
+ }
+
+ body.book #header .details br {
+ display: block;
+ }
+
+ body.book #header .details br + span::before {
+ content: none !important;
+ }
+
+ body.book #toc {
+ border: 0 !important;
+ text-align: left !important;
+ padding: 0 !important;
+ margin: 0 !important;
+ }
+
+ body.book #toc,
+ body.book h1.sect0,
+ body.book .sect1 > h2 {
+ page-break-before: always;
+ }
+
+ .listingblock code[data-lang]::before {
+ display: block;
+ }
+
+ div.page-break {
+ display: block;
+ page-break-after: always;
+ }
+
+ #footer {
+ padding: 0 0.9375em;
+ }
+
+ .hide-on-print {
+ display: none !important;
+ }
+
+ .print-only {
+ display: block !important;
+ }
+
+ .hide-for-print {
+ display: none !important;
+ }
+
+ .show-for-print {
+ display: inherit !important;
+ }
+}
+
+@media amzn-kf8, print {
+ #header > h1:first-child {
+ margin-top: 1.25rem;
+ }
+
+ .sect1 + .sect1 {
+ border: 0;
+ }
+
+ #footer {
+ background: none;
+ }
+
+ #footer-text {
+ color: rgb(0 0 0 / 0.6);
+ font-size: 0.9em;
+ }
+}
+
+@media amzn-kf8 {
+ body > div[id] {
+ padding: 0;
+ }
+}
diff --git a/site/blog.md b/site/blog.md
new file mode 100644
index 0000000..ad92f47
--- /dev/null
+++ b/site/blog.md
@@ -0,0 +1,17 @@
+# Blog
+
+These are my blog posts
+
+* 2021-09-26 [Memory management, virtual and residential memory](/blog/2021-09-26-memory-management.html)
+* 2021-01-09 [Mutt inline patch handling](/blog/2021-01-09-mutt-inline-patch-macro.html)
+* 2020-11-14 [OpenBSD Full Disk Encryption (FDE) Setup](/blog/2020-11-14-openbsd-fde.html)
+* 2020-05-17 [Dark-Mode in Browsers](/blog/2020-05-17-browser-dark-mode.html)
+* 2019-10-24 [Building an OpenBSD Kernel](/blog/2019-10-24-building-an-openbsd-kernel.html)
+* 2019-10-17 [LineageOS on the Motorola Z2 Force](/blog/2019-10-17-LineageOS-on-Motorola-Z2-Force.html)
+* 2019-04-27 [Manage dotfiles with git](/blog/2019-04-27-manage-dotfiles-with-git.html)
+
+*Note that the $ and # in my blog posts have meaning.*
+
+$ run this command as user
+# run this command as root (or prepend doas/sudo)
+
diff --git a/site/blog.meta b/site/blog.meta
new file mode 100644
index 0000000..4ceb086
--- /dev/null
+++ b/site/blog.meta
@@ -0,0 +1,2 @@
+title: Blog
+section: blog
diff --git a/site/blog/2019-04-27-manage-dotfiles-with-git.md b/site/blog/2019-04-27-manage-dotfiles-with-git.md
new file mode 100644
index 0000000..a27d99c
--- /dev/null
+++ b/site/blog/2019-04-27-manage-dotfiles-with-git.md
@@ -0,0 +1,58 @@
+# Manage dotfiles with git
+
+I'm managing my dotfiles with git. My method serves me well for a few
+years already and so I think it's time to write it down.
+
+If you think git, you might think of a dotfile repository and dozens of
+symlinks into the home directory. This is precisely what kept me from
+using git until I discovered bare repositories.
+
+Create your dotfile repository with the `--bare` parameter
+
+
+git init --bare ${HOME}/.cfg
+
+
+This creates only a folder for git control files, which normally reside
+inside the `.git` folder within the repository.
+
+You can now tell git to use `${HOME}` as your work-tree directory. This
+makes git handle your home directory like all the files would be within
+the git repository. Now you can:
+
+
+git --git-dir=${HOME}/.cfg/ --work-tree=${HOME} add .vimrc
+git --git-dir=${HOME}/.cfg/ --work-tree=${HOME} commit -m "my .vimrc"
+
+
+If course it is silly to type out such a long command every time you
+want to interract with your dotfiles. So why not create an alias?
+
+
+alias config='git --git-dir=${HOME}/.cfg/ --work-tree=${HOME}'
+
+
+Put this in your `~/.bashrc` or `~/.kshrc` and you can now use the command
+`config` in the same way you usually use git.
+
+
+config add .vimrc
+config commit -m "my vimrc"
+
+
+Maybe you have been brave and typed `config status` already. This will
+list the content of your whole home directory as "untracked files". This
+is not what we want. We can run `git config` and tell it to stop doing
+this. But of course we must run our git, which is called `config`.
+
+
+config config --local status.showUntrackedFiles no
+
+
+Now git status will only check what's being tracked. So if you add
+your vimrc file and later change it, `config status` will show it,
+`config diff` will diff it...
+
+You can now use the power of git with your new `config` command.
+
+The solution is not perfect, but it comes pretty close...
diff --git a/site/blog/2019-10-17-LineageOS-on-Motorola-Z2-Force.md b/site/blog/2019-10-17-LineageOS-on-Motorola-Z2-Force.md
new file mode 100644
index 0000000..47a3012
--- /dev/null
+++ b/site/blog/2019-10-17-LineageOS-on-Motorola-Z2-Force.md
@@ -0,0 +1,42 @@
+# LineageOS on Motorola Z2 Force
+
+Whenever there is a major LineageOS Update, chances are that I forgot
+the flashing process. So here are the notes.
+
+Disclaimer: Due to the missing tools to flash from OpenBSD, I use my
+work computer, which runs windows.
+
+*Required Downloads:*
+
+* [Android Platform Tools](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)
+ (contains adb and fastboot)
+* [Motorola Smart Assistant](https://support.lenovo.com/us/en/downloads/ds101291) (contains USB drivers for fastboot)
+
+*Prepare:*
+
+- Install motorola smart assistant
+- Extract platform-tools make sure you're in the platform tools
+ directory or that they are in your $PATH.
+
+*Update steps:*
+
+- > Boot into bootloader (power+down)
+- $ fastboot flash boot_a <lineageos_recovery>.img
+- $ fastboot flash boot_b <lineageos_recovery>.img
+- > Boot into bootloader (power+down) -> Boot Recovery
+- > Factory Reset -> Wipe data / factory reset + Wipe System
+- > Apply update -> adb sideload
+- $ adb sideload <lineageos>.zip
+- $ adb sideload <addons>.zip
+- > Reboot
+
+$ == commandline activity
+> == phone activity
+
+*Notes:*
+
+* "adb devices" works without USB drivers
+* "fastboot devices" shows nothing if USB drivers are not installed
+* This phone has two boot areas and therefore "fastboot flash boot" will
+ fail. The areas "boot_a" and "boot_b" must be used instead. If "boot_a"
+ and "boot_b" are flashed differently, booting will fail.
diff --git a/site/blog/2019-10-24-building-an-openbsd-kernel.md b/site/blog/2019-10-24-building-an-openbsd-kernel.md
new file mode 100644
index 0000000..8e2ed26
--- /dev/null
+++ b/site/blog/2019-10-24-building-an-openbsd-kernel.md
@@ -0,0 +1,47 @@
+# Building an OpenBSD Kernel
+
+I'm running OpenBSD-current for a while in order to support my port.
+It's only one port at the moment, but that's a start, right?
+
+Anyway... every once in a while I stumble over a patch on the OpenBSD
+mailing list I want to try and this requires me to apply the patch and
+build the Kernel with it. But how?
+
+Well, the documentation is where
+[where you would expect it](https://www.openbsd.org/faq/faq5.html#Custom).
+
+*Download the kernel source*
+
+
+# cd /usr
+# cvs -qd anoncvs@anoncvs.ca.openbsd.org:/cvs checkout -P src
+
+
+*Update the kernel source (if you downloaded it a while ago)*
+
+
+# cd /usr/src
+# cvs -q up -Pd
+
+
+*Configure Kernel*
+
+
+# cd /usr/src/sys/arch/amd64/conf
+# cp GENERIC.MP MYKERNEL
+# config MYKERNEL
+
+
+*Build and install kernel (amd64)*
+
+
+# cd /sys/arch/amd64/compile/MYKERNEL
+# make clean
+# make
+# make install # the old kernel is /obsd now
+
+
+That's it. Reboot.
+
+This is ONLY the Kernel. If you need to build the whole system, please
+consult the OpenBSD documentation. The manpage release(8) is a good start.
diff --git a/site/blog/2020-05-17-browser-dark-mode.md b/site/blog/2020-05-17-browser-dark-mode.md
new file mode 100644
index 0000000..0fba212
--- /dev/null
+++ b/site/blog/2020-05-17-browser-dark-mode.md
@@ -0,0 +1,55 @@
+# Browser Dark Mode
+
+Dark Mode luckily has become a thing also in the non-unix world. Finally
+browsers can be used with dark interfaces and websites can have
+alternative color schemes.
+
+However, in other operating systems, there is a global toggle for dark
+mode, which also switches the browser into it. This is not the case on
+linux and unix systems.
+
+## Chrome / Chromium / Iridium
+
+Chrome and Chromium starting with version 73 can be tought to start in
+dark mode:
+
+
+$ chrome --enable-features=WebUIDarkMode --force-dark-mode
+
+
+Then go to chrome://settings/?search=themes and switch the theme to
+"Classic".
+
+## Firefox
+
+Firefox learned the dark mode in release 70.
+
+ 0. Go to "about:config"
+ 1. Enter "ui.systemUsesDarkTheme" into the search bar
+ 2. Click "Number" and then "+"
+ 3. Enter "1" and click the check mark
+
+Right click on a free spot in the icon bar and select "customize". At
+the bottom left of the screen, you can switch to a dark theme.
+
+Note: If you've set privacy.resistFingerprinting to "true" the CSS dark
+mode switching won't work. Kudus to
+[@andinus@tilde.zone](https://tilde.zone/@andinus) for figuring this out.
+
+There you go, both browsers are in dark mode now. The UI should be dark
+and also websites that support the `@media (prefers-color-scheme: dark)`
+directive should make use of it.
+
+You can test it on my webpage ([https://codevoid.de](https://codevoid.de)). The
+light version has a light gray background and a blue font. The dark version has
+a dark gray background and an orange font.
+
+## vim-browser (vimb)
+
+
+$ echo "set dark-mode=true" >> ${HOME}/.config/vimb/config
+
+
+## luakit
+
+Open `:settings` and check `application.prefer_dark_mode`
diff --git a/site/blog/2020-11-14-openbsd-fde.md b/site/blog/2020-11-14-openbsd-fde.md
new file mode 100644
index 0000000..c16ca16
--- /dev/null
+++ b/site/blog/2020-11-14-openbsd-fde.md
@@ -0,0 +1,32 @@
+# OpenBSD FDE Setup
+
+This is a condensed version of [OpenBSD FDE
+FAQ](https://www.openbsd.org/faq/faq14.html#softraid).
+
+Boot installer, drop to shell with "s"
+
+
+# cd /dev && sh MAKEDEV sd0
+# dd if=/dev/urandom of=/dev/rsd0c bs=1m
+# fdisk -iy -g -b 960 sd0 # GPT / without -g and -b for MBR
+# disklabel -E sd0
+
+
+Note, switch to kbd en before setting the password as this is
+what you have on the boot prompt.
+
+
+# bioctl -c C -l sd0a softraid0
+# dd if=/dev/zero of=/dev/rsd1c bs=1m count=1
+
+
+Ctrl+D to restart the installer. Choose sd1 as install target.
+
+If sd1 is not present:
+
+
+# cd /dev && sh MAKEDEV sd1
+
+
+When the installer later asks about installing with MBR or GPT layout,
+choose MBR. Even if you boot via UEFI/GPT.
diff --git a/site/blog/2021-01-09-mutt-inline-patch-macro.md b/site/blog/2021-01-09-mutt-inline-patch-macro.md
new file mode 100644
index 0000000..363f1a0
--- /dev/null
+++ b/site/blog/2021-01-09-mutt-inline-patch-macro.md
@@ -0,0 +1,74 @@
+# Mutt inline patch handling
+
+Developers like to send diffs inline in emails. They do this, because it's fast
+and easy to read through them, comment on them and also to apply them. Some
+version control systems also take over the email text into the patch description
+as well.
+
+Up to now, my workflow was manual. I had to save the email somewhere, then open
+a terminal, cd to the direcory the patch shall be applied in and call the patch
+utility with the path to the saved email as argument.
+
+No more.
+
+This mutt macro takes the current visible email and copies it to a temporary
+file (/tmp/mutt-patch.diff). Then it executes the portpatch.sh shell script. All
+with one push on ctrl+s while looking at the email.
+
+The macro must be written in one line and ^S can be entered with the keyboard
+sequence ctrl+v ctrl+s:
+
+
+macro pager ^S "<shell-escape>rm -f /tmp/mutt-patch.diff<enter><copy-message>/tmp/mutt-patch.diff<enter><enter-command>echo 'Saved as /tmp/mutt-patch.diff'<enter><shell-escape> ~/.mutt/scripts/portpatch.sh /tmp/mutt-patch.diff<enter>"
+
+
+The portpatch.sh script:
+
+
+#!/bin/sh
+# needs converters/qprint
+clear
+
+echo '---------------------------------------------------------------------'
+grep -E 'Subject: |^Index|^RCS|^diff --git|^file +|^[-+]{3} ' "${1}"
+echo '---------------------------------------------------------------------'
+
+printf "Apply patch on path [defaults to /usr/ports]? "
+read -r _path
+
+printf "Fix quoted-printable mangeled patch? [y/N]: "
+read -r _qprint
+
+case ${_qprint} in
+ [y|Y]) _catcmd="qprint -d"; ;;
+ *) _catcmd="cat"; ;;
+esac
+
+printf "Strip? [0]: "
+read -r _strip
+
+${_catcmd} "${1}" | doas patch -Ep${_strip:=0} -d ${_path:=/usr/ports}
+cd ${_path} && ksh
+
+
+The script shows some relvant bits from the email patch that are handy
+to determine on which path the patch shall be applied.
+
+Next it allows the user to enter a different path. I mostly use /usr/ports, so
+this is the default. Then the patch is applied and a ksh shell is opened for
+further work.
+
+Quitting the shell brings me back to mutt to work on the next email.
+
+Sometimes someone sends a mangled patch encoded in quoted-printable. My script
+allows to fix this with qprint.
+
+Git diffs mostly need strip 1 to cut off the a/ b/ in front of the file path, so
+the script is asking for that too. For most patches on ports@, the defaults are
+fine and hitting enter 2 times works as intended.
+
+*...and if everyone would generate patches from the /usr/ports root, it wouldn't
+even be necessary to enter the path.*
+
+This is quite friggin handy.
+
diff --git a/site/blog/2021-05-19-gnupg-quickstart.md b/site/blog/2021-05-19-gnupg-quickstart.md
new file mode 100644
index 0000000..5d82ff3
--- /dev/null
+++ b/site/blog/2021-05-19-gnupg-quickstart.md
@@ -0,0 +1,213 @@
+# GnuPG Quickstart
+
+I love GPG and the way it works. I know there are many that complain
+about it because it has flaws. My stance on this is that I prefer
+battle-tested software with known flaws to something with unknown flaws.
+
+Anyway, this should get you started with GnuPG
+
+## Prerequisites
+
+Install gpg and pinentry.
+
+
+# pkg_add gnupg pinentry
+
+
+## You need a Key
+
+If you want to lock and unlock stuff, you need a key. This is how you
+get to one:
+
+
+$ gpg --generate-key
+
+
+Hop through the wizard until you see these lines:
+
+
+pub rsa3072 2021-05-19 [SC] [expires: 2023-05-19]
+ BA696588D9A04AD9F70DA33EC54733F6DBECC2C1
+uid John Doe <j.doe@example.com>
+sub rsa3072 2021-05-19 [E] [expires: 2023-05-19]
+
+
+If you see an error like:
+ gpg: agent_genkey failed: Permission denied
+
+Add the following entry and try again.
+
+
+$ echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
+
+
+Congratulations, you got yourself a GPG Key. This long gibberish is your
+full GPG Key ID. Most of the time, you can simply use the last 8
+characters. So the short version of this GPG Key is DBECC2C1.
+
+You can set it as default key, so it's used to encrypt stuff when no
+explicit key is given.
+
+
+$ echo "default-key DBECC2C1" >> ~/.gnupg/gpg.conf
+
+
+## Share the key with your people
+
+If you want someone to be able to encrypt something for you, send him or
+her the output of:
+
+
+$ gpg --export -a DBECC2C1
+
+
+You can also use your email address instead of the Key ID, if you have
+only one key with it. This key is public. So put it on some webspace and
+add a link to your email header or signature.
+
+## Upload the key so people can find it (optional)
+
+You can also upload your key to a key server. For this, configure a
+keyserver:
+
+
+$ echo "keyserver hkps://keys.openpgp.org" >> ~/.gnupg/gpg.conf
+
+
+Then send your key to it:
+
+
+$ gpg --send-keys DBECC2C1
+
+
+## You got a key from someone
+
+Add a key from someone else to gnupg, so you can use it to encrypt data
+for this person. If the key is on your harddrive, use:
+
+
+$ gpg --import <pubkeyfile.asc>
+
+
+The file ending here is kind of undefined. Some call it .asc, .gpg, .pub
+or .key. If the key is on a key server, you can import it like so:
+
+
+$ gpg --recv-key 52BE43BA
+
+
+This would import my key. You can look at it now with:
+
+
+$ gpg --list-keys 52BE43BA
+
+
+## Encrypt a file
+
+This encrypts the file plain.txt with the public key DBECC2C1.
+
+
+$ gpg --encrypt -r DBECC2C1 file.txt
+
+
+Now you have file.txt.gpg, which is the encrypted version
+
+## Decrypt a file
+
+GnuPG automaticall figures out what key it can use to decrypt a file. So
+this will output the content of file.txt on the terminal. If you want
+to save the output in a file, add -o file.txt.
+
+
+$ gpg -d file.txt.gpg
+$ gpg -d file.txt.gpg -o file.txt
+
+
+## Choose a better password prompt (optional)
+
+You can change the way gpg asks for the password:
+
+
+$ cat ~/.gnupg/gpg-agent.conf
+[...]
+pinentry-program /usr/local/bin/pinentry-curses
+[...]
+
+
+Options are:
+
+ - pinentry (sometimes also called pinentry-tty)
+ - pinentry-curses
+ - pinentry-gtk2: pkg_add pinentry-gtk2
+ - pinentry-gnome3: pkg_add pinentry-gnome3
+ - pinentry-dmenu: https://github.com/ritze/pinentry-dmenu
+
+*Note: If you use a console pinentry program and want to use gpg with a
+GUI tool (like thunderbird), the password prompt will be invisible and
+gpg/thunderbird will freeze.*
+
+Makes sense, doesn't it?
+
+## Start GPG Agent for password caching (optional)
+
+Put this in your .kshrc or .bashrc:
+
+
+export GPG_TTY=$(tty)
+gpg-connect-agent /bye
+
+
+## Make a Backup (not so optional)
+
+There is no handholding cloud or support team you can call when you
+messed up or deleted your key. So back it up safely.
+
+Either you backup your ~/.gnugp directory, or you export the secret
+keys and backup them safely.
+
+
+$ gpg --export-secret-keys -a DBECC2C1 > gpg_key_backup.sec
+
+
+Seriously, don't skip this step.
+
+## Configure Mutt (optional)
+
+Install mutt with the gpgme flavor. Gpgme is the "new way" of handling
+gpg in mutt.
+
+
+# pkg_add mutt--gpgme
+
+
+If you're not on OpenBSD, check with `mutt -v` if it was compiled with
+the `--enable-gpgme` option. Then enable it in mutt.
+
+
+$ cat ~/.muttrc
+[...]
+crypt_use_gpgme = yes
+[...]
+
+
+In the mutt compose view, you can now select Security Options.
+
+
+ From: c0dev0id <c0@example.com>
+ To: j.doe@example.com
+ Cc:
+ Bcc:
+ Subject: Hello my friend
+ Reply-To:
+ Fcc: =Sent
+ Security: Sign, Encrypt (PGP/MIME)
+ Sign as: <default>
+
+
+You can change the setting with the key "p", which should bring up a
+selection menu.
+
+ PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?
+
+*That's it! GPG is not difficult. You need to know a few bits, but these are not
+more difficult than many other things we do on a daily basis.*
diff --git a/site/blog/2021-09-26-memory-management.md b/site/blog/2021-09-26-memory-management.md
new file mode 100644
index 0000000..dc02446
--- /dev/null
+++ b/site/blog/2021-09-26-memory-management.md
@@ -0,0 +1,69 @@
+Disclaimer: I'm trying to learn this stuff. Now a year later, I think
+I got some terminology wrong. The process address space is not one, but
+many pages. How many depends on the page size.
+
+# Memory management, virtual and residential memory
+
+Memory management is a complex topic and most can be left for the kernel
+to handle. But having a fundamental idea about where memory is
+allocated greatly helps in understanding top(1) and the memory footprint
+of applications.
+
+## Process memory address space (page)
+
+When a process starts up, the kernel assigns it a so called memory page.
+The page size depends on the architecture. On amd64 it's 2^64 - 1 bytes.
+
+Every memory allocation this process performs, returns a pointer to some
+place within this page. Forcing a pointer outside this page, will cause
+a SEGFAULT.
+
+
+char *w = 1; // segfault
+char *w = malloc(12); // returns pointer within page
+
+
+# Memory allocation (virtual memory)
+
+Let's say we allocatate 2G of memory:
+
+
+char *m = malloc(2*1073741824); // 2*1G in bytes
+
+
+This will grab 2G of consecutive address space within the process memory.
+At this point, the memory is likely available but not guaranteed. The
+allocation shows up in top(1) as "SIZE" or on linux as "VIRT"ual memory.
+This memory is not actually used. So nothing has been written to the
+physical RAM chip in your computer.
+
+# Using memory (residential memory)
+
+Once memory gets used, it will actually use up space on your RAM chip.
+
+
+memset(m, 'u', 1073741824);
+
+
+Now we've written the character "u" to the first 1G of our allocated
+memory. If we look at top(), we'll see something like this:
+
+
+ PID TID PRI NICE SIZE RES STATE WAIT TIME CPU COMMAND
+96621 569318 3 0 2048M 1027M sleep/12 ttyin 0:01 1.66% ./a.out
+ ^ ^
+ allocated memory -' `- used (written) memory
+
+
+Note 1: When memory is swapped to disk, it leaves the residential bucket and
+can be seen as swap->used.
+
+Note 2: Stack memory will also show up as residential when used. Unused stack
+memory will *not* show up as virtual memory.
+
+Note 3: Residential memory includes shared memory as well. If you see 10
+chrome processes which are consuming 300MB of residential memory each, this
+does *not* mean that chrome as a whole is using 3000MB.
+
+TODO: Find out how the shared memory part of RES can be seen on OpenBSD.
+(Linux has SHR in top)
diff --git a/site/code.meta b/site/code.meta
new file mode 100644
index 0000000..afc4ec3
--- /dev/null
+++ b/site/code.meta
@@ -0,0 +1,2 @@
+title: Code
+section: code
diff --git a/site/code.sh b/site/code.sh
new file mode 100644
index 0000000..5a1d89a
--- /dev/null
+++ b/site/code.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+_distpath="$PWD/www/distfiles"
+mkdir -p "$_distpath"
+
+_repopath="/home/sdk/www/repo"
+
+out() { printf ' %s%s\n' "$1"; }
+
+out "Source Code Repositories "
+out " Stuff I wrote or regularly contribute to
"
+
+repo() {
+ NAME="$1"
+ LINK="$2"
+ DESC="$3"
+ out " "
+ out " $NAME "
+ out " $DESC "
+ out " "
+}
+
+out ""
+out " "
+out " Repository "
+out " Description "
+out " "
+
+
+repo "xpick" "https://github.com/c0dev0id/xpick" "Command line color picker with hex, xterm and rgb support"
+repo "mkpicindex" "https://github.com/c0dev0id/mkpicindex" "Image gallery generator with shell tools (static + js version)"
+repo "luakit" "https://github.com/luakit/luakit" "Fast, small, webkit based browser framework extensible by Lua"
+repo "mystuff" "https://github.com/c0dev0id/mystuff" "My OpenBSD ports"
+repo "dotfiles" "https://github.com/c0dev0id/dotfiles" "My Dotfiles"
+
+
+out "
"
diff --git a/site/code/favicon.png b/site/code/favicon.png
new file mode 100644
index 0000000..3212266
Binary files /dev/null and b/site/code/favicon.png differ
diff --git a/site/code/logo.png b/site/code/logo.png
new file mode 100644
index 0000000..6cbfa28
Binary files /dev/null and b/site/code/logo.png differ
diff --git a/site/code/style.css b/site/code/style.css
new file mode 100644
index 0000000..016bec8
--- /dev/null
+++ b/site/code/style.css
@@ -0,0 +1,153 @@
+:root {
+ --width : 36;
+ --rounding : 8px;
+ --accent : #1d3456;
+ --dark-grey : #ddd;
+ --grey : #eee;
+ --light-grey : #f8f8f8;
+ --code : #bdd5f6;
+ --content : min(calc(1rem * var(--width) - 2rem),calc(100vw - 2rem));
+}
+
+@font-face {
+ font-family : 'Proza';
+ font-weight : 400;
+ src : url('/proza-r.woff2') format('woff2');
+}
+
+@font-face {
+ font-family : 'Proza';
+ font-weight : 300;
+ src : url('/proza-l.woff2') format('woff2');
+}
+
+@font-face {
+ font-family : 'Proza';
+ font-weight : 300;
+ font-style : italic;
+ src : url('/proza-li.woff2') format('woff2');
+}
+
+html {
+ height : 100%;
+ font-family : Proza,sans-serif;
+ font-weight : 300;
+ font-size : clamp(16px, 100vw / var(--width), 20px);
+ font-feature-settings : 'onum','pnum';
+ line-height : 1.5;
+ -webkit-text-size-adjust : none;
+ text-size-adjust : none;
+}
+
+body {
+ height : 100%;
+ background : var(--accent);
+ color : #fff;
+}
+
+header,
+footer {
+ font-weight : 400;
+}
+
+body {
+ color: #000;
+ background-color: #fff;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-size: 1em;
+ margin: 0;
+}
+
+img, h1, h2 {
+ vertical-align: middle;
+}
+
+img {
+ border: 0;
+}
+
+a:target {
+ background-color: #ccc;
+}
+
+a.d,
+a.h,
+a.i,
+a.line {
+ text-decoration: none;
+}
+
+#blob a {
+ color: #555;
+}
+
+#blob a:hover {
+ color: blue;
+ text-decoration: none;
+}
+
+table thead td {
+ font-weight: bold;
+}
+
+table td {
+ padding: 0 0.4em;
+}
+
+#content table td {
+ vertical-align: top;
+ white-space: nowrap;
+}
+
+#branches tr:hover td,
+#tags tr:hover td,
+#index tr:hover td,
+#log tr:hover td,
+#files tr:hover td {
+ background-color: #eee;
+}
+
+#index tr td:nth-child(2),
+#tags tr td:nth-child(3),
+#branches tr td:nth-child(3),
+#log tr td:nth-child(2) {
+ white-space: normal;
+}
+
+.desc {
+ color: #555;
+}
+
+hr {
+ border: 0;
+ border-top: 1px solid #555;
+ height: 1px;
+}
+
+pre {
+ font: 0.8rem 'Consolas',Menlo,monospace
+}
+
+pre a.h {
+ color: #00a;
+}
+
+.A,
+span.i,
+pre a.i {
+ color: #070;
+}
+
+.D,
+span.d,
+pre a.d {
+ color: #e00;
+}
+
+pre a.h:hover,
+pre a.i:hover,
+pre a.d:hover {
+ text-decoration: none;
+}
diff --git a/site/favicon.ico b/site/favicon.ico
new file mode 100644
index 0000000..4af2804
Binary files /dev/null and b/site/favicon.ico differ
diff --git a/site/favicon.png b/site/favicon.png
new file mode 100644
index 0000000..3212266
Binary files /dev/null and b/site/favicon.png differ
diff --git a/site/global.meta b/site/global.meta
new file mode 100644
index 0000000..ee19823
--- /dev/null
+++ b/site/global.meta
@@ -0,0 +1 @@
+site_title: Stefan Hagen
diff --git a/site/gpg.txt b/site/gpg.txt
new file mode 100644
index 0000000..41e1f54
--- /dev/null
+++ b/site/gpg.txt
@@ -0,0 +1,122 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+=ZR0P
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/site/helpers.awk b/site/helpers.awk
new file mode 100644
index 0000000..5ba1cf9
--- /dev/null
+++ b/site/helpers.awk
@@ -0,0 +1,38 @@
+{ helpers = "yes" }
+
+function load_helpers() {
+ data["page_title"] = page_title()
+ data["section_blog"] = section_blog()
+ data["section_code"] = section_code()
+ data["section_photos"] = section_photos()
+ data["page_css"] = page_css()
+}
+
+function page_title( title) {
+ if (data["title"]) {
+ title = data["title"] " - " data["site_title"]
+ } else {
+ title = data["site_title"]
+ }
+ return title
+}
+function section_blog(section) {
+ if (data["section"] == "blog") {
+ return " class=\"section\""
+ }
+}
+function section_code(section) {
+ if (data["section"] == "code") {
+ return " class=\"section\""
+ }
+}
+function section_photos(section) {
+ if (data["section"] == "photos") {
+ return " class=\"section\""
+ }
+}
+function page_css(css) {
+ if (data["page_css"]) {
+ return " \n "
+ }
+}
diff --git a/site/images/404.png b/site/images/404.png
new file mode 100644
index 0000000..ae118be
Binary files /dev/null and b/site/images/404.png differ
diff --git a/site/images/bun.jpg b/site/images/bun.jpg
new file mode 100644
index 0000000..3fe0807
Binary files /dev/null and b/site/images/bun.jpg differ
diff --git a/site/images/icons/arrow-right.svg b/site/images/icons/arrow-right.svg
new file mode 100644
index 0000000..179b4be
--- /dev/null
+++ b/site/images/icons/arrow-right.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/site/images/icons/attachment.svg b/site/images/icons/attachment.svg
new file mode 100644
index 0000000..f114ce8
--- /dev/null
+++ b/site/images/icons/attachment.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/site/images/icons/cc0.svg b/site/images/icons/cc0.svg
new file mode 100644
index 0000000..195592b
--- /dev/null
+++ b/site/images/icons/cc0.svg
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/site/images/icons/github-square.svg b/site/images/icons/github-square.svg
new file mode 100644
index 0000000..8d2921e
--- /dev/null
+++ b/site/images/icons/github-square.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/site/images/icons/github.svg b/site/images/icons/github.svg
new file mode 100644
index 0000000..91803e3
--- /dev/null
+++ b/site/images/icons/github.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/site/images/irc.png b/site/images/irc.png
new file mode 100644
index 0000000..ae61623
Binary files /dev/null and b/site/images/irc.png differ
diff --git a/site/images/me.jpg b/site/images/me.jpg
new file mode 100644
index 0000000..989c246
Binary files /dev/null and b/site/images/me.jpg differ
diff --git a/site/index.adoc b/site/index.adoc
new file mode 100644
index 0000000..33197d8
--- /dev/null
+++ b/site/index.adoc
@@ -0,0 +1,20 @@
+== Welcome,
+
+++++
+
+++++
+As you may have guessed from the URL, my name is Stefan Hagen. I'm a software developer based in south-west Germany. I'm living in a small town called https://en.wikipedia.org/wiki/Hockenheim[Hockenheim,role=external,window=_blank] together with my wife Jessica and two cats named http://stefanhagen.de/photos/Chloe-%26-June/[Chloe and June].
+
+I'm the head of the https://www.uugrn.org[Unix User Group Rhein-Neckar,role=external,window=_blank] and you can meet me at our local events https://fixme.uugrn.org[FIXME,role=external,window=_blank] and https://stammtisch.uugrn.org[Stammtisch,role=external,window=_blank] (regular table).
+
+I'm also developing for my favorite https://www.openbsd.org[Operating System,role=external,window=_blank] by https://en.wikipedia.org/wiki/Porting[porting software,role=external,window=_blank] and occationally http://www.oxide.org/cvs/sdk.html[fixing a bug,role=external,window=_blank].
+
+For compatibility reasons, this website is available via http://stefanhagen.de[plaintext (http)] and https://stefanhagen.de[encrypted (https)]. Set your bookmark accordingly.
+
+=== You can find me here:
+[%hardbreaks]
+icon:arrow-right[fw] on https://irc.uugrn.org[irc.uugrn.org,role=external,window=_blank] ( #uugrn, sdk )
+icon:arrow-right[fw] on https://github.com/c0dev0id[github.com/c0dev0id,role=external,window=_blank]
+icon:arrow-right[fw] on https://bsd.network/@sh[bsd.network,role=external,window=_blank] (Mastodon)
+
+You can optain my email addresses from link:/gpg.txt[my gpg key] or by using the https://linux.die.net/man/1/finger[finger(1)] command on `finger@codevoid.de` <- this is _not_ an email address.
diff --git a/site/main.layout b/site/main.layout
new file mode 100644
index 0000000..1646236
--- /dev/null
+++ b/site/main.layout
@@ -0,0 +1,38 @@
+
+
+
+
+ {{page_title}}
+
+
+
+
+
+ {{page_css}}
+
+
+
+
+ {{{yield}}}
+
+
+
+
diff --git a/site/netcitizen/index.adoc b/site/netcitizen/index.adoc
new file mode 100644
index 0000000..f69bab3
--- /dev/null
+++ b/site/netcitizen/index.adoc
@@ -0,0 +1,94 @@
+= Net Citizen
+
+The web was still young when I first went online in 1996. It felt like a
+utopian dream of free culture and free knowledge. Anyone could contribute and
+communicate. I spent countless hours on IRC, learnt html, php and mysql and
+created my first site on a shared shell server with some webspace.
+
+I’ve watched as the dream has become a nightmare of
+https://en.wikipedia.org/wiki/Online_advertising#Privacy_concerns[surveillance]
+and monetisation
+(https://en.wikipedia.org/wiki/Website_monetization[1],
+https://en.wikipedia.org/wiki/Data_monetization[2],
+https://en.wikipedia.org/wiki/Software_monetization[3]). Companies such as
+https://en.wikipedia.org/wiki/Google#Racially-targeted_surveillance[Google]
+and https://en.wikipedia.org/wiki/Privacy_concerns_with_Facebook[Facebook]
+offer their
+https://en.wikipedia.org/wiki/Privacy_concerns_with_social_networking_services[services]
+for free to the public because their real products are their advertising
+networks powered by the personal data of their visitors.
+
+I've watched hundreds of carefully handcrafted, personal websites become slow
+and boring wordpress, medium and bootstrap blogs that all look the same. Many
+of them just disappeared and people moved to big social media plattforms.
+
+I've watched networks becoming regulated, favoring services for money and
+slowing down or blocking services that were not liked by the network provider,
+endagering https://en.wikipedia.org/wiki/Net_neutrality[Net neutrality].
+
+I watched a network that was made for everyone become a marketing instrument
+to influence politics and make everyone pay with their personal data. Mostly
+involuntarily and by offering a useful service people want. This service is
+mostly not the business the company is in, but rather a side product needed
+so people join in.
+
+The same scheme can be seen in games, which use psychological techniques to get
+people addicted, so they buy in app goods, which have absolutely zero value in
+real life.
+
+And here I am, ranting about the past like one of the old people.
+
+I have little influence over the wider web, but I can control my small part of
+it, and hold it to the ideal I learned to love. This page is simple, doesn't use
+javascript, tracking or cookies. It's just there, like a good old homepage.
+
+== Copyright
+
+Copyright limits creativity and holds back progress by restricting our rights to
+build upon the works of others. Therefore I'm releasing this website, it's code
+and content under the terms of the Creative Commons CC0 1.0 Universal Legal Code.
+You can use and adapt it without attribution.
+
+Exempt from this release are all pictures that show people or are in the Photos
+section of this website.
+
+== Privacy
+
+My site is hosted on a server provided by Hetzner Online GmbH in Germany. I'm
+operating the server myself and Hetzner only provides the hardware and remote
+access to it. There is no content delivery network involved when accessing this
+site. This means it might be slow in far away regions, but it also means that no
+data is shared with a CDN provider. The server is fully encrypted and webserver
+logs are deleted after two weeks.
+
+Almost every site today includes code that tracks visitors for statistical and
+advertising purposes. Often the site owner includes code with the deliberate aim
+of tracking their visitors, but sometimes they just want to include a feature
+provided by a third party, and that provider includes their own tracking code.
+
+My site doesn’t include any tracking code, and doesn’t load any code from third
+parties. It doesn’t have a cookie banner because it doesn’t use cookies.
+
+== Transparency
+
+You probably don’t know me, and shouldn’t have to trust me. Instead, you should
+be able to check security and privacy claims for yourself. Unfortunately most
+sites today use a process called code minification, which makes them faster but
+also makes it harder for other people to understand their code.
+
+My site doesn’t need to use code minification in order to load quickly due to
+its simple design, efficient implementation, and absence of resources loaded
+from third parties. As a result, other software developers can easily understand
+how the layout, styling, and interactive features are created.
+
+== Attribution
+
+I'm not every good with design and therefore many design related elements
+of this page are taken from https://iamkate.com[Kate Rose Morley] who thankfully
+released her work under a permissive license.
+However, the way how the page and content is generated is different and
+based on a modified version of https://github.com/nuex/zodiac[zodiac],
+which is a static website generator written in the programming language
+https://en.wikipedia.org/wiki/AWK[AWK]. Some content pages are generated by
+https://asciidoctor.org[asciidoctor] and others by shell scripts or a
+markdown parser. Here is the https://github.com/c0dev0id/website[Source Code].
diff --git a/site/netcitizen/index.meta b/site/netcitizen/index.meta
new file mode 100644
index 0000000..eb1559f
--- /dev/null
+++ b/site/netcitizen/index.meta
@@ -0,0 +1 @@
+title: Net Citizen
diff --git a/site/proza-l.woff2 b/site/proza-l.woff2
new file mode 100644
index 0000000..15dda40
Binary files /dev/null and b/site/proza-l.woff2 differ
diff --git a/site/proza-li.woff2 b/site/proza-li.woff2
new file mode 100644
index 0000000..6f33969
Binary files /dev/null and b/site/proza-li.woff2 differ
diff --git a/site/proza-r.woff2 b/site/proza-r.woff2
new file mode 100644
index 0000000..68369f7
Binary files /dev/null and b/site/proza-r.woff2 differ
diff --git a/site/site.css b/site/site.css
new file mode 100644
index 0000000..4693fe1
--- /dev/null
+++ b/site/site.css
@@ -0,0 +1,481 @@
+:root {
+ --width : 36;
+ --rounding : 8px;
+ --accent : #1d3456;
+ --dark-grey : #ddd;
+ --grey : #eee;
+ --light-grey : #f8f8f8;
+ --code : #bdd5f6;
+ --content : min(calc(1rem * var(--width) - 2rem),calc(100vw - 2rem));
+}
+
+@font-face {
+ font-family : 'Proza';
+ font-weight : 400;
+ src : url('/proza-r.woff2') format('woff2');
+}
+
+@font-face {
+ font-family : 'Proza';
+ font-weight : 300;
+ src : url('/proza-l.woff2') format('woff2');
+}
+
+@font-face {
+ font-family : 'Proza';
+ font-weight : 300;
+ font-style : italic;
+ src : url('/proza-li.woff2') format('woff2');
+}
+
+*,
+::before,
+::after {
+ box-sizing : border-box;
+ margin : 0;
+}
+
+html {
+ height : 100%;
+ font-family : Proza,sans-serif;
+ font-weight : 300;
+ font-size : clamp(16px, 100vw / var(--width), 20px);
+ font-feature-settings : 'onum','pnum';
+ line-height : 1.5;
+ -webkit-text-size-adjust : none;
+ text-size-adjust : none;
+}
+
+body {
+ display : grid;
+ grid-template-rows : max-content 1fr max-content;
+ height : 100%;
+ background : var(--accent);
+ color : #fff;
+}
+
+header,
+footer {
+ font-weight : 400;
+}
+
+header {
+ display : grid;
+ grid-template-columns : 30px calc(min(100vw, 1rem * var(--width)) - 60px - 2rem) 30px;
+ justify-content : center;
+ align-items : center;
+ padding : 0 1rem;
+}
+
+header svg {
+ fill : #fff;
+}
+
+nav ul {
+ display : grid;
+ grid-auto-flow : column;
+ grid-auto-columns : min-content;
+ justify-content : center;
+ padding : 1rem;
+}
+
+nav li {
+ display : block;
+}
+
+nav a {
+ display : block;
+ padding : 0 0.5rem;
+ border-radius : 0.75rem;
+ color : inherit;
+ text-decoration : none;
+}
+
+nav a.section {
+ background : #fff;
+ color : var(--accent);
+}
+
+main {
+ padding-bottom : 1rem;
+ background : #fff;
+ color : #000;
+}
+
+footer {
+ padding : 1rem;
+ text-align : center;
+}
+
+footer > a{
+ color : #fff;
+ text-decoration-color : #fff;
+}
+
+h1,
+h2,
+h3,
+p,
+dl,
+ol,
+ul,
+pre,
+code,
+table,
+figure,
+form,
+main > div {
+ max-width : calc(1rem * var(--width));
+ margin : 0 auto;
+ padding : 1rem 1rem 0;
+}
+
+h1,
+h2,
+h3 {
+ font-weight : 400;
+ line-height : 1.1;
+}
+
+h1 {
+ font-size : 2rem;
+}
+
+h2 {
+ padding-top : 2rem;
+ font-size : 1.5rem;
+}
+
+h3 {
+ padding-top : 2rem;
+ font-size : 1.1rem;
+}
+
+dl {
+ padding : 0 2rem;
+}
+
+dt {
+ padding-top : 1rem;
+}
+
+dd {
+ padding-left : 1rem;
+}
+
+ol,
+ul {
+ padding : 1rem 2rem 0 3rem;
+}
+
+ul ul {
+ padding : 0 0 0 1rem;
+}
+
+table {
+ margin-top : 1rem;
+ border-collapse : collapse;
+ font-feature-settings : 'lnum','tnum';
+}
+
+thead {
+ position : sticky;
+ top : 0;
+}
+
+th,
+td {
+ padding : 0.25rem 0.5rem;
+}
+
+th {
+ background : var(--accent);
+ color : #fff;
+ font-weight : 400;
+ text-align : left;
+}
+
+.repotable tr:nth-child(even) td {
+ background : var(--grey);
+}
+
+.numeric {
+ text-align : right;
+}
+
+.negative {
+ color : #f00;
+}
+
+figure,
+form {
+ width : max-content;
+}
+
+figure > img,
+figure > svg {
+ max-width : calc(100vw - 2rem);
+}
+
+form > div {
+ padding : 1rem;
+ border-radius : var(--rounding);
+ background : var(--grey);
+}
+
+pre,
+code {
+ font : 0.7rem/1.1rem 'Consolas',Menlo,monospace;
+ font-feature-settings : 'lnum','tnum';
+}
+
+pre {
+ margin-top : 1em;
+ border-left : 4px solid var(--accent);
+ border-radius : var(--rounding);
+ padding : 4px 4px 4px 8px;
+ background : var(--code);
+ overflow-x : auto;
+ width : min(calc(1rem * var(--width) - 2rem),calc(100vw - 2rem))
+}
+
+code {
+ padding : 2px 6px 2px;
+ border-radius : var(--rounding);
+ background : var(--code);
+}
+
+a {
+ color : var(--accent);
+ text-decoration-color : var(--accent);
+ text-decoration-thickness : 1px;
+ text-underline-offset : 2px;
+}
+
+a:visited {
+ color : inherit;
+}
+
+abbr {
+ font-variant : small-caps;
+ text-transform : lowercase;
+}
+
+img,
+svg {
+ vertical-align : bottom;
+}
+
+input,
+textarea,
+select {
+ border : 2px solid var(--dark-grey);
+ border-radius : var(--rounding);
+ background : #fff no-repeat center center;
+ color : #000;
+}
+
+:is(input, textarea, select):where(:active:not(:disabled), :focus) {
+ border-color : var(--accent);
+ outline : none;
+}
+
+:is(input, textarea, select):disabled {
+ background : var(--grey);
+ color : #000;
+}
+
+input:where([type="password"], [type="text"]),
+textarea,
+select {
+ padding : calc(0.25rem - 2px) calc(0.5rem - 2px);
+ font-family : Proza,sans-serif;
+ font-weight : 300;
+ font-size : 1rem;
+ font-feature-settings : 'lnum','tnum';
+ line-height : 1.5;
+}
+
+input:where([inputmode="numeric"], [inputmode="decimal"]) {
+ text-align : right;
+}
+
+select {
+ -webkit-appearance : none;
+ appearance : none;
+ height : 2rem;
+ padding-right : 30px;
+ background-image : url('/select.svg');
+ background-position : right;
+}
+
+input:where([type="checkbox"], [type="radio"]) {
+ -webkit-appearance : none;
+ appearance : none;
+ width : 22px;
+ height : 22px;
+ margin : calc(0.75rem - 11px) 0.25rem 0 0;
+ vertical-align : top;
+}
+
+input[type="checkbox"]:checked {
+ background-image : url('/checkbox.svg');
+}
+
+input[type="radio"] {
+ border-radius : 50%;
+}
+
+input[type="radio"]:checked {
+ background-image : url('/radio.svg');
+}
+
+input[type="file"] {
+ position : absolute;
+ left : -100vw;
+}
+
+button{
+ margin : 0;
+ padding : 0;
+ border : 0;
+ background : transparent;
+ font-family : inherit;
+ font-size : inherit;
+ line-height : inherit;
+}
+
+button:-moz-focus-inner {
+ padding : 0;
+ border : 0;
+}
+
+button:where(:active, :focus) {
+ outline : none;
+}
+
+button > span,
+.button {
+ display : inline-block;
+ padding : 0 0.5rem;
+ border : 2px solid var(--accent);
+ border-radius : calc(0.75rem + 2px);
+ background : var(--accent);
+ color : #fff;
+ font-weight : 400;
+ -webkit-user-select : none;
+ user-select : none;
+ cursor : pointer;
+}
+
+button:where(:active, :focus) > span,
+.button:where(:active, :focus),
+input[type="file"]:where(:active, :focus) + .button {
+ background : #fff;
+ color : var(--accent);
+}
+
+.repotable {
+ width : 100%;
+ border-radius: calc(0.75rem + 2px);
+ overflow : hidden;
+ text-align : left;
+ vertical-align: top;
+ width : min(calc(1rem * var(--width) - 2rem),calc(100vw - 2rem));
+}
+
+.highlight > div {
+ background : var(--light-grey);
+ overflow : hidden;
+ padding-right : 0.8rem;
+ border-radius : var(--rounding * 2);
+}
+
+.highlight table {
+ --horizontal : 0.8rem;
+ --vertical : 0.6rem;
+ width : 100%;
+ margin : 0;
+ padding : 0;
+}
+
+.highlight tr {
+ display : grid;
+ grid-template-columns : max-content 1fr;
+ gap : var(--horizontal);
+ background : green;
+}
+
+.highlight td:first-child {
+ padding : var(--vertical) var(--horizontal);
+ background : var(--grey);
+ color : #aaa;
+}
+
+.highlight td:last-child {
+ overflow : auto;
+ padding : var(--vertical) 0;
+ background : transparent;
+}
+
+.highlight code {
+ display : block;
+ padding : 0;
+ background : transparent;
+}
+
+.highlight :where(.c, .c1, .cm){
+ color : #aaa;
+ font-style : italic;
+}
+
+.highlight :where(.o, .p){
+ color : #aaa;
+}
+
+.highlight :where(.fm, .k, .kc, .kd, .nt),
+.highlight .language-css :where(.nc, .nd, .nn, .s2){
+ color : #c66;
+}
+
+.highlight :where(.na, .nb, .nf, .nv),
+.highlight .language-css :where(.k, .kc, .kp, .kt),
+.highlight .language-javascript .nx{
+ color : #5b5;
+}
+
+.highlight :where(.cp, .nc, .ni, .nx),
+.highlight .language-css :where(.n, .nv){
+ color : #e94;
+}
+
+.highlight :where(.m, .mf, .mh, .mi, .s, .s1, .s2, .sr){
+ color : #36b;
+}
+
+.photo-img {
+ width: 100%;
+}
+.photo-mid {
+ width: var(--content);
+}
+.photo-td {
+ width: calc((var(--content) / 3) - (4 * 4px));
+ padding: 4px;
+}
+.photo-table {
+ width: var(--content);
+ margin: auto;
+ border: 0;
+ padding: 0;
+}
+
+/* ASCIIDOCTOR FIXES */
+
+.sect1, .sect0 {
+ padding: 0;
+}
+
+div#preamble {
+ padding: 0;
+}