diff --git a/.gitignore b/.gitignore index 4d13571..02b5472 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,11 @@ *.html -!docs/about/resume.html +!/src/about/resume.html +*.meta +*.mk +/post/list +!/docs/about/resume.html rss.xml -www-root -docs/papers/.list +/www-root +/papers/*.pdf +/papers/*.dvi -# repo2html -.clist -.cref-bad -.cref-errlog -.hashcache diff --git a/.gitmodules b/.gitmodules index 50c2e22..04707be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "docs/papers/cptt"] path = docs/papers/cptt url = https://mikegerwitz.com/projects/cptt +[submodule "papers/cptt"] + path = papers/cptt + url = https://mikegerwitz.com/projects/cptt +[submodule "papers/coope"] + path = papers/coope + url = https://mikegerwitz.com/projects/coope diff --git a/Makefile b/Makefile index 9a8dad4..20a9475 100644 --- a/Makefile +++ b/Makefile @@ -1,107 +1,136 @@ # Builds thoughts (well, not quite like that) # -# Copyright (C) 2013 Mike Gerwitz +# Copyright (C) 2013, 2018, 2019 Mike Gerwitz # -# This program is free software: you can redistribute it and/or modify +# This program is free software: you can rewww-ribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # -# This program is distributed in the hope that it will be useful, +# This program is www-ributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# # +# +# This project is a static site generator. This Makefile was written to +# have deep knowledge of every aspect of the site so that it can be +# incrementally built, and so that all relevant portions will be properly +# rebuilt any time something changes. +# +# Source files are automatically identified through either wildcards or +# Makefile generation with one important exception: things in src/. The +# reason is that src/ contains a number of things we don't want published, +# and the distinction is too messy to codify. Of course, another option is +# to clean that up, but I don't mind being explicit for now. +## -pages := $(patsubst %.pg, %.html, \ - $(shell find docs/ -name '*.pg')) -pages_md := $(patsubst %.md, %.html, \ - $(shell find docs/ -name '*.md')) -articles := $(patsubst %.txt, %.html, \ - $(shell find docs/ -maxdepth 2 -name '*.txt' | grep -Fv /gh/)) -# articles in TeX with an inappropriate var name -texticles=$(patsubst %/, %.html, $(dir $(shell find docs/ -name 'Makefile'))) -www_root := www-root/ -url_root := https://mikegerwitz.com -repo_url := https://mikegerwitz.com/projects/thoughts -repo_commit_url := '$(repo_url)/commit/?id=%s' +.DELETE_ON_ERROR: -# configured repo2html command -repo2html := repo2html \ - -t 'Mike Gerwitz' \ - -d 'Free Software Hacker+Activist' \ - -c 'Mike Gerwitz' \ - -l 'This content is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.' \ - -C '/style.css' \ - -f 'tools/thoughts-fmt' \ - -F .listfilter \ - -T '$(PWD)/tpl' \ - -u '$(repo_url)' \ - -U '$(repo_commit_url)' \ - -E '' +postsrc := $(wildcard post/*.md) +pmeta := $(postsrc:.md=.meta) +phtml := $(postsrc:.md=.html) +pmk := $(pmeta:.meta=.mk) -.PHONY: default clean pages articles thoughts docs +www-root = www-root + +# articles in TeX +texticles = $(wildcard papers/*/) +www-paper = $(patsubst papers/%/, $(www-root)/papers/%.pdf, $(texticles)) \ + $(patsubst papers/%/, $(www-root)/papers/%.dvi, $(texticles)) + +images = $(wildcard images/*.*) $(wildcard images/tp/*.*) +www-images = $(patsubst images/%, $(www-root)/images/%, $(images)) + +cssfonts := $(shell build-aux/lsfonts) +www-fonts := $(patsubst fonts/%, $(www-root)/fonts/%, $(cssfonts)) + +# Manually maintain both for simplicity and to ensure something does not get +# unintentionally published. +srcpages = src/index.html src/about.html src/papers.html src/posts.html \ + src/talks.html src/404.html src/about/inside.html \ + src/about/githubbub.html \ + src/about/resume.html $(wildcard src/about/resume/*) +www-pages = $(patsubst src/%, $(www-root)/%, $(srcpages)) + +www-files = $(www-pages) $(www-root)/style.css $(www-root)/rss.xml $(www-paper) \ + $(www-images) $(www-fonts) + +RSS_N=10 +export WWW_URL + + +.PHONY: default clean webroot default: www-root -thoughts: - mkdir -p "$(www_root)" - $(repo2html) \ - -R 40 \ - -o "$(www_root)" \ - '$(url_root)' \ - > "$(www_root)/index.html" +%.meta: %.html src/post2meta src/post2html + src/post2meta $< > $@ +src/talks.html: src/talks.rec +src/papers.html: src/papers.rec +%.html %.xml: %.sh post/list src/mkheader src/header.tpl.htm src/footer.tpl.htm $(phtml) + $< > $@ +%.html: %.md src/post2html src/mkheader src/h12title src/header.tpl.htm src/footer.tpl.htm src/pandoc.tpl + src/post2html $< > $@ +%.html: %.htm src/mkheader src/h12title src/header.tpl.htm src/footer.tpl.htm + src/mkheader about @__PAGE_TITLE__@ \ + | cat - $< src/footer.tpl.htm \ + | src/h12title @__PAGE_TITLE__@ \ + > $@ -# all .txt articles will be compiled with asciidoc, then post-processed with the -# mgify script -%.html: %.txt - asciidoc -fasciidoc.conf -v \ - -a stylesdir= \ - -a themedir=$(PWD)/ \ - $< - ./tools/mgify "$@" +# special outputs +src/rss.xml: src/rss.sh post/list $(phtml) + head -n$(RSS_N) post/list | xargs $< > $@ -# "pages" -%.html: %.pg docs/papers/.list tpl/.config - $(repo2html) -icontent -ftools/extfmt <$< >$@ -%.html: %.md tpl/.config - $(repo2html) -icontent -ftools/mdfmt <$< >$@ +posts: $(pmeta) $(phtml) +post/list: $(pmeta) + ls post/*.meta | sort -rn > $@ -# TeX papers are expected to have their own makefiles as well as an abstract.tex -%.html: %/abstract.tex - $(MAKE) -C '$(dir $<)' pdf dvi - url_root='$(url_root)' ./tools/texdoc '$(dir $<)' | $(repo2html) -icontent -ftools/extfmt >$@ +# Rules for generating the final webroot from the posts are themselves +# generated. This also appends dependencies to www-posts. +.PHONY: www-posts +post/%.mk: post/%.meta build-aux/mkmk + build-aux/mkmk $(www-root) $< > $@ + +# Note the conditional include only for webroot. This is needed for two +# reasons: +# 1. To avoid including them on `clean' (see GNU Make manual, which is +# where this snippet originated from); and +# 2. Because otherwise including the makefiles causes every pmete to be +# built, which is unnecessary for all but `webroot'. +# +# The alternative (and perhaps more proper means) to #2 would be to run mkmk +# as part of the meta target. This was originally done until a solution to +# `clean' was needed; this handles both situations well. +ifeq ($(MAKECMDGOALS),webroot) +include $(pmk) +endif + +webroot: www-posts $(www-files) +$(www-root)/style.css: style.css + install -Dma+r $< $@ +$(www-root)/%: src/% + install -Dma+r $< $@ +$(www-root)/fonts/%: fonts/% + install -Dma+r $< $@ +$(www-root)/papers/%: papers/% + install -Dma+r $< $@ +$(www-root)/images/%: images/% + install -Dma+r $< $@ + + +# TeX papers are expected to have their own Makefiles as well as an abstract.tex +papers/%.pdf: papers/%/abstract.tex + $(MAKE) -C $(dir $<) pdf + cp $(dir $<)/$*.pdf $@ +papers/%.dvi: papers/%/abstract.tex + $(MAKE) -C $(dir $<) dvi + cp $(dir $<)/$*.dvi $@ docs/papers/.list: thoughts articles echo "$(articles) $(texticles)" | tr ' ' '\n' | tools/doclist >$@ -images: images/tp/Makefile - $(MAKE) -C '$(dir $<)' all check -images/tp/Makefile: images/tp/gen-makefile - ( cd images/tp/ && ./gen-makefile ) >$@ - -pages: $(pages) $(pages_md) -articles: $(articles) $(texticles) -docs: pages articles -www-root: docs thoughts images - mkdir -p www-root/papers - ( cd docs/ \ - && find . -maxdepth 2 -name '*.html' -exec ../tools/doc-cp {} ../www-root/{} \; \ - && find . -maxdepth 3 \( -name '*.pdf' -o -name '*.dvi' \) -exec cp {} ../www-root/{} \; \ - ) - mkdir -p www-root/images/ - cp -v images/*.* images/tp/*.png www-root/images/ - cp -rv fonts/ www-root/ - cp -rv _raw/* www-root/ - cp -v style.css www-root/ - mkdir -p www-root/docs - cp -rv docs/gh/ www-root/docs/ - cp -rv docs/about/resume www-root/about/ - cp -rv docs/hoxsl www-root/hoxsl - clean: - rm -rf www-root/ - rm -f $(pages) $(pages_md) $(articles) $(texticles) + rm -rf $(www-root) $(pmeta) $(phtml) $(pmk) diff --git a/README b/README index e8d6356..52de14f 100644 --- a/README +++ b/README @@ -1,5 +1,4 @@ The miscellaneous thoughts and ramblings of a free software hacker. -This website is processed with repo2html. +https://mikegerwitz.com/ -http://mikegerwitz.com/ diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..a41c9f8 --- /dev/null +++ b/bootstrap @@ -0,0 +1,77 @@ +#!/bin/bash +# Prepares build environment +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This will also download any necessary third-party files. Note that all +# downloads are proxied over Tor (using `torify'). +## + +set -euo pipefail + +# Source fonts and license (SIL Open Font License 1.1) +declare -ra fonts=( + https://github.com/adobe-fonts/source-sans-pro/raw/c7ea228c8cd66f65dac985bef98fda12c9cfa713/WOFF/OTF/SourceSansPro-Light.otf.woff + https://github.com/adobe-fonts/source-sans-pro/raw/c7ea228c8cd66f65dac985bef98fda12c9cfa713/WOFF/OTF/SourceSansPro-Regular.otf.woff + https://github.com/adobe-fonts/source-sans-pro/raw/c7ea228c8cd66f65dac985bef98fda12c9cfa713/LICENSE.txt +) + +declare -r tpimagesdir=images/tp +declare -r fontdir=fonts + + +# Download third-party images. This not only keeps them out of the +# repository, but explicitly states in a reproducible manner how the images +# were manipulated (if at all). +get-images() +{ + echo 'retrieving third-party images...' + + ( cd "$tpimagesdir" && ./gen-makefile > Makefile ) + make -C "$tpimagesdir" all check +} + + +# Download and verify fonts and license. +get-fonts() +{ + local font dest + + echo 'retrieving font files...' + for font in "${fonts[@]}"; do + dest="$fontdir/$( basename "$font" )" + + test ! -f "$dest" || continue + torify wget "$font" -O "$dest" + done + + # Verify that we haven't been served bad files. This should only happen + # in the case of network failure or a malicious host, since the above URLs + # reference the commit hash. + echo 'verifying font files...' + ( cd "$fontdir" && sha512sum -c SHA512SUM ) +} + + +# Bootstrap. +main() +{ + get-images + get-fonts +} + + +main "$@" diff --git a/build-aux/lsfonts b/build-aux/lsfonts new file mode 100755 index 0000000..652615e --- /dev/null +++ b/build-aux/lsfonts @@ -0,0 +1,22 @@ +#!/bin/sh +# List fonts used by CSS +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +## + +grep -A2 @font-face style.css \ + | grep -o "fonts/[^']\+" + diff --git a/build-aux/mkmk b/build-aux/mkmk new file mode 100755 index 0000000..4f6a983 --- /dev/null +++ b/build-aux/mkmk @@ -0,0 +1,48 @@ +#!/bin/bash +# Generate dependency Makefile for post +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# The dependency Makefile is responsible for webroot generation. This is +# necessary since the directory structure of the webroot varies so wildly +# from that of the source. +## + +set -euo pipefail + + +# Generate Makefile. Produces webroot target and adds that target to the +# `www-posts' phony target. +main() +{ + local -r distdir=${1?Missing distdir} + local -r meta=${2?Missing post path} + + local slug + slug=$( recsel -P slug "$meta" ) + + local -r dest="$distdir/$slug.html" + local -r src="${meta%%.meta}.html" + + cat < \$@ +SHA512SUM: \$(images) + sha512sum \$(images) > \$@ check: - sha256sum -c SHA256SUM + sha512sum -c SHA512SUM clean: \$(RM) \$(images) diff --git a/images/tp/remote-list b/images/tp/remote-list index 84119f5..f92aaf1 100644 --- a/images/tp/remote-list +++ b/images/tp/remote-list @@ -1 +1,5 @@ eff-42.png https://web.archive.org/web/20170922020250/https://www.eff.org/files/2014/01/24/eff-logo-plain-rgb.png -trim -resize 42 -gravity center -extent 42x42 +eff-privacy.png https://web.archive.org/web/20190102234255/https://www.eff.org/files/issues/icon-privacy-1_0.png -scale x250 -crop 250x250+125+0 +fsfs-icons-beige.png https://web.archive.org/web/20190105011705/http://static.fsf.org/nosvn/images/badges/fsfs_icons_beige-bg.png +lp-2017-crop.png https://web.archive.org/web/20181208025632/https://libreplanet.org/2017/assets/img/site_logo_alternate.png -crop 75x75+29+0 + diff --git a/papers/coope b/papers/coope new file mode 160000 index 0000000..93fa274 --- /dev/null +++ b/papers/coope @@ -0,0 +1 @@ +Subproject commit 93fa274206c70606fca0b42d9329e3f8565816f4 diff --git a/papers/cptt b/papers/cptt new file mode 160000 index 0000000..41a35f3 --- /dev/null +++ b/papers/cptt @@ -0,0 +1 @@ +Subproject commit 41a35f3c37fd41772ff7ae8aca62d77c4cafcf6c diff --git a/src/404.htm b/src/404.htm new file mode 100644 index 0000000..4a1231e --- /dev/null +++ b/src/404.htm @@ -0,0 +1,20 @@ +
+

Page Not Found

+ +

+ Sorry the page you requested cannot be found; it may have been removed + or you may have stumbled across a broken link. If you believe that you + have received this message in error, please contact Mike directly. If + you have arrived at this page from an external link, please contact the + author of that website instead. +

+ +

+ [This is where one would insert the obligatory “we apologize for the + inconvenience”...but this is a personal site, not a business, so I'm not all + that sympathetic. If it's a bug, it'll be fixed. If you think that the page + you're looking for should exist (and that it did in the past), consider looking + through this site's repository (available on the Projects page) and seeing what + might have happened to it. Good day to you, kind sir/madam/otherwise.] +

+
diff --git a/src/about.htm b/src/about.htm new file mode 100644 index 0000000..c8622ef --- /dev/null +++ b/src/about.htm @@ -0,0 +1,90 @@ + + +
+

About

+ +

+ I am a free (as in + freedom) software hacker + and user freedom activist with a focus on user privacy and security. + I am a professional software developer dealing primarily with web development; + compiler construction; and software architecture, and have been + programming for about twenty years. + My other personal interests include mathematics, cryptography, + philosophy and ethics, pedagogy, writing, law, and various other fields. + I also closely follow the work of + the Free Software + Foundation, Electronic Frontier + Foundation, and other entities devoted to free information and free + society. +

+

+ I am the author of GNU + ease.js; + a member of the GNU evaluation + team; + hold an administrative role within GNU; + and volunteer for various other aspects of + the GNU Project and + the Free Software Foundation. +

+

+ I am a hacker, + not a cracker—the + latter breaks the security of systems, while the former expresses playful + creativity in their work. +

+

+ Outside of my field, + I enjoy time with my family—including my wife and two + sons—who + keep me very busy and help to keep me sane. + I also have a fascination with a wide range of sciences that I wish I had + the time to devote to researching. +

+

+ Much of this site is devoted to my thoughts and ramblings on various + matters and so will contain material that is subject to strong bias; + you are encouraged to construct your own opinions. + Formal papers contain no such influence without rationale and references. +

+

+ I may be contacted at mtg at gnu dot org. + I do not make use of “social media” websites, + though I may (or may not) respond to queries on websites that I am a + member of, + and I do host my own GNU + Social instance. +

+

+ (Note: This website itself is free/libre—the source code is + available via the commit hash links in the footer of various pages and + the content is licensed for free distribution and, in most cases, + modification.) +

+

+ I changed GPG keys in October 2016; + see my key transition statement, + signed with both my new + and old keys. +

+

+ LibrePlanet + 2016 Photo Copyright © 2016 Kori Feener, + CC BY 4.0; + used with permission. +

+
diff --git a/src/about/githubbub.md b/src/about/githubbub.md new file mode 100644 index 0000000..9893929 --- /dev/null +++ b/src/about/githubbub.md @@ -0,0 +1,126 @@ +# GitHubbub! GitHub Does Not Value Software Freedom. + +
+ ![GitHub](/images/octoright-large.png "GitHub logo rotated 270° to resemble a Copyright symbol")\ +
+ +If you hit this page expecting to have been taken to my GitHub profile, + then this is probably not what you were looking for; + but let me tell you why you're here. + +Before providing a link to something hosted on a service, + it is important to consider whether the service or website is antithetical + to the message you are trying to convey to your readers/visitors, + and whether it deserves clarification; + there's a little bit of both here. + +If you're looking for a host friendly toward free software, + take a look at the [GNU ethical repository criteria][gnu-repo], + which sets standards for acceptable hosts to parts of the + [GNU operating system][gnu]. + + +## Non-Free JavaScript +[Free software][freesw] guarantees your freedom to study, + modify, + and share the software that you use. +We value these freedoms on the desktop, + so why should we compromise when websites serve proprietary JavaScript + [just because it creates the illusion of remote execution][whyfreejs]? +When you visit a website that serves JavaScript to the client, + your web browser is automatically [downloading and executing][jstrap] + (often without your permission) ephemeral, unsigned, untrusted software. +If that JavaScript is not [freely licensed][librejs], + then the software running in your web browser is proprietary. + +**When you visit `github.com`, + you download over 200kB of obfuscated code, + much of which is proprietary.** +This code provides many website features that are fairly essential, + and *do not work with JavaScript disabled*: + +- Change repository names or descriptions; +- Delete repositories; +- Add an SSH key to your account; +- Fork repositories; +- Create pull requests; +- Enable and disable project features; +- Use the wiki and issue trackers; +- View graphs of statistics; +- And others. + +That is---GitHub forces you to run proprietary software in order to use much + of their website. +This is a bit startling for a host that owes its very existence to the + success and development of free software. + +## Desire To Remain Non-Free +I contacted GitHub back in April 2014 pointing out these concerns and + asking if they would be able to either liberate their JavaScript or make + GitHub's essential functionality work without JavaScript enabled. +The first response I received was from one of their "JavaScript Developers": + +> Hi Mike, +> +> Thanks for getting in touch with us here. Some of our internal projects are +> specific to running GitHub, and as such will probably remain closed. We do +> make an effort to open source projects that we create that we think would be +> beneficial to the community, some of which is JavaScript. +> +> You can see a list of some of the open source projects that power GitHub +> here: +> +> https://github.com/showcases/projects-that-power-github + +This response is unfortunately misguided---yes, + it is good that GitHub produces free software, + but it is a false assumption that their proprietary code would serve no + benefit to the community: + the very existence of their proprietary software [gives them unjust + control over their users][unjust]; + relinquishing that control is of benefit to the community. + +I replied to the above message to clarify my point. +After receiving no response, + I forwarded the e-mail to GitHub's original founders: + [Tom Preston-Werner][tom], + [Chris Wanstrath][chris], + and [PJ Hyett][pj]. +The response I received from Chris was blunt and discouraging: + +> Hey Mike, +> +> We have no plans to release github.com's JavaScript as free software at +> this time, nor do we have plans to remove the site's dependence on +> JavaScript. Thanks for the interest. + +The original correspondence is provided here: + +1. [Original request][gh-request] to `support@github.com`, Tom, Chris, and + PJ. +2. [Reply to my original request][gh-request-reply] from one of the developers. +3. [My reply to the developer][gh-request2] providing more information and + asking for a commitment. +4. [Forward of my reply][gh-request3] to Tom, Chris, and PJ, after having + received no response from the developer. +5. [Response from Chris Wanstrath][gh-request3-reply] stating that GitHub + has "no plans" to liberate its JavaScript or "remove the site's + dependence on JavaScript". + + +[gnu-repo]: https://www.gnu.org/software/repo-criteria.html +[gnu]: https://www.gnu.org/gnu/gnu.html +[freesw]: https://www.gnu.org/philosophy/free-sw.html +[whyfreejs]: https://www.gnu.org/software/easejs/whyfreejs.html +[jstrap]: https://www.gnu.org/philosophy/javascript-trap.html +[librejs]: https://www.gnu.org/software/librejs/free-your-javascript.html +[unjust]: https://www.gnu.org/philosophy/free-software-even-more-important.html +[tom]: https://github.com/mojombo +[chris]: https://github.com/defunkt +[pj]: https://github.com/pjhyett + +[gh-request]: /docs/gh/email-request.txt +[gh-request-reply]: /docs/gh/email-request-reply.txt +[gh-request2]: /docs/gh/email-request2.txt +[gh-request3]: /docs/gh/email-request3.txt +[gh-request3-reply]: /docs/gh/email-request3-reply.txt diff --git a/src/about/inside.htm b/src/about/inside.htm new file mode 100644 index 0000000..6a815da --- /dev/null +++ b/src/about/inside.htm @@ -0,0 +1,47 @@ +
+

GNU/Linux Inside

+ + A Big GNU Head + +

+ This website and the server on which it is hosted is run entirely + by free software. +

+

+ Do you use GNU/Linux or other free software on your website? Flaunt it! + Feel free to place the image below on your own website, blog, or + anywhere else you see fit to let others know that you support GNU and + free software. +

+

+ This image also helps to bring awareness to + the GNU operating system as well as + GNU’s philosophy. The + majority of users today consider the operating system to be called + “Linux”, which is false—this is the name of the kernel; + GNU is the operating + system. +

+

+ The page fold is transparent; it will therefore work well with + any background color. Please note that this is a PNG with + alphatransparency—older browsers that users shouldn’t be using anymore + (such as IE 6) will not render it properly unless you take the necessary + precautions. +

+

+ GNU/Linux Inside Page Fold +

+

+ Feel free + to download the + source file (GIMP), released under + the Creative + Commons Attribution-ShareAlike 2.0 Unported License. It + incorporates ``A + Bold GNU Head’’ by Aurelio A. Heckert, which appears at the top of + this page. +

+
diff --git a/docs/about/resume.html b/src/about/resume.html similarity index 100% rename from docs/about/resume.html rename to src/about/resume.html diff --git a/docs/about/resume/.gitignore b/src/about/resume/.gitignore similarity index 100% rename from docs/about/resume/.gitignore rename to src/about/resume/.gitignore diff --git a/docs/about/resume/style-print.css b/src/about/resume/style-print.css similarity index 100% rename from docs/about/resume/style-print.css rename to src/about/resume/style-print.css diff --git a/docs/about/resume/style.css b/src/about/resume/style.css similarity index 100% rename from docs/about/resume/style.css rename to src/about/resume/style.css diff --git a/src/footer.tpl.htm b/src/footer.tpl.htm new file mode 100644 index 0000000..ae3e779 --- /dev/null +++ b/src/footer.tpl.htm @@ -0,0 +1,107 @@ + + + + + diff --git a/src/h12title b/src/h12title new file mode 100755 index 0000000..c638b96 --- /dev/null +++ b/src/h12title @@ -0,0 +1,43 @@ +#!/bin/bash +# Copies first body h1 text into title +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This assumes that an
tag exists and assumes that is the main +# content from which the title ought to be derived. +## + +set -euo pipefail + + +main() +{ + local -r placeholder=${1?Missing placeholder} + + local body; + body=$( cat ) + + local title + title=$( + <<<"$body" grep -A1 ')[^<]+' \ + ) + + sed "s#$placeholder#${title/&/\\&}#" <<< "$body" +} + +main "$@" diff --git a/src/header.tpl.htm b/src/header.tpl.htm new file mode 100644 index 0000000..f2aa0e7 --- /dev/null +++ b/src/header.tpl.htm @@ -0,0 +1,30 @@ + + + + + + + @PAGE_TITLE@Mike Gerwitz + + + +
+
+

Mike Gerwitz

+

Free Software Hacker+Activist

+
+ + +
+ +
diff --git a/src/index.sh b/src/index.sh new file mode 100755 index 0000000..d899fcb --- /dev/null +++ b/src/index.sh @@ -0,0 +1,133 @@ +#!/bin/bash +# Generate index HTML page +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# The index page consists of post abstracts, some static text, and the +# static header and footer. All post metadata files must have been built, +# along with `post/list'. +# +# This script includes the static body (see `main'). +## + +set -euo pipefail + + +# Get the file name of the Nth most recent post. This relies on the +# existence of `post/list'. +pnfile() +{ + local -ri n=${1?Missing relative post number} + + sed "${n}q;d" post/list +} + + +# Read field FIELD from post metadata recfile FILE. +pmeta() +{ + local -r file=${1?Missing file name} + local -r field=${2?Missing field name} + + recsel -P "$field" "$file" +} + + +# Process each numeric argument using `abstract'. Each argument must be a +# relative post number (see `pnfile'). +abstracts() +{ + while [ $# -gt 0 ]; do + abstract "$1" + shift + done +} + + +# Generate HTML for relative post number N (see `pnfile'). +abstract() +{ + local -ri n=${1?Missing relative post number} + + local file title date slug body + file=$( pnfile "$n" ) + title=$( pmeta "$file" subject ) + date=$( pmeta "$file" date ) + slug=$( pmeta "$file" slug ) + body=$( pmeta "$file" abstract ) + + cat < +

$title

+ $body +

Posted on $date. + Read more » +

+
+EOF +} + + +# Generate index HTML page. +# TODO: Factor out static sections. +main() +{ + src/mkheader index + + cat < + + + +
+

Latest Posts

+ + $( abstracts {1..2} ) +
+ +
+

The Surreptitious Assault on Privacy, Security, + and Freedom

+ + + + Watch LibrePlanet 2017 Talk +
+ +
+

Older Posts

+ + $( abstracts {3..8} ) + + View all posts +
+EOF + + cat src/footer.tpl.htm +} + + +main "$@" diff --git a/src/mkheader b/src/mkheader new file mode 100755 index 0000000..292fe4f --- /dev/null +++ b/src/mkheader @@ -0,0 +1,53 @@ +#!/bin/bash +# Generate HTML header +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# The header is mostly static but contains a dynamic page type and title. +## + +set -euo pipefail + +declare -ri EX_USAGE=64 + + +# Generate header by populating @PAGE_{TITLE,TYPE}@. If no title is given, +# then the title will be completely omitted. If provided, it will have an +# em dash delimiter appended, with whitespace on both sides for visual +# clarity (contrary to my usual typographical conventions). +main() +{ + local -r type=${1?Missing type} + local -r title_orig=${2:-} + + local -r title=${title_orig/&/\\&} + + [[ $type =~ ^[a-z]+$ ]] || { + echo 'error: type must be an all-lowercase word' + exit $EX_USAGE + } + + [[ ! $title =~ \# ]] || { + echo "error: title must not contain \`#'" + exit $EX_USAGE + } + + sed "s#@PAGE_TITLE@#$title${title:+ \\— }#g + s#@PAGE_TYPE@#$type#g" \ + src/header.tpl.htm +} + +main "$@" diff --git a/src/pandoc.tpl b/src/pandoc.tpl new file mode 100644 index 0000000..c8deb96 --- /dev/null +++ b/src/pandoc.tpl @@ -0,0 +1,28 @@ +$for(include-before)$ +$include-before$ + +$endfor$ +$if(toc)$ +$toc$ + +$endif$ + +
+$body$ + +$if(tags)$ +
+

Tags

+
    + $for(tags)$ +
  • $tags$
  • + $endfor$ +
+
+$endif$ +
+ +$for(include-after)$ + +$include-after$ +$endfor$ diff --git a/src/papers.rec b/src/papers.rec new file mode 100644 index 0000000..966c6ec --- /dev/null +++ b/src/papers.rec @@ -0,0 +1,41 @@ +id: git-horror-story +type: post +ref: 2012-05-22-git-horror-story + +id: coope +type: latex +ref: papers/coope +pubdate: 2012-05-06 + +id: cptt +type: latex +ref: papers/cptt +pubdate: 2013-05-13 + +id: national-uproar +type: post +ref: 2013-06-10-national-uproar + +id: gnu-kwindows +type: post +ref: 2016-04-06-gnu-kwindows + +id: gitlab-gitorious-freesw +type: post +ref: 2015-05-20-gitlab-gitorious-freesw + +id: copyleft-vs-community +type: post +ref: 2013-08-13-copyleft-vs-community + +id: re-fsf-waste-away +type: post +ref: 2013-01-26-re-fsf-waste-high-priority + +id: vlc-lgpl +type: post +ref: 2012-11-17-vlc-lgpl + +id: re-skype-let-spy +type: post +ref: 2013-01-30-re-skype-let-spy diff --git a/src/papers.sh b/src/papers.sh new file mode 100755 index 0000000..1137b29 --- /dev/null +++ b/src/papers.sh @@ -0,0 +1,183 @@ +#!/bin/bash +# Generate papers HTML page +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Papers are (at least at present) written in LaTeX, whereas articles are +# simply posts. Both are specified in $PAPERFILE. This page generates +# abstracts for both formats, along with links to each of their output +# formats (one or more of PDF, DVI, HTML). +## + +set -euo pipefail + +# Refile containing paper references and metadata. +declare -r PAPERFILE=${PAPERFILE:-src/papers.rec} + + +# List ids of all papers in $PAPERFILE. +paper-list() +{ + recsel -CP id "$PAPERFILE" +} + + +# Retrieve field FIELD from paper ID in $PAPERFILE. +paper-field() +{ + local -r id=${1?Missing paper id} + local -r field=${2?Missing paper field} + + recsel -P "$field" -e "id = '$id'" "$PAPERFILE" +} + + +# Read field FIELD from post metadata recfile FILE. +post-field() +{ + local -r ref=${1?Missing post name} + local -r field=${2?Missing field name} + + recsel -P "$field" "post/$ref.meta" +} + + +# Generate abstract for article or paper ID. Delegates to one of +# {post,latex}-abstract based on its type. +abstract() +{ + local -r id=${1?Missing paper id} + + local type ref + type=$( paper-field "$id" type ) + ref=$( paper-field "$id" ref ) + + case "$type" in + post|latex) + "$type-abstract" "$id" "$ref";; + *) + echo "Unknown paper type for id \`$id" >&2 + return 1 + esac +} + + + +# Generate abstract for post REF. +post-abstract() +{ + local -r ref=${2?Missing post ref} + + local id title date abstract slug + id=$( post-field "$ref" id ) + title=$( post-field "$ref" subject ) + date=$( post-field "$ref" date ) + abstract=$( post-field "$ref" abstract ) + slug=$( post-field "$ref" slug ) + + cat < +

$title

+ + + + $abstract + +

Posted on $date.

+ +EOF +} + + +# Extract title from LaTeX document. Note that this performs no actual +# processing on that title, so this will need to be e.g. run through Pandoc +# in the future if titles contain something that should be parsed (like +# dashes). +latex-title() +{ + head -n1 | sed '1s/^% //;1a\\' +} + + +# Produce text of LaTeX abstract (from its abstract.tex). +# +# Two minor transformations are made: Footnotes are removed by exploiting +# Pandoc's behavior of ignoring unknown/unsupported commands, since that +# doesn't look very good in the abstract output. Emdashes have whitespace +# on either side removed to translate to my modern convention (this can be +# removed when old papers are updated). +latex-abstract-text() +{ + sed 's/\\footnote/\\void/; + s/ \+--- \+/---/g' \ + | pandoc -flatex -thtml +} + + +# Generate abstract for LaTeX document (from abstract.tex) ID located at +# path REF. REF is expected to contain `abstract.tex' and `REF.tex', along +# with the built `REF.pdf' and `REF.dvi'. +latex-abstract() +{ + local -r id=${1?Missing paper id} + local -r ref=${2?Missing paper ref} + + local -r abstract_tex="$ref/abstract.tex" + local -r main="$ref/${ref##*/}.tex" + local -r sans=${main%/*.tex} + + local title abstract pubdate + title=$( latex-title < "$main" ) + abstract=$( latex-abstract-text < "$abstract_tex" ) + pubdate=$( paper-field "$id" pubdate ) + + cat < +

