summaryrefslogtreecommitdiff
path: root/haunt
diff options
context:
space:
mode:
authorJakob L. Kreuze <zerodaysfordays@sdf.org>2021-12-14 21:02:40 -0500
committerJakob L. Kreuze <zerodaysfordays@sdf.org>2021-12-14 21:04:13 -0500
commit648ab07ee7b500935ba3673d897b9bddbc610934 (patch)
tree451d0ce2d355fce76f55a377fa22e3a3a8657a97 /haunt
parent90ad4c0e9b4d08d46a56130c44f4c04862bb0c06 (diff)
pages: Update biography front-matter and project listing
Diffstat (limited to 'haunt')
-rw-r--r--haunt/pages/about.sxml313
-rw-r--r--haunt/static/css/style.css76
2 files changed, 298 insertions, 91 deletions
diff --git a/haunt/pages/about.sxml b/haunt/pages/about.sxml
index c468721..be8114e 100644
--- a/haunt/pages/about.sxml
+++ b/haunt/pages/about.sxml
@@ -17,83 +17,227 @@
;;; <http://www.gnu.org/licenses/>.
(use-modules (ice-9 match)
+ (ice-9 rdelim)
+ (ice-9 popen)
(jakob theme)
- (jakob utils sxml))
+ (jakob utils sxml)
+ (srfi srfi-1)
+ (srfi srfi-19)
+ (sxml simple))
(define %software-projects
- '(("Rebuild" "Dormant"
+ `(("Kona" rust
+ "https://git.sr.ht/~jakob/kona"
+ "./repositories/kona/"
+ ("Lightweight, self-hosted tagged image gallery."))
+ ("zerodaysfordays" ebuild
+ "https://git.sr.ht/~jakob/zerodaysfordays"
+ "./repositories/zerodaysfordays/"
+ ("My personal Gentoo overlay."))
+ ("My Website" scheme
+ "https://git.sr.ht/~jakob/blog"
+ "../"
+ ("The website you're reading right now. Effectively a massive 'contrib'
+module for " ,(hyperlink "https://dthompson.us/projects/haunt.html" "Haunt")
+"."))))
+
+(define %abandoned-software-projects
+ `(("ox-haunt" elisp
+ "https://git.sr.ht/~jakob/ox-haunt"
+ "./repositories/ox-haunt/"
+ ("Haunt-flavored HTML backend for the Org export engine")
+ ,(string->date "Apr 05 2020" "~b ~e ~Y"))
+ ("Mines" kotlin
+ "https://git.sr.ht/~jakob/mines"
+ "./repositories/mines/"
+ ("Android implementation of the classic video game \"Minesweeper\".")
+ ,(string->date "Apr 12 2019" "~b ~e ~Y"))
+ ("Slime the World" fennel
+ "https://git.sr.ht/~jakob/slime-the-world"
+ "./repositories/slime-the-world/"
+ ("My entry for the 2018 Autumn Lisp Game Jam; a game about covering everything in slime.")
+ ,(string->date "Jan 01 2019" "~b ~e ~Y"))
+ ("Rebuild" rust
"https://git.sr.ht/~jakob/rebuild"
- ("An attempt at reimplementing Ken Silverman's Build engine, with the goal of being modular enough to host a modern Blood source port."))
- ("wildmidi" "Dormant"
+ "./repositories/rebuild/"
+ ("An attempt at reimplementing Ken Silverman's Build engine, with the goal of being modular enough to host a modern Blood source port.")
+ ,(string->date "Sep 23 2018" "~b ~e ~Y"))
+ ("wildmidi" rust
"https://git.sr.ht/~jakob/wildmidi"
- ("A simple [Rust] wrapper around the WildMIDI software synthesizer library."))
- ("Slime the World" "Finished"
- "https://git.sr.ht/~jakob/slime-the-world"
- ("My entry for the 2018 Autumn Lisp Game Jam; a game about covering everything in slime."))
- ("Nekopack" "Finished"
- "https://git.sr.ht/~jakob/nekopack"
- ("Tool for extracting game data from Nekopara's XP3 archives."))
- ("skullfuck" "Finished"
- "https://git.sr.ht/~jakob/skullfuck"
- ("Optimizing compiler for Brainfuck, contained in a single C source file."))
- ("Mines" "Abandoned"
- "https://git.sr.ht/~jakob/mines"
- ("Android implementation of the classic video game \"Minesweeper\"."))
- ("Hypodermic" "Abandoned"
- "https://git.sr.ht/~jakob/hypodermic"
- ("Proof-of-concept shared object injector that will eventually be integrated with PINCE."))
- ("Duke on FluidSynth" "Abandoned"
+ "./repositories/wildmidi/"
+ ("A simple [Rust] wrapper around the WildMIDI software synthesizer library.")
+ ,(string->date "Aug 31 2018" "~b ~e ~Y"))
+ ("Duke on FluidSynth" c++
"https://git.sr.ht/~jakob/duke-on-fluidsynth"
- ("Experimental FluidSynth MIDI driver for EDuke32."))))
-
-(define %emacs-projects
- '(("ox-haunt" "Active"
- "https://melpa.org/#/dired-rmjunk"
- ("Haunt-flavored HTML backend for the Org export engine."))
- ("dired-rmjunk" "Dormant"
- "https://melpa.org/#/dired-rmjunk"
- ("A port of Jakub Klinkovský's rmshit.py to Dired."))))
+ "./repositories/duke-on-fluidsynth/"
+ ("Experimental FluidSynth MIDI driver for EDuke32.")
+ ,(string->date "Apr 13 2018" "~b ~e ~Y"))
+ ("Hypodermic" python
+ "https://git.sr.ht/~jakob/hypodermic"
+ "./repositories/hypodermic/"
+ ("Proof-of-concept shared object injector that will eventually be integrated with PINCE.")
+ ,(string->date "Jan 22 2018" "~b ~e ~Y"))
+ ("skullfuck" c
+ "https://git.sr.ht/~jakob/skullfuck"
+ "./repositories/skullfuck/"
+ ("Optimizing compiler for Brainfuck, contained in a single C source file.")
+ ,(string->date "Jun 21 2017" "~b ~e ~Y"))
+ ("Nekopack" c
+ "https://git.sr.ht/~jakob/nekopack"
+ "./repositories/nekopack/"
+ ("Tool for extracting game data from Nekopara's XP3 archives.")
+ ,(string->date "Dec 01 2017" "~b ~e ~Y"))))
(define %software-contributions
- `(("GNU Guix" "Not Actively"
+ `(("GNU Guix" scheme
"https://guix.gnu.org"
- ("Functional package manager."))
- ("Radare2" "Not Actively"
+ "./repositories/guix"
+ ("Functional cross-platform package manager and a tool to instantiate and manage
+Unix-like operating systems, based on the Nix package manager.")
+ ,(string->date "Dec 28 2019" "~b ~e ~Y"))
+ ("Radare2" c
"https://www.radare.org/r/"
- ("UNIX-like reverse engineering framework and command-line tools."))
- ("Haiku" "Not Actively"
+ "./repositories/radare2"
+ ("UNIX-like reverse engineering framework and command-line tools.")
+ ,(string->date "Nov 09 2018" "~b ~e ~Y"))
+ ("Haiku" c++
"https://www.haiku-os.org/"
- ("The Haiku operating system."))))
+ "./repositories/haiku"
+ ("The Haiku operating system.")
+ ,(string->date "Jun 31 2019" "~b ~e ~Y"))
+ ("PINCE" python
+ "https://github.com/korcankaraokcu/PINCE"
+ "./repositories/pince"
+ ("A reverse engineering tool, comparable to Cheat Engine for GNU/Linux. I still
+maintain the Arch Linux package, which is unfortunate, as I no longer use Arch
+Linux.")
+ ,(string->date "Apr 15 2018" "~b ~e ~Y"))))
-(define %packaging-projects
- '(("zerodaysfordays" "Active"
- "https://git.sr.ht/~jakob/zerodaysfordays"
- ("My personal Gentoo ebuild overlay."))
- ("PINCE" "Active"
- "https://aur.archlinux.org/packages/pince-git/"
- ("A Linux reverse engineering tool inspired by Cheat Engine. I was a former
-upstream contributor. I still maintain the Arch Linux package, which is
-unfortunate, as I no longer use Arch Linux."))))
+(define (lang-to-button lang)
+ (case lang
+ ((c) '(button (@ (class "lang-c")) "C"))
+ ((c++) '(button (@ (class "lang-cpp")) "C++"))
+ ((python) '(button (@ (class "lang-python")) "Python"))
+ ((rust) '(button (@ (class "lang-rust")) "Rust"))
+ ((kotlin) '(button (@ (class "lang-kotlin")) "Kotlin"))
+ ((fennel) '(button (@ (class "lang-fennel")) "Fennel"))
+ ((elisp) '(button (@ (class "lang-elisp")) "Elisp"))
+ ((scheme) '(button (@ (class "lang-scheme")) "Scheme"))
+ ((ebuild) '(button (@ (class "lang-ebuild")) "Ebuild"))))
+
+(define (date-of-first-commit repository-path)
+ "Return the date of the first commit in `repository-path'."
+ (let* ((command (format #f "bash -c 'cd \"~a\"; git log --author=\"[Jj]akob\" --reverse --pretty=\"format:%at\" | head -n 1'"
+ repository-path))
+ (port (open-input-pipe command))
+ (str (read-line port)))
+ (close-pipe port)
+ (time-utc->date (make-time 'time-utc 0 (string->number str)))))
+
+(define* (bin-commit-counts repository-path #:key start end)
+ "Count commits per month-long interval between `start' and `end'.
+
+Take `end' to be `(current-date)' if unspecified. Similarly, take `start' to be
+the date of the first commit in the repository if unspecified."
+ (define (date-in-past date)
+ "Return `#t' iff `date' is in the past.
+
+If `end' is specified, return `#t' iff `date' is prior to `end'."
+ (time<=? (date->time-utc date)
+ (if end
+ (date->time-utc end)
+ (current-time 'time-utc))))
+ (define (increment-date-by-month date)
+ "Return a SRFI-19 date one month in the future from `date'."
+ ;; Special handling for leap years.
+ (define (days-in-month date)
+ (if (= 2 (date-month date))
+ (if (and (or (zero? (remainder (date-year date) 400))
+ (positive? (remainder (date-year date) 100)))
+ (zero? (remainder (date-year date) 4)))
+ 29
+ 28)
+ (cadr
+ (assoc (date-month date)
+ '((1 31) (3 31) (4 30) (5 31) (6 30) (7 31)
+ (8 31) (9 30) (10 31) (11 30) (12 31))))))
+ (time-utc->date
+ (add-duration (date->time-utc date)
+ (make-time 'time-duration 0 (* 60 60 24
+ (days-in-month date))))))
+ (define (count-commits-in-month start-date)
+ "Return the number of commits in the month starting on `start-date'."
+ (let* ((end-date (increment-date-by-month start-date))
+ (command (format #f "bash -c 'cd \"~a\"; git rev-list --count HEAD --author=\"[Jj]akob\" --since=\"~a\" --before=\"~a\"'"
+ repository-path
+ (date->string start-date "~b ~e ~Y")
+ (date->string end-date "~b ~e ~Y"))))
+ (let* ((port (open-input-pipe command))
+ (str (read-line port)))
+ (close-pipe port)
+ str)))
+ (let loop ((bin '())
+ (date (or start (date-of-first-commit repository-path))))
+ (if (date-in-past date)
+ (loop (cons (count-commits-in-month date) bin)
+ (increment-date-by-month date))
+ (reverse! (map string->number bin)))))
+
+(define* (render-histogram summary #:key (width 60) (height 25))
+ "Render a list of intervals as an SVG histogram."
+ ;; Assuming an interval lasts a month, I'm lucky to get 50 commits in.
+ (define max-commits-per-interval 50)
+ (define (format-shapes shapes)
+ `(svg (@ (xmlns "http://www.w3.org/2000/svg")
+ (version "1.1")
+ (width ,(number->string width))
+ (height ,(number->string height)))
+ ;; Border for the histogram.
+ (rect (@ (x "0") (y "0") (width ,width) (height ,height)
+ (stroke "black") (stroke-width "1")
+ (fill "transparent")))
+ ,@shapes))
+ (let* ((summary (if (> (length summary) 30)
+ (take-right summary 30)
+ summary))
+ (content-width (* 2 (length summary)))
+ (right-pad (max (- width content-width) 0))
+ (upper-bound (max max-commits-per-interval
+ (apply max summary))))
+ (format-shapes
+ (map (match-lambda
+ ((commit-count i)
+ `(line (@ (stroke "black")
+ (stroke-width "1")
+ ;; Separate strokes by 2px and pad to the right.
+ (x1 ,(+ right-pad (* i 2)))
+ (x2 ,(+ right-pad (* i 2)))
+ (y1 ,height)
+ (y2 ,(exact->inexact
+ (- height
+ (* (/ commit-count upper-bound)
+ height))))))))
+ (zip summary (iota (length summary)))))))
-(define (project name status url description)
- (let ((status-class (match status
- ("Active" "good")
- ("Not Actively" "info")
- ("Finished" "info")
- ("Dormant" "okay")
- ("Abandoned" "bad")
- (_ "info"))))
+(define* (project name lang url repository-path description #:optional end-date)
+ (let ((start-date (date-of-first-commit repository-path)))
`(tr (td ,(hyperlink url name))
- (td (button (@ (class ,(format #f "label-~a" status-class)))
- ,status))
+ (td ,(lang-to-button lang))
+ (td ,(render-histogram (bin-commit-counts repository-path #:end end-date)))
+ (td ,(if end-date
+ (format #f "~a - ~a"
+ (date->string start-date "~b ~e ~Y")
+ (date->string end-date "~b ~e ~Y"))
+ (format #f "~a - Present" (date->string start-date "~b ~e ~Y"))))
(td (p ,@description)))))
-(define (project-section name projects)
- `(section
- (h4 ,name)
- (table
+(define* (project-section title format items #:key subtitle folded)
+ #<(section
+ (h4 ,title)
+ ,(when subtitle `(p ,subtitle))
+ (table (@ (class "project-section"))
(tbody
- ,@(map (lambda (args) (apply project args)) projects)))))
+ ,@(map (lambda (args) (apply format args)) items)))))
(theme
#:title "About"
@@ -102,7 +246,7 @@ unfortunate, as I no longer use Arch Linux."))))
(ul (@ (class "horizontal-list"))
(li "Email: " (strong "zerodaysfordays at ‌​‌‌‌​‌‌‍‌​‌‌​​​​‍‌​‌‌​​​‌‍‌‌​‌‌​​​‍‌​‌​‌​‌‌‍‌‌​‌‌‌‌‌‍‌​‌‌‌​​‌‍‌​‌​‌​‌​‍‌​‌‌‌‌​​‍‌​‌‌​‌​​‍‌​‌‌​‌‌​‍‌​‌‌​​​‌‍‌​‌‌‌​​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​sdf.org"))
(li "XMPP: " (strong "jakob at ‌​‌‌‌​‌‌‍‌​‌‌​​​​‍‌​‌‌​​​‌‍‌‌​‌‌​​​‍‌​‌​‌​‌‌‍‌‌​‌‌‌‌‌‍‌​‌‌‌​​‌‍‌​‌​‌​‌​‍‌​‌‌‌‌​​‍‌​‌‌​‌​​‍‌​‌‌​‌‌​‍‌​‌‌​​​‌‍‌​‌‌‌​​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​xmpp.is"))
- (li "IRC: " (strong "tsarfox on freenode.net.")))
+ (li "IRC: " (strong "tsarfox on irc.libera.chat.")))
(ul (@ (class "horizontal-list"))
(li "GPG: " ,(hyperlink "/static/gpg.txt" "6581 A4FC 404F 6434 AEA3 008C 45ED 4DC3 05BA DA33")))
(ul (@ (class "horizontal-list"))
@@ -113,31 +257,44 @@ unfortunate, as I no longer use Arch Linux."))))
(li ,(hyperlink "http://zerodaysfordays.sdf.org/" "sdf"))
(li ,(hyperlink "https://lobste.rs/u/jakob" "lobste.rs")))
(main (@ (class "overline"))
- (p "My name's Jakob. I'm a self-taught free software hacker currently
-studying computer science and mathematics at the University of Massachusetts
-Amherst. I'm into functional programming, computer security, permaculture,
-cooking, punk rock, and lifting weights.")
- (p "I'm still in the process of putting things together, so this page is a bit empty.")
+ (p "My name's Jakob, and I'm a self-taught "
+ ,(hyperlink "https://www.gnu.org/philosophy/free-sw.html" "free software")
+ ,(hyperlink "https://en.wikipedia.org/wiki/Hacker_culture#Definition" " hacker")
+ ". I'm into functional programming, computer security, permaculture, and lifting
+weights.")
+ (p "That's the short version. I have a longer biography available " ,(hyperlink "/pages/about-complete.html" "here") ".")
(p (b "N.B. ")
"if you have sent an email to an address of mine
ending in 'sdf.lonestar.org' between January 2nd, 2020 and now, I have not
received it. SDF has discontinued mail service on that domain. As such, "
- ,(hyperlink "https://paste.sr.ht/%7Ejakob/18c048600c26d125d6d743e6d5b44db852573242" "I have a new PGP key."))
- ;; (p "I am paranoid about malicious web spiders indexing my resume, so if
-;; you are looking for that sort of thing, replace 'pages/about.html' with 'files
-;; forward slash resume dot P​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​ D‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​ F' in the URL bar.")
- ;; (p "If you used that god-awful LinkedIn")
- )
+ ,(hyperlink "https://paste.sr.ht/%7Ejakob/18c048600c26d125d6d743e6d5b44db852573242" "I have a new PGP key.")))
(h3 "Site Map")
(nav (@ (id "site-map"))
(section (h4 ,(hyperlink "/blogroll" "Blogroll"))
(p "A noncomprehensive list of the blogs I follow."))
(section (h4 ,(hyperlink "/bookmark" "Bookmarks"))
(p "Collection of some things that I especially enjoyed reading."))
- (section (h4 ,(hyperlink "/outbox" "Webmention Outbox"))
- (p "List of all the Webmention replies I've sent. Probably uninteresting to most.")))
+ ;; (section (h4 ,(hyperlink "/outbox" "Webmention Outbox"))
+ ;; (p "List of all the Webmention replies I've sent. Probably uninteresting to most."))
+ )
(h3 "Projects")
- ,(project-section "Software" %software-projects)
- ,(project-section "Emacs" %emacs-projects)
- ,(project-section "Packaging" %packaging-projects)
- ,(project-section "Other Contributions" %software-contributions)))
+ ,(project-section
+ "Software"
+ project
+ %software-projects)
+ ,(project-section
+ "Other Contributions"
+ project
+ %software-contributions
+ #:subtitle
+ "There are a few non-trivial contributions I've made to various free software
+projects, which I enumerate here. I take pride in giving back code.")
+ ,(project-section
+ "Software (Abandoned)"
+ project
+ %abandoned-software-projects
+ #:subtitle
+ "The unfortunate reality of hobbyist programming is that projects to be
+abandoned once that coding itch is satisfied. That's true of many of my
+projects."
+ #:folded #t)))
diff --git a/haunt/static/css/style.css b/haunt/static/css/style.css
index a198a89..145c315 100644
--- a/haunt/static/css/style.css
+++ b/haunt/static/css/style.css
@@ -258,19 +258,6 @@ tr:nth-child(even) {
background-color: #f2f2f2;
}
-
-td:nth-child(1) {
- width: 20%;
-}
-
-td:nth-child(2) {
- width: 10%;
-}
-
-td:nth-child(3) {
- width: 70%;
-}
-
/* Buttons. */
button {
@@ -314,3 +301,66 @@ button {
.spoiler:hover {
background-color: #f6f5f4;
}
+
+/* Styles specific to the "about" page. */
+
+.project-section td:nth-child(1) {
+ width: 15%;
+}
+
+.project-section td:nth-child(2) {
+ width: 60px;
+}
+
+.project-section td:nth-child(3) {
+ width: 80px;
+}
+
+.project-section td:nth-child(4) {
+ width: 15%;
+}
+
+.lang-c {
+ background-color: #555555;
+ color: #fff;
+}
+
+.lang-cpp {
+ background-color: #f34b7d;
+ color: #fff;
+}
+
+.lang-python {
+ background-color: #3572a5;
+ color: #ffdb4e;
+}
+
+.lang-rust {
+ background-color: #dea584;
+ color: #fff;
+}
+
+.lang-kotlin {
+ background-color: #f89917;
+ color: #fff;
+}
+
+.lang-fennel {
+ background-color: #2ca02c;
+ color: #fff;
+}
+
+.lang-elisp {
+ background-color: #c065db;
+ color: #fff;
+}
+
+.lang-scheme {
+ background-color: #1e4aec;
+ color: #fff;
+}
+
+.lang-ebuild {
+ background-color: #4d4270;
+ color: #fff;
+}