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 "" + +echo "

    Collections:

    " + +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 " " +out " " +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 "
    RepositoryDescription
    " 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----- + +mQINBFr51VIBEACZLzWpx/JMZsm0Nl+hIWLEbvf04UGlDA8njr5lF+n3SY1YoKxs +HsuHI60PvStKEh7hfXu+EyZfvk/7NBXnqi+nJzRNHN8b/KXVXugV7Ix5sP4QYfPt +Cpi9mXQNXNHHQyQFt5GN02eyeqdu7nIaIMkI7HP9421S55i/H3UNajTNJpd7AWZ+ +B5U76M6ydjI1cPrLVzfRkWk2se41tUVSas6t7nzAtlkiWEzfV7ee1Ob1YciXaDxS +H0ROlbhmHBH6ySjea5iDlKYR7VILN262DNxaXLCQv4ZnCsUMlNyupl/qsqQkKZS3 +BHJ2Jrfx6t1qV1+jmgb2ARjWef8VeDLm138yZaFDyCvpWhBSNZCyjGJppUGpvOAW +TYAyOVKjDOErh6sqqwMX2scuwiKmfncq1Ayy3d3VzC41SEhJGj/bllR3kMSD5PQa +MsKFJu3GnLEw81GifMzrNsn7wlxz3k/Zj12PaLVc3+ixjpau5WUzMUTKiz3l0Avh +LOVJIVYL2RctFsOGSZWEF3X5IgB7g3ry4qGz8OO3xaFSpLjeWjvwtdaiBPH76hG0 +s1GkJu9o/Kk6N98U9uFESsH+I7hZxwpLF5cOh3qrQ7yjx6hPMYL3GnCNyzdjY7Ht +V6YF7bFwGzWn2lF9raefRvriRbqkjl478fy5SnjtQAbgRsFq5D05FJXEcQARAQAB +tCBTdGVmYW4gSGFnZW4gPHNoQHN0ZWZhbmhhZ2VuLmRlPokCTgQTAQoAOBYhBMvT +xGhktGUX6Pu5D7a8LsVSvkO6BQJjnhbgAhsBBQsJCAcDBRUKCQgLBRYCAwEAAh4B +AheAAAoJELa8LsVSvkO6d0cP/14Zy7X843nHo9Vi0B0ju8RqdNV+z1Ev5kc8Q8sv +gKGW2vZHDe8pL8M3siFAHkYxptTy/4L5CDoAZXwXd0XeMiLO2H4su8XJinEOAVwX +9DXHO9QKYKjCCG5lAPPz7su2Qop+Br5QtkBXq1wcRYH1HtokxAaBTLM7TZzGsF9/ +6XI6NX+yKHdrs/84+06kJEZTmkQbrwBQbCTB9h2QxeE/V0Ae7Rje6H0ptLOdTN6K +eGiEsW+m56KptDJGoUWx0pZjE1qJ6mKkJqF/ixb4pPjNeRC2YjJ2a0H6bJxB6yjh +pn2rnI2prD54tANGHW3pQEo4/AmQiEo95zlmrSQ9s+z1Ej5VcM+HDmCL3meT0ooU +S6aQChljyxiWZeFRqXTUE9UO+S1jeGwc3FHmFk5Wt7c1CS5ADgfCyXsabUJHue4g +bh43nJjNUTqjwd59HpOv8XC4gYOFhGXK+hM67n3F+NW1XwiRgmF6DZ/3GnyWTdVg +1p78f/viP6LNFNn4xvXHKn3NzWwQi7arZBewCfFgb8Z26h3m+o+XZrzlJMQlji+4 +AQSP7OOtwc7Ow27A09bE5b+75LfTXtLGHyHHlfKfOSERNJsgLFTKZdEtQXYQsubv +uatcu5dJq92LnnvQ5RQezVCC42L8q+jCW+RiIxngvrWiOdNod6iKQQY+3MRXJw11 +2tCWtB1TdGVmYW4gSGFnZW4gPHNoQGNvZGV2b2lkLmRlPokCTgQTAQoAOAULCQgH +AwUVCgkICwUWAgMBAAIeAQIXgAIbARYhBMvTxGhktGUX6Pu5D7a8LsVSvkO6BQJf +GxW+AAoJELa8LsVSvkO6LcQP/jJMwZlcTWFaqRXJq48aCbd4E4uPIh8AMfW9ZZtC +xwn+U4IWDTioB0yvJ/q9Kjg1aJY2ym9gkMLmqyEj/SsiavQ2C7WQYJH1S+O/Ivqx +If/HcW3deW2IE//doa2fp9hnlJV62mqyN5Qugk0HdpMxFTT1ohR2zTrBWO2QhC8G +rzAc6CRD4VW8borYL+lFgzDG1ILPcqpb3QtRmlfXkmmBHDEGudLXVIAimO/JmnVI +UcfiE6hoP+mNVGvFEh7jPcOImEJWsn+XAaevipKkDJqie1HxgUMt8NfecBY9SuHV +VtFsRpwL4lvM+6qC1zOLVKUY6/OSRd+DY5EThtE2jG4ojR1b9SlSNuhROIWnIswG +sozyNPtyjD5zX3Fne3FmvD+P/s12AJWJLU+hPq4jNaW1rjVjC0NTWF8FOiGjh4oo +vESeeP/Kz3BgXMce/lyFH7n3lcZJ1y0e/EGWFYG5ut32Fe/t+kAcJQfLsaR5uHcC +SvhOtniAvwRa6EswpRLehm8+p8wUtw4T+r8FOMCSQhIomHKElVCjyyNYt3mNzgWB +IRIvw9wBLkAU88j2kKSeXXIxdaPIocSwOwWCPvSY/R5OjB9OhJULQZ8mBFvYrLZO +v7QlCLrdwfUM1JTi29wqdger++g60KdacOyJoWUYmoZl/GTIIx23cXUcKk2EBnu7 +GetVuQINBFr51VIBEAC3QhpZOfzkpbSQvgnfQeaRdo2ajF+VuOmHHl8oBX3H5+G7 +bnPq3ms2S54R91vJlAnRpjo/2bj/W0aQvAv0uYroq9oLXra0aCmnuoDRrMs2R1Qv +W/U8pSVXFaLQOu0SWIM9bsnrA1/y4nthtuB/kSAUM775lF2OoX5QqHKGasqD9Stl +AkcSYgF0dQsX8z2g8eWTl5DOdCpKbx4O2CJncrq5T49rqLaberK9m/Y3u/kZGCFD +o9XlpHRFvj74PiiTng6Ckcu86U/4qs1zfw4IY0nEMlV4qftkRm53l8q8RFi4DLYf +SpCrihZ1PxdmHrL9C+xDfBha4UWe9smCD35/Y7bTFwwRQfei9PDoxCjOtMBhCZvX +5P1nLWtsREd0khO+mVatukTTBruFa3GGY1sX9IjQClfSpuBJAR9DoOWQGKKtq8vn +rkBZMF2z+Rw+n+fBPUn26V8XmK6vPiPWNCGjgQDVNBg/uI+ATnE7lfp/MzmgIO7p +rdK3Y1ZUrePXuu9hYRN8Kkgd7AU0zjayTUsJYOy75TFqBJYH/HVYq7cMbv+Gp6NG +soTUhjVO1H7HebIOzEI4YtrXEDRpzTm9cgMaLJJPhQelWqyNNsq5ygorC7aawrNe +m9uMSxNcBWDPWrQqGYisXmEm61HJBCN0VzQv7S2G68aJDRhvhZ07jCayq1Gj9QAR +AQABiQI8BBgBCgAmAhsMFiEEy9PEaGS0ZRfo+7kPtrwuxVK+Q7oFAl8bFiYFCQqe +YtQACgkQtrwuxVK+Q7pKyQ/+Oizhk9IiJ7t2TIKFjfIKYa1IxBA0njf1tVNU07L8 +Jvdr0nn37iP0xRgbDeNEnpUIxRCq5PVbTM5ua5K0X+WpzySjjBvsT4KGQ+Xr+ldW +jsQR3GV2uFqSs50/25WE/uAo1M9gNeG6twzISI5wsYpKMyVOEWIlx9nl0k/OxkzH +7odX3ttl2lRzKuvXDjC6X66yuGZBRlyG/7wQVCftvcB5LySGRDKNXdN18sjiF3GZ +RtT8QkbmxTDTjO4H/OX8S7lC7xJm6BBJbsseEgrJWzHhW33x+LlXYHK4BsEPXA9h +nIajYzvjvcbpk9lhL3CXXJglRLZzKzrDuMTV6z3p1hp0ORKV+pYmdf2yUOd93qqf +cuQ85qRgdByR8ShKbHEcwR3OEH9B8dUKDy4lKHhg7OzDs/50CnJSgyEOKCVxn5Ng +Bm4l3pXzQh/kqk3ybYieyDCFG/H9Ltk74V+hH6vKn68PNKE70PnZ8iZ1psGoxHun +qN6uKppINaJTM9JJA+A03PL6waLsGHPz5TaKxVdvoXSOW+qNEYHFpCgpO8tFcAGv +TLfVDpQFWFjVCY/VSYfcZ76FTJN8f56EtPY2R2G7kD3YW5MwIFbyg3tfEuoGm++z +JpOJSXytQxYoQxHCp/cRJLrGZcZGtZNW1rssDzkUabhzhExpv5uSwek1wYoz7fTm +4Qm5Ag0EXxsWLgEQALN2AxWXioOWNxOtunLMmaxeD+FsJgXRi0MIwPewD3EroKM+ +RW1MEqcHD/5eeoYrk2XG/H12TEGs31f82EAJ2ZpxhDzZmPfFH3wiwZ2yQQmt2YLA +qL29Nsj6QbRLuZxxSlkBH0Racs+bnDActbPrnhpf/kQPG8ge0F59tSE1NzIurEVV +47OYVfytfMzPQc4/hBvVL9yTyl4wXSPwVQOVGzLDKSuI/ta2jFKU1yd6Sub9gTZE +7BL9L8u/XqXb5BxJZ7tNykGaeWsdSuAlgCNPI2cMUQ5n32lxpqhcEKEAtJwetomi +e5bvDVt4LcYgufXStUKabugYhlc3XW3wGcbkDPOExwxmnrHKjf3MARORwzwDbZtb +bF6Ke6M708uQr4jImqMFk5Ew5cwYyzkfmxgTbKfSfq6x/MJbW6Q99mzH/tT8lcms +QRvGFbNGXxfMXr+KhftNywzXrB59mjdfop8V4MkYiC8mPlCf4Fyvf7NA4ZyI8dC6 +xP5TP7EfdoRFU3oCnKFgikYvRvastXAqGA4xGD8fWM+WYYmiBxWD3kLBC9b1xa2W +X5P5ttyDtUV+PMNZT5QjNWro6wBtrD16ZpYplo21qeUNt8RHLD0dAm6EppFi+iq+ +gxXNjEVX8d1fv+kLkITHnSN2ptV756jRHc5+VUDr2ErqpHw4vbmvghRcDl5XABEB +AAGJBHIEGAEKACYWIQTL08RoZLRlF+j7uQ+2vC7FUr5DugUCXxsWLgIbAgUJBn0i +AAJACRC2vC7FUr5DusF0IAQZAQoAHRYhBMMN6skyKeVSlzr5yJ8g2ONALR4OBQJf +GxYuAAoJEJ8g2ONALR4OeSkP/2CwSjhNF1xT7lfQ3Gm94/UlHkSF4efeWEJAIl/G +fGA02CKjL+P7t7Qn3Fx28e/O2fOCvaz+Uhp/1NFDnLF95YlvmAOvC2em5F7jiy0C +YQ9FM7FMgoAIaXQR5Lss3PAqsyKrpu8RD+CQ0gpXjZzJertSLOYYz/Xj6F4eNskV +fdFLnwV/aw5XPnUH1JDs5u+QkwbahFLQd0I53pplS3c9vwWzLbZt3Vxz1PS4SeEO +Po7W3iYB7ahd/zJGpjk4pOo5gEbaiHl+hzpe0YLUO+ze7BfLy4LcYGStshMzzXl1 +aqk/8fADudDb/8BFbKfbg/HOrv7bgI+6FWePP1vjsmUN7uJfXtx7Pz6X2m6P7IZm +IRUiBwJBbfHOAuIhkDh9JjW1HLMfUWAbYRy0W6mshCtNqVGt2EMrI/SUWcuh9Z7B +eNDTN0aMWr1tEFlRJmEqUoUloOiw81uPwQzZhOac/Bn4Sfimyzj9LcwoltO+X92Y +ty7hSDmgS/i5avCtcoyWGSFY43iArtu0FxriYJM9MiUZhyUnHUGm68k8OJuKIoVg +ApSJNJAAew8kpqbLC2vOxRMHf27S0aCam3M2tIq3hFt9w5QuVvJXBhvZryJcSCaG +gUnB/mUFcqjBHEd7oD2WcL0+TLRJA2nfammnlru2+sdCZpysqeepMz5WmHJIm5MB +bzJIWlQQAJCPOE/ja94X2Of95MTXN+Z89f4Ik6T65xUzG+Wzc4K6SHsMHW3o/0BY +fwZ3sfjzMXghiL5Zr4Go3GkfTk5a2RpX3sVN0NptoOOCvVNRMFa7/4pwMEyjbPeG +GWc4fFpzucNd2xtKeA9l9kDVeILjhbKJIZpiL6L/q4JJ/AfA8VlrVEYzj+ITwpnN +PLTkCCnfjxZoWYpTVKAqrKLL/yI8W/GGg4OCIeGmtZvlQaoVyMafR9fnzNdAY8gl +0RsFd9XvWcs4P1enY8stXi1ZVN9ri/tMcXx/mlvEhyJW3pbxag5lPagK2jlXHKjW +pT1rHvgh2j5kZc9weWknYUQhxy1/8dMfqjEURCred9vCVmBhWpVuPjmgshtNgSbv +yO1AseHyQVntdT680m1twT8z2qlNc0fKgEEGO14vvGo/gwYH1KW0N898om+Bggcd +PnQSYovVEC0OU7hbTewRM35yCRUdgDWSBpmr4bg/KfAnt2iMWX7QIx3Z01oi/1Hz +aU/HBSmqVW1azYd55ZRTUCZgpQSNNbAYxRfT2Nbaap1dtT1+B/SzPof3y4Z+dWqL +xO1EqIt3B1SvUwGlzAsTO9fvqPZ7GchwRyPpfjgGAR6JYVgnvWe6UZhjp3LOME16 +2x6CB4INYXWwytIn8jnBi0Hzwnw5C1zjbPfE2H6hsSz2tcrlcOdXuQINBF8bFlQB +EADZWd3KzsSnHLTAKS6own8YoAVfyJ9Gryaz7Xs3OqF03tNLpSb+MH8OA6KU81Nv +E2+3/ZNJ0g+HTESg/3jYhcOGSA4gv95oe8wZxJyhXxdhaJThu15i1tmXTU3D57Xb +iaIg2Nx4pNT7j65/kqW6CDd8tZ2y4Fo6F4nNznad0DkaGVtuDCFm/tjdozmb8DcV +NYxjVEoxe8h6oha2NEu2hFH19e7oAyIsQZHKCZ3MxNhQT0zjsFnXKixHVkLSvaVR +/o28NCcg3bi4mMLZBjZ4ZFKFlEz7HIDj+RBIjeKb2vJUyXQU+v6EeRrLehwmVKO6 +6tC01aLebIGuHJ/V+P/CtM2JuZp12EpHMryaPAr2nBJXyO6dFhpIlev2oCGf2M1U +B82rhqq3C1uaFGvqWotFEUzym7dFK+imiUR9kgr96dbw4hkSRKFbxb/e6B+KFxOZ +a9HaRExH9z30KAfc7lDscaHKqQn2jjuVCne7aAC66081r043SlxWAxeQny/HHzQM +HI4NLpaAqo/n9Uw1agsNJgf5GHfVPQo/raG2HXp1TF49qE732P8+e4NhBZiT6ozM +ir2VFrwMjnhhxSs9vDXuOeyDqn83PspBhjKOlFAOvZqS7fQj//tc5tQe6r+ams07 +Y7s5osI+teKtFuptcm12YGXXcKSo9hoPBOeaDQb7iwfe6QARAQABiQI8BBgBCgAm +FiEEy9PEaGS0ZRfo+7kPtrwuxVK+Q7oFAl8bFlQCGyAFCQZ9IgAACgkQtrwuxVK+ +Q7pqnw/7BSZN+/fJSvsqHPjOa4mm0+5Uog+slSS7HZFyX6iS3cMzGPNyYwGheZ6G +1dDEVcTJkNPCgW+81XqeqCtXXMtLd6jyyMQLOomY1wTuWeGTpuDGsMgoF5AohL3X +kebeQ6EGWRuP9VOcbXY/gmPm25EtHspJq6lMEY7YJJhcjB/v88bMcHlrMqejS4ty +6WRMKSnOZw5dEKk/kkaTthACaAOC/7cJVyLKwnFXlaG0Wo2waQ87Ij0z+lgBPNO6 +sAe8i+OKIrokmP7YnIAUtBfA0pMZTqZthTEIJFpHfcJGY7OaCM0kr1T/s10Lprj6 +1oyd4zH3ca1Ljwhgcuo+P4oD6+mptEWPhouuveZgH/4Rsz5P1MFzzwSIzQkqrCKw +1vmcg0toWe/v5UdClc7aGt0fKwWyHc87ZsV2jX8UrbEAElP0kqYcg+rspNSA+y7T +L54YN5LIH5QLfe8zoXxRPa91hQ5PP0X17hfl1ZwXDZqfPSv12Qj0W9tveCVA0SBo +SZdp6F7IN1NwHEUPmelseu82+sSooiNIOwNZSJdGwrWnCBtmWJS8djFvFwJNZLmH +ctwvxBwYt9aTIlQU8AzYOracxjdrJ/WUBD84TEhKAq2f/vvMzpelxXo0Yiecjw7/ ++U/h95sdn/XvH1n4T8zUE+uzAu4Rkr77RHuBOaPu9pXMKaAqiU4= +=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}} + + + +
    + {{site_title}} + + Stefan Hagen on Mastodon +
    +
    {{{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; +}