$title

+ + + + $abstract + +

Published on $pubdate.

+ +EOF +} + + +# Generate papers page. +main() +{ + src/mkheader papers Papers + + local papers + papers=$( recsel -P id src/papers.rec ) + + echo '

Papers / Articles

' + paper-list | while read id; do abstract "$id"; done + + cat src/footer.tpl.htm +} + + +main "$@" diff --git a/src/post2html b/src/post2html new file mode 100755 index 0000000..1785541 --- /dev/null +++ b/src/post2html @@ -0,0 +1,96 @@ +#!/bin/bash +# Generate HTML from post Markdown source +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script accepts the file name rather than data on stdin because the +# filename encodes the post date. +# +# Note that the `pagetitle' is set to "ignoreme"---it is not used, but is +# needed to suppress the warning pandoc produces without suppressing all +# warnings. +# +# Pandoc is used to generate the HTML and includes a (mostly) static header +# and footer. Note that this duplicates the date logic in `post2meta', +# because that must be run on this output, but the post must also contain +# the date, and we want to do all HTML processing now. +## + +set -euo pipefail + +# Pandoc output format and extensions. +declare -ra ext=( + markdown + smart + footnotes + gfm_auto_identifiers + fancy_lists + startnum + tex_math_dollars +) + + +# Convert extensions to `+'-delimited string. +pexts() +{ + local IFS=+ + echo "${ext[*]}" +} + + +# Wrap h1 in an hgroup along with the post date. +# +# Sometimes this script is used on things that aren't posts (e.g. normal +# pages), in which case a date will be unavailable and the output will be +# unchanged. +hgroup-wrap() +{ + local -r date=${1?Missing date} + + # Abort if this is not a date prefix + [[ $date =~ [0-9]{4}-[0-9]{2}-[0-9]{2} ]] || { + cat + return + } + + sed '/^

+ a

'"$date"'

+ }' +} + + +# Generate HTML from post. Note that `pagetitle' is set just to suppress +# Pandoc warnings about it missing; it is unused. +main() +{ + local -r file=${1?Missing file name} + local -r base=$( basename "$file" .md ) + local -r date=${base:0:10} + + pandoc -f"$( pexts )" -thtml5 \ + --standalone --template src/pandoc.tpl \ + --metadata pagetitle:ignoreme \ + --base-header-level=1 \ + -B <( src/mkheader post @__PAGE_TITLE__@ ) \ + -A src/footer.tpl.htm \ + < "$file" \ + | src/h12title @__PAGE_TITLE__@ \ + | hgroup-wrap "$date" +} + + +main "$@" diff --git a/src/post2meta b/src/post2meta new file mode 100755 index 0000000..c50c97e --- /dev/null +++ b/src/post2meta @@ -0,0 +1,80 @@ +#!/usr/bin/gawk -f +# Cache post data in metadata recutils file +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Generates database of metadata for a given post in recutils format for use +# by other scripts. The post must have already been converted to HTML using +# `post2html' or some equivalent means. +# +# This script is also responsible for determining what constitutes the +# abstract, which we consider to be everything after the subject line but +# before the end-of-abstract marker "". If no such marker +# exists then the script exits in error. +## + +# Output author and post date derived from the file name. +BEGINFILE { + match( FILENAME, /[^/]+$/, name ) + + # TODO: configurable + print "author: Mike Gerwitz " + + printf "date: %s\n", + gensub( /^(.{10}).*$/, "\\1", "", name[0] ) +} + +# Wait until after
; everything before it is the HTML header. +/^ *
/ { main=1 } +!main { next } + + +# The first header represents the subject/title and also contains the +# unique id for this post (as generated by `post2html'). +main && /^

]+>/, "", "g" ) + + # Grab the generated id from the header and use it to + # generate a complete slug. + printf "slug: %s/%s\n", \ + gensub( /^([0-9]+)-([0-9]+).*$/, "\\1/\\2", "", name[0] ), \ + gensub( /^]+ id="([^"]+)".*$/, "\\1", "" ) + + # Skip the date line immediately following the header and grab the first + # line of the abstract. + getline + getline + + printf "abstract: %s\n", $0 + a = 1 + next +} + +# The end-of-abstract marker is "". Until we reach that point, +# output each line of the abstract prefixed by a `+', which is the recutils +# line continuation marker. +/^/ { exit } +a { printf "+ %s\n", $0 } + +# If we get to this point, that means that there is no end-of-abstract +# marker, which we will consider to be an error just to make sure that the +# author didn't forget to add one. If the entire post is to be considered +# part of the abstract, then the marker can be added at the end of the post. +ENDFILE { + print "error: missing ''" > "/dev/stderr" + exit 1 +} diff --git a/src/posts.sh b/src/posts.sh new file mode 100755 index 0000000..a3c6182 --- /dev/null +++ b/src/posts.sh @@ -0,0 +1,103 @@ +#!/bin/bash +# Generate posts HTML page +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# The generated page contains the abstracts of _all_ posts; this may get +# unwieldy over time. +# +# TODO: Maybe refactor common abstract logic with `index.sh' and +# `papers.sh'? +## + +set -euo pipefail + +# Last generated yet (see `abstract-from'). +declare -i lastyear=0 + + +# Get the file name of the Nth most recent post. This relies on the +# existence of `post/list'. +pnfile() +{ + local -ri n=${1?Missing relative post number} + + sed "${n}q;d" post/list +} + + +# Read field FIELD from post metadata recfile FILE. +pmeta() +{ + local -r file=${1?Missing file name} + local -r field=${2?Missing field name} + + recsel -P "$field" "$file" +} + + +# Generate HTML for relative post number N (see `pnfile'). +abstract-from() +{ + local -r file=${1?Missing post file name} + + local title date slug body + title=$( pmeta "$file" subject ) + date=$( pmeta "$file" date ) + slug=$( pmeta "$file" slug ) + body=$( pmeta "$file" abstract ) + + local -ri year=${date:0:4} + + if [ $year -ne $lastyear ]; then + test $lastyear -eq 0 || echo '' + lastyear=$year + + cat < +

$year

+EOF + fi + + cat < +

$title

+ $body +

Posted on $date. + Read more » +

+ +EOF +} + + +# Generate posts page. +main() +{ + src/mkheader posts Posts + + local file + while read file; do + abstract-from "$file" + done < post/list + + echo '
' + + cat src/footer.tpl.htm +} + + +main "$@" diff --git a/src/rss.sh b/src/rss.sh new file mode 100755 index 0000000..5fb506f --- /dev/null +++ b/src/rss.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# Generate RSS feed from given post metadata files +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# All posts must be provided on the command line as a path to each +# individual metadata file, in the order in which they should appear in the +# feed output. +## + +set -euo pipefail + +# Website root URL. +declare -r www=${WWW_URL:-https://mikegerwitz.com} + + +# Look up metadatum FIELD in metafile FILE. +pmeta() +{ + local -r file=${1?Missing metafile name} + local -r field=${2?Missing field name} + + recsel -P "$field" "$file" +} + + +# Generate RSS item for each post in provided arguments. +# See `gen-item'. +gen-items() +{ + while [ $# -gt 0 ]; do + gen-item "$1" + shift + done +} + + +# Generate RSS item for post in metadata file FILE. The abstract will be +# used for the item description. +gen-item() +{ + local -r file=${1?Missing file name} + + local subject author slug date + subject=$( pmeta "$file" subject ) + author=$( pmeta "$file" author ) + slug=$( pmeta "$file" slug ) + date=$( pmeta "$file" date ) + + # TODO: entire content? + local abstract + abstract=$( pmeta "$file" abstract ) + + cat < + <![CDATA[$subject]]> + + $www/$slug + $date + + +EOF +} + + +# Output usage information and exit with EX_USAGE. +usage() +{ + cat < + + + Mike Gerwitz's Thoughts and Ramblings + $www + + Posts and articles from a free software hacker and activst with a focus on user privacy and security + + $( gen-items "$@" ) + + +EOF +} + + +main "$@" diff --git a/src/talks.rec b/src/talks.rec new file mode 100644 index 0000000..3591e88 --- /dev/null +++ b/src/talks.rec @@ -0,0 +1,81 @@ +id: sapsf +title: The Surreptitious Assault on Privacy, Security, and Freedom +location: LibrePlanet 2017 +date: 2017-03-26 +locimg: lp-2017 +abstract: Privacy, security, and personal freedom: one cannot be had without the ++ others. Each of these essential rights are being surreptitiously ++ assaulted; only the most technical among us even know what to look for, ++ let alone how to defend ourselves. Governments, corporations, and groups ++ of ill-minded individuals are spying and preying upon both users and ++ bystanders with unprecedented frequency and breadth. For those of us who ++ do understand these issues, it would be irresponsible not to fight for ++ the rights of others and continue to bring these assaults to light. ++ ++ This talk will survey the most pressing issues of today, including ++ topics of government surveillance and espionage; advertisers and data ++ analytics; the Internet of Things; corporate negligence; public policy ++ and the crypto wars; dangers of a non-free Web and untrusted, ephemeral ++ software; pervasive monitoring; remote servers, services, and “the ++ cloud”; modern vehicles; the fight against decentralization and free ++ software; societal pressures and complacency with the status quo; and ++ more. ++ ++ Attendees will walk away with a broad understanding of these topics; an ++ overview of mitigations; and dozens of resources for further research ++ and discussion with others. No prior knowledge of security or ++ cryptography are necessary. +video-url: https://media.libreplanet.org/u/libreplanet/m/the-surreptitious-assault-on-privacy-security-and-freedom/ +link: /talks/sapsf.pdf Slides +link: /projects/sapsf/plain/sapsf.bib Bibliography +link: /projects/sapsf/ Source Code + + +id: ethics-void +title: The Ethics Void +location: LibrePlanet 2018 +date: 2018-03-25 +locimg: lp-2018 +abstract: Many communities have widely adopted codes of ethics governing the ++ moral conduct of their members and professionals. Some of these codes may ++ even be enshrined in law, and for good reason—certain conduct can have ++ enormous consequences on the lives of others. ++ ++ Software and technology pervade virtually every aspect of our lives. Yet, ++ when compared to other fields, our community leaders and educators have ++ produced an ethics void. Last year, I introduced numerous topics concerning ++ privacy, security, and freedom that raise serious ethical concerns. Join me ++ this year as we consider some of those examples and others in an attempt to ++ derive a code of ethics that compares to the moral obligations of other ++ fields, and to consider how leaders and educators should approach ethics ++ within education and guidance. +video-url: https://media.libreplanet.org/u/libreplanet/m/the-ethics-void/ +link: /talks/ethics-void.pdf Slides +link: /projects/ethics-void/ Source Code + + +id: online-freedom +title: Restore Online Freedom! +location: LibrePlanet 2016 +date: 2016-03-20 +locimg: lp-2016 +abstract: Imagine a world where surveillance is the default and users must ++ opt-in to privacy. Imagine that your every action is logged and analyzed to ++ learn how you behave, what your interests are, and what you might do ++ next. Imagine that, even on your fully free operating system, proprietary ++ software is automatically downloaded and run not only without your consent, ++ but often without your knowledge. In this world, even free software cannot ++ be easily modified, shared, or replaced. In many cases, you might not even ++ be in control of your own computing—your actions and your data might be in ++ control by a remote entity, and only they decide what you are and are not ++ allowed to do. ++ ++ This may sound dystopian, but this is the world you’re living in right ++ now. The Web today is an increasingly hostile, freedom-denying place that ++ propagates to nearly every aspect of the average users’ lives—from their PCs ++ to their phones, to their TVs and beyond. But before we can stand up and ++ demand back our freedoms, we must understand what we’re being robbed of, how ++ it’s being done, and what can (or can’t) be done to stop it. +video-url: https://media.libreplanet.org/u/libreplanet/m/restore-online-freedom/ +link: https://media.libreplanet.org/u/libreplanet/m/restore-online-freedom-14bf/ Slides +link: /projects/online-freedom/ Source Code diff --git a/src/talks.sh b/src/talks.sh new file mode 100755 index 0000000..15f87dd --- /dev/null +++ b/src/talks.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# Generate talks HTML page +# +# Copyright (C) 2019 Mike Gerwitz +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Talks are organized along with abstract in $TALKFILE. Abstracts are +# assumed to be Markdown-formatted and are run through Pandoc. A link to +# the talk video is provided, along with any supplemental links provided via +# $TALKFILE (e.g. slides, source code, bibliography). +## + +set -euo pipefail + +# Recfile containing talk abstracts and metadata. +declare -r TALKFILE=${TALKFILE:-src/talks.rec} + + +# List ids of all talks in $TALKFILE. +talk-list() +{ + recsel -CP id "$TALKFILE" +} + + +# Retrieve field FIELD from talk identified by ID in $TALKFILE. +talk-field() +{ + local -r id=${1?Missing talk id} + local -r field=${2?Missing talk field} + + recsel -P "$field" -e "id = '$id'" "$TALKFILE" +} + + +# Generate abstract for talk. +abstract() +{ + local -r id=${1?Missing talk id} + + local title location locimg date abstract url links + title=$( talk-field "$id" title ) + location=$( talk-field "$id" location ) + locimg=$( talk-field "$id" locimg ) + date=$( talk-field "$id" date ) + abstract=$( talk-field "$id" abstract ) + url=$( talk-field "$id" video-url ) + links=$( talk-field "$id" link ) + + local abstract_html + abstract_html=$( pandoc -fmarkdown -thtml5 <<< "$abstract" ) + + cat < +

$title

+ + + + $abstract_html + +

Presented on $date.

+ +EOF +} + + +# Generate talks page. +main() +{ + src/mkheader talks Talks + + local talks + talks=$( recsel -P id src/talks.rec ) + + echo '

Talks

' + talk-list | while read id; do abstract "$id"; done + + cat src/footer.tpl.htm +} + + +main "$@" diff --git a/style.css b/style.css index d13c4e5..bba5f6c 100644 --- a/style.css +++ b/style.css @@ -1,111 +1,186 @@ +/** + * mikegerwitz.com stylesheet + * + * Copyright (C) 2019 Mike Gerwitz + * This work is released under the Creative Commons Attribution + * Share-Alike 4.0 International license. + */ + +/* TODO: Good font stack to fall back on if user has fonts blocked. */ @font-face { - font-family: Open Sans; - src: url('/fonts/OpenSans-Regular.woff'); + font-family: Source Sans Pro; + src: url('/fonts/SourceSansPro-Regular.otf.woff'); +} +@font-face { + font-family: Source Sans Pro Light; + src: url('/fonts/SourceSansPro-Light.otf.woff'); +} + +html { + /* see footer; just in case the page is too short */ + background-color: #2e3436; } body { - margin: 1em 5em; + background-color: white; + + /* TODO: slightly non-black color */ + + margin: 0; + padding: 2em 4em 0em 4em; + /*padding: 1em 5em;*/ + text-align: justify; - font-family: 'Open Sans', 'Liberation Sans', sans-serif; + font-family: 'Source Sans Pro', 'Liberation Sans', sans-serif; } -body.index, -.body-index { - margin: 2em 10em 1em 10em; - padding-right: 300px; -} - -/* override above, since we'll have to compound - * with the original body (only use this when - * body.index cannot possibly be used!) */ -.body-index { - margin: 2em 5em 1em 5em; -} - -body.index.no-sidebar, -.body-index.no-sidebar { - padding-right: 0px; -} - - a { color: #0066cc; } a:visited { color: #6666cc; } -/* hanging; ids for asciidoc styling */ -header, footer, -#header, #footer, .article #copyright { - margin: 0em -3em; - text-align: left; +.title > a { + color: black; + text-decoration: none; } -body.index footer, -.body-index footer { - margin: 0em -10em; + +a.box { + display: block; + width: 200px; + padding: 204px 0 0 0; + + border-width: 4px; + border-style: solid; + border-color: #2e3436; + + background-color: #2e3436; + color: white; + + background-repeat: no-repeat; + background-size: contain; + + text-align: center; + font-weight: bold; + font-size: 1.2em; + + text-decoration: none; } -/* typesetting standards for ~60 chars per line */ -body article .content, -body.article #content { - clear: both; - margin: auto; - - max-width: 38em; /* fallback for older browsers */ - max-width: 60ch; - - line-height: 1.8em; -} -/* ~70 for certain articles because of nesting (like GHS) */ -body.article #content { - max-width: 44em; /* fallback for older browsers */ - max-width: 70ch; -} -body article header, -body.article #header { - margin: auto; - - max-width: 44em; /* fallback for older browsers */ - max-width: 70ch; +a.box:hover { + border-top-width: 8px; + padding-top: 200px; + background-position: 0px -4px; } -h1, h2, h3, #menu, -body.index ul.index li .day, -.author, -strong { - font-family: 'URW Gothic L', 'Avant Garde', sans-serif; +a.box:visited { + color: white; +} + + +/* Asides should be dimmed so as not to distract from + the main content. */ +aside a.box { + filter: grayscale(100%); + transition: filter 0.25s; +} +aside a.box:hover { + filter: none; +} + + +/* Link lists are to be styled in context-specific ways. */ +ul.links { + display: block; + padding: 0; + margin: 0; + text-align: center; +} +ul.links > li { + display: block; + margin-top: 1em; +} +ul.links > li:first-child { + margin-top: 0; +} + + +.talk ul.links { + display: inline-block; +} + + +/* Talk images */ +.talk .links a.video { + display: block; + background-repeat: no-repeat; + + line-height: 2em; /* some space below image */ +} +.talk .links a.video.lp-2016 { + background-image: url('images/lp-2016.png'); + padding-top: 75px; + min-width: 220px; +} +.talk .links a.video.lp-2017 { + background-image: url('images/lp-2017.png'); + padding-top: 75px; + min-width: 220px; +} +.talk .links a.video.lp-2018 { + background-image: url('images/lp-2018.png'); + padding-top: 97px; + min-width: 200px; +} + + +a.box.free-sw { + background-image: url('images/tp/fsfs-icons-beige.png'); +} +a.box.eff-privacy { + background-image: url('images/tp/eff-privacy.png'); +} + + +main { + position: relative; +} + +main > aside { + float: right; +} +aside.sm { + max-width: 30ch; + font-size: 0.9em; +} + + +h1, h2, h3 { font-weight: normal; } -h1 { font-size: 1.8em; } +h1 { font-size: 1.7em; } h2 { font-size: 1.4em; } +h3 { font-size: 1.1em; } +h4 { font-size: 1.0em; } -h2.date { - display: block; - font-size: 1.1em; - color: #666f63; - - margin: -1em 1.5em 1.5em 0em; - float: left; -} - -h2.date ~ .author { - display: block; - margin-top: -1em; -} - -.author > .email { - margin-left: 0.25em; -} h1 a, h1 a:visited { text-decoration: none; color: inherit; } -/* latter for asciidoc-generated output */ -h1.title, -#header h1 { + +header { + position: relative; + margin: 0 0 2em 0; +} + +header h1 { font-size: 2em; - margin-bottom: 0.1em; + margin: 0px 0px 0.1em 0px; + text-align: left; +} + +.title { text-align: left; } @@ -116,123 +191,193 @@ h2.desc { font-weight: normal; color: #666f63; - margin-top: 0px; - margin-bottom: 2em; + margin: 0px 0px 2em 0px; } -#menu { +header nav { + position: absolute; + top: 0; + right: 0; +} + +.menu ul { + display: inline-block; text-align: center; padding: 0; - margin: 0px -300px 3.5em 0px; -} -.no-sidebar #menu { - /* cancels out #menu padding above */ - margin-right: 0px; -} -#menu li { - display: inline-block; - font-size: 1.3em; - letter-spacing: 0.05em; + margin: 0; - /* in addition to the 3.5em above; allows - for decent spacing when line overflows - at lower resolutions - (3.5 + [0.5/1.3=0.38] = 4.0)*/ - margin-bottom: 0.38em; + /* height of h1 to the left */ + line-height: 2em; } -#menu li a { - color: #666f63; +.menu li { + display: inline-block; + font-size: 1.1em; + font-weight: bold; +} +.menu li a { + color: #2e3436; text-decoration: none; - border-left: 1px solid #868f83; padding: 0.15em 1em; } -#menu li:first-child a { - border-left: none; +.menu li a:hover { + border-bottom: 0.3ex solid #2e3436; } -#headline { + +main { + margin: auto; + width: 90ch; +} + +body.posts main { + width: auto; + max-width: 120ch; +} + + +/* Articles are formatted at a modest width that makes reading + easier. Reduced with makes it easier for the reader's eyes to scan to + the next line. Alternatively, the line spacing can be increased to make + it easier for the eyes to not loose their way. So the wider the text, + the larger the line spacing. */ + +article { + width: 70ch; + line-height: 1.8em; + margin: auto; +} +article.abstract { + width: 60ch; + line-height: 1.5em; + margin: 0; +} + +/* Main links appear to the right of the abstract. */ +article.abstract ul.links { position: absolute; - text-align: center; - right: 10em; + right: 0; + min-width: 25ch; } -#headline a { - display: block; - text-decoration: none; - margin-top: 2em; - clear: left; + + +article.abstract .title { + display: inline-block; + margin: 0; + font-weight: bold; + font-size: 1.1em; /* h3 */ + text-align: left; } -#headline a:first-child { + +article:not(.abstract) > hgroup { + margin: 0 -2rem; +} +article:not(.abstract) > h1:not(:first-child), +article:not(.abstract) > h2 { + margin-left: -2rem; + border-bottom: 2px solid #babdb6; +} +article:not(.abstract) > h3 { + border-bottom: 1px solid #babdb6; +} + +article .date { + font-size: 0.9em; + color: #666f63; + margin-top: -1em; +} + +article.abstract { + margin-top: 1em; +} + +article.abstract p:first-of-type { margin-top: 0; } -#headline img { - margin-left: 2em; + +/* Images are all centered by default. */ +article img { + display: block; + margin: 0 auto; } -body.index .content, -.body-index .content { - /* this is not ideal, but works since the sidebar content is (currently) all - images */ - min-height: 750px; - padding-right: 1.5em; - /* don't let text get too wide */ - max-width: 40em; - margin: auto; - - line-height: 1.8em; -} -#cgit .content { - max-width: none; -} -body.index.no-sidebar .content, -.body-index.no-sidebar .content { - min-height: inherit; +section.compact { + clear: both; } -body.index h3.index { - margin-bottom: 0.5em; +section.compact article { + width: 48%; + float: right; } -body.index ul.index { - text-align: left; - list-style: none; - margin: 0px; - padding-left: 1.5em; -} -body.index ul.index li { - margin: 1em 0px; -} -body.index ul.index li .day { + +/* the first child is the section heading, so odds should + be on the left */ +section.compact article:nth-child(2n) { float: left; - margin-right: 0.5em; + clear: both; } -p#ref-0 { - margin-top: 2em; + +/* posts */ +body.posts section.compact:not(:first-child) { + padding-top: 2em; } -p.ref { +body.posts section.compact > h1 { + text-align: center; +} + + +section .view-all { + display: block; + text-align: center; + margin: 1em auto; + clear: both; +} + + +section.highlight { + display: block; + background-color: #2e3436; + padding: 2em; + color: #eeeeee; /* just slightly less jarring */ + margin: 2em 0; + clear: both; +} + +section.highlight > .title { + font-size: 1.2em; + display: inline-block; + width: 50%; + font-weight: bold; + margin-top: 0; +} + +section.highlight aside { + display: block; + float: right; + width: 40%; + + font-family: 'Source Sans Pro Light'; font-size: 0.9em; - margin: 0.25em 0em; - text-align: left; -} -sup { - font-size: 0.6em; -} -p.ref:target { - background-color: #fce94f; } -pre { - white-space: pre-wrap; +section.highlight a.lp-watch { + display: inline-block; + + background-image: url('images/tp/lp-2017-crop.png'); + background-repeat: no-repeat; + background-position: middle left; + + /* accommodate background image */ + line-height: 75px; + padding-left: 85px; /* 75px + 10px margin between */ + + font-size: 1.2em; + color: white; + + clear: left; } -dt { - letter-spacing: 0.1em; -} - -tt { - background-color: #eeeeec; - color: #000055; -} .inline-img { text-align: center; @@ -258,21 +403,8 @@ tt { margin-left: auto; } -.listingblock { - background-color: #eeeeec; - background-image: url('images/cross_scratches.png'); - padding: 0.5em; - border: 1px solid #babdb6; - border-radius: 0.25em -} -.exampleblock { - margin-left: 2em; - padding-left: 1em; - border-left: 5px solid #eeeeec; -} - -#gnuinside { +.page-flip { position: absolute; display: block; @@ -282,47 +414,114 @@ tt { height: 50px; } -footer, #footer, .article #copyright { - font-size: 0.9em; - margin-top: 2em; - clear: both; -} -footer .commit-id { - font-family: monospace; +.affiliation-list ul { + display: inline-block; + text-align: center; + padding: 0; + margin: 0; } - -/* to account for headline (sidebar) */ -body.index footer .bimgs, -.body-index footer.bimgs, -body.index footer hr, -.body-index footer hr { - margin-right: -300px; +.affiliation-list ul > li { + display: inline-block; + margin: 1em; } - -.no-sidebar footer .bimgs, -.no-sidebar footer hr { - margin-right: 0px; -} - -#selflinks { - position: absolute; - top: 60px; - right: 0px; - width: 42px; - padding: 6px; -} -#selflinks a { +.affiliation-list a { text-decoration: none; } -#selflinks img { - transition: transform 0.25s; +.affiliation-list img:not(:hover) { + transition: filter 3s; + filter: grayscale(100%); } -#selflinks img[src*=octoright]:hover { +.affiliation-list img[src*=octoright] { + transition: transform 0.5s; +} +.affiliation-list img[src*=octoright]:hover { transform: rotate(-20deg); } +.hn-icon { + display: inline-block; + position: relative; + + background-color: #ff6600; + + width: 42px; + height: 42px; + top: -1em; + + font-size: 16px; + font-weight: bold; + text-align: center; + line-height: 42px; +} +.hn-icon:not(:hover) { + transition: background-color 3s; + background-color: #888888; +} + +.hn-icon, +a.hn-icon:visited, +a.hn-icon:active, +a.hn-icon:hover { + color: white; + text-decoration: none; +} + +br.end { + clear: both; +} + +footer, footer h2 { + font-family: 'Source Sans Pro Light'; +} +footer, #footer { + font-size: 0.8em; + text-align: center; + + background-color: #2e3436; + color: #eeeeee; + + margin: 4em -4rem 0 -4rem; + padding: 1em; + + clear: both; +} + +#copyright { + width: 80ch; + margin: 1em auto 0em auto; +} + +footer .site-nav { + display: inline-block; + margin: 0 auto 1em auto; +} +footer .site-nav > nav { + text-align: left; + float: left; + margin: 0 2em; +} +footer .site-nav > nav > h2 { + font-size: 1.2em; + margin: 0; + font-weight: bold; +} +footer .site-nav > nav > ul { + display: inline-block; + padding: 0 0 0 0.5em; + margin: 0; + text-align: left; +} +footer .site-nav > nav > ul > li { + display: block; +} +footer .site-nav > nav > ul > li a { + color: white; + text-decoration: none; +} + + .octoflop { /* make upright again (image is rotated 270deg) */ transform: rotate(90deg); @@ -333,15 +532,6 @@ body.index footer hr, animation-fill-mode: forwards; } -.talk-logo { - display: block; - text-align: center; -} - -p ~ p .talk-logo { - margin-top: 5ex; -} - @keyframes octoflop { 30% { transform: rotate(-35deg); @@ -369,379 +559,24 @@ p ~ p .talk-logo { } } -.hn-icon { - display: block; - background-color: #ff6600; - - width: 42px; - height: 42px; - - font-size: 16px; - font-weight: bold; - text-align: center; - line-height: 42px; -} - -.hn-icon, -a.hn-icon:visited, -a.hn-icon:active, -a.hn-icon:hover { - color: white; - text-decoration: none; -} - -.bimgs { - float: right; - margin-left: 1em; -} - -.bimgs img { - margin-left: 0.1em; -} -.bimgs img:first-child { - margin-left: 0em; -} - -body.content .abstract { - font-size: 0.9em; -} -body.content .abstract .start { - font-weight: bold; -} - -dl > dd { - margin-bottom: 0.5em; -} - -dl > dd > dl { - margin-top: 1em; -} - -dl > dd > p:last-child { - margin-bottom: 0px; -} - -#postamble > p { - margin: 0em; -} - -#index-headline { - display: block; - margin: 0em auto 2em auto; -} - -#index-headline img { - border-radius: 0.25em; - max-width: 90%; -} - - -/** exclusively asciidoc-generated content styling **/ -body.article h2 { - position: relative; - - border-bottom: 2px solid #babdb6; - left: -2em; - - margin-right: -2em; -} - -body.article h3 { - border-bottom: 1px solid #babdb6; -} - -#author { - font-size: 1.1em; - letter-spacing: 0.1em; -} - -#footer { - border-top: 2px solid #babdb6; - padding-top: 0.5em; -} - -.article #copyright { - margin-top: 0; -} - -@media screen and (max-width: 1024px) { - body { - margin: 2em !important; - } - - /* account for upper-right page fold using the full - image width---this will be guaranteed to work - regardless of the user's font size; kinda ruins - the illusion if text is atop of it ;) */ - h1.subject { - margin-right: 50px; - } - - #headline { - right: 2em; - } - - header, footer, - #header, #footer, .article #copyright { - margin-left: 0px; - } - - body.index footer, - .body-index footer { - margin: 0em; - } -} - -@media screen and (max-width: 640px) { - body { - margin: 1em !important; - padding-right: 0 !important; - } - body.index .content, - .body-index .content { - min-height: 0px; - padding-right: 0px; - } - - header { - margin-right: 0px; - } - - #menu { - margin-right: 0px; - margin-bottom: 2em; - } - - #headline { - position: initial; - float: right; - width: 75px; - } - - #headline a { - display: inline; - margin: 0.5em; - } - #headline img { - max-height: 75px; - margin-left: 0; - } - #index-headline img { - max-height: 5em; - } - - #selflinks { - position: absolute; - top: 0px; - right: 50px; - width: auto; - height: 42px; - padding: 6px; - } - - .hn-icon { - float: right; - margin-left: 2px; - } - - header, footer, - body.index footer .bimgs, - .body-index footer .bimgs, - body.index footer hr, - .body-index footer hr, - #header, #footer, .article #copyright { - margin-right: 0px; - } - - .bimgs { - float: none; - margin-left: 0px; - } - - /* we're pretty low on real estate at this point */ - blockquote { - margin: 1em 0px 1em 2em; - } - - ul, ul.index { - padding-left: 1em !important; - } -} - -/* selflinks start to overlap with heading */ -@media screen and (max-width: 475px) { - #selflinks img { - max-width: 32px; - max-height: 32px; - } - - - .hn-icon { - max-width: 32px; - max-height: 32px; - - font-size: 12px; - line-height: 32px; - } -} - -/* when things start getting odd from 640px */ -@media screen and (max-width: 420px) { - #menu { - font-size: 0.8em; - } - - #selflinks img { - max-width: 21px; - max-height: 21px; - } - - .hn-icon { - max-width: 21px; - max-height: 21px; - - font-size: 9px; - line-height: 21px; - } - - footer { - font-size: 0.9em; - } - - .bimgs img { - width: 70px; - height: 25px; - } -} - - -/*** Org mode HTML output ***/ -/* much of the above will overlap, so only some is needed here */ -#postamble { - margin: 2em -5em 0em -5em; - text-align: left; - font-size: 0.9em; - - border-top: 1px solid #babdb6; - padding-top: 0.5em; -} - -.todo, .done { - font-size: 0.1em; - letter-spacing: -0.1em; - color: transparent; -} - -/* note that we must undo our hiding */ -.todo::before, -.done::before { - position: absolute; - visibility: visible; - - letter-spacing: normal; - font-size: 12em; - left: -1.5em; - top: -0.1em; - - font-weight: bold; -} - -.todo::before { - color: black; - content: '☐'; -} - -.done::before { - color: #4e9a06; - content: '☑'; -} - -/* eases positioning in, e.g., margin */ -.outline-1, -.outline-2, -.outline-3 { - position: relative; -} - -#table-of-contents .todo, -#table-of-contents .done { - display: none; -} - - -/** cgit customization **/ - -div#cgit div.content { - padding: 2em 0em; /* remove left/right margin */ -} - -/* repo name and desc, above tabs */ -div#cgit table#header td.main { - font-size: 1.4em; /* h2 font size (see above) */ -} -div#cgit table#header td.sub { - border-top: 0px; -} - -div#cgit #header { - margin: inherit; /* undo previous conflicting style */ -} - -/* reduce tab page separator height */ -div#cgit table.tabs { - border-bottom-width: 1px; -} -div#cgit table.tabs td a { - padding: 0.25ex 0.75em 0ex; -} -div#cgit table.tabs td a.active { - background-color: inherit; - border-bottom: 3px solid #ccc; -} - -div#cgit div.content { - border-bottom: inherit; /* we have our own footer */ -} - -/* we have limited width, so wrap and compensate */ -div#cgit table.list.nowrap td { - white-space: inherit; - text-align: left; -} -div#cgit table.list.nowrap td.sublevel-repo, -div#cgit table.list.nowrap td .age-months { - white-space: nowrap; -} -div#cgit table.list.nowrap tr { - vertical-align: top; -} - -div#cgit table.list tr:not(.nohover) td { - padding-top: 0.5ex; - padding-bottom: 0.5ex; -} - -/* getting creative...separate sections */ -div#cgit table.list tr:not(.nohover) + tr.nohover td { - padding-top: 1ex; -} - -/* reduce headings relative to surrounding page */ -div#cgit h1 { font-size: 1.4em; } -div#cgit h2 { font-size: 1.2em; } -div#cgit h3 { font-size: 1.1em; } -div#cgit h4 { font-size: 1.0em; } - - -/*** https://github.com/jgm/highlighting-kate/blob/master/css/hk-tango.css * ***/ +/*** https://github.com/jgm/highlighting-kate/blob/master/css/hk-tango.css ***/ +/* GNU GPLv2 */ /* Loosely based on pygment's tango colors */ +/* Modified where indicated by Mike Gerwitz */ table.sourceCode, tr.sourceCode, td.sourceCode, table.sourceCode pre { margin: 0; padding: 0; border: 0; vertical-align: baseline; border: none; background-color: #f8f8f8 } td.nums { text-align: right; padding-right: 5px; padding-left: 5px; background-color: #f0f0f0; } td.sourceCode { padding-left: 5px; } code.sourceCode { background-color: #f8f8f8; } -pre.sourceCode { background-color: #f8f8f8; line-height: 125% } +pre.sourceCode { + /* modified by Mike Gerwitz */ + padding: 1em; + margin: 0 -1em; + + background-color: #f8f8f8; + line-height: 125% +} td.nums pre { background-color: #f0f0f0; line-height: 125% } code.sourceCode span.kw { color: #204a87; font-weight: bold } /* Keyword */ code.sourceCode span.dt { color: #204a87 } /* Keyword.Type */