(load "~/quicklisp/setup.lisp")
(ql:quickload '(:hunchentoot :jdhtml2 :jdfiles :jdcss :jdstrings :auto-index))
(defpackage :jordandashel.com
(:use :cl :hunchentoot :jdhtml2 :jdfiles :jdcss
:auto-index :jdstrings))
(in-package :jordandashel.com)
(defun register-static-file (webpath filename)
(create-regex-dispatcher
webpath
#'(lambda ()
(html
(body
(pre
(get-text-in-file filename)))))))
(defun source-code ()
(html (body (pre (code :class "lisp"
(get-text-in-file "~/common-lisp/jordandashel.com/home.lisp"))))))
(defun source-listings ()
(html
(head
(title "source listings")
(css-safe-defaults)
(viewport)
(css
'(a ((font-size 1.5em)
(color darkgreen)))
'(body ((background-color lemonchiffon)))
'(p ((max-width 100%)))
'(".item"
((border-style solid)
(background-color lightblue)
(display inline-block)
(padding 10px)
(padding-bottom 20px)
(margin-top 15px)
(width 70%))
)))
(body (h1 "source listings"))
(div :class "item"
(p "i did some of the 2025 Advent of Code. i made it to day 8 before falling behind"
"and not catching up again, but here are my 8 solutions:")
(a :href "/aoc2025" " AoC 2025")
(p "please note that this is not my best or most readable code, just that which "
"i hacked together in order to solve the problem of the day :)"))
(div :class "item"
(p "here is an emacs extension i made some time ago. "
"i use it to organize large photo dumps."
"i use it often, though it has some rough edges."
"it's called \"photogal\", which stands for photo Grouper And Labeler."
)
(a :href "/photogal.el" " photogal")
(p "it should run alright if you load it into a running emacs session and "
"execute M-x photogal
")
(p "it will move files if you ask it to, so have backups"
"and be warned :)"))
(div :class "item"
(p "when i was working at new york public radio, we had a growing microservices-style architecture."
"it was largely supported by a long-running nginx reverse proxy which had picked up a lot"
"of cruft over the years. i was charged with investigating some network routing issues."
"the whole thing was very difficult to debug, so i wrote a network test harness"
"that allowed me to mock out all the microservices and carefully debug the nginx system "
"under test.")
(a :href "https://github.com/nypublicradio/unettest" " unettest")
(p "this helped me to solve one of the most challenging debugging tasks of my career."
"ultimately, what was going on is that there was one javascript service which was generating"
"error pages with 404 messages. those pages were bubbled up through other javascript libraries,"
"one of which changed the HTTP status code to a success code 200 while still displaying "
"the correct 404 error visually in the html, effectively lying about the state of things."
"this caused the nginx system to fail to identify 404 pages since the status code was"
"being rudely, silently, and incorrectly modified between network handoffs."))
))
(defun aoc2025 ()
(html
(head
(script (format
nil "~{~a~}~%"
(loop for x from 1 to 8
collecting
(format
nil "
function showAocCode~a() {
document.getElementById(\"code-box\").innerHTML = ~{\"~a\" + \"\\n\" +~} \"\";
document.getElementById(\"aoc-link\").innerHTML = \"original instructions: https://adventofcode.com/2025/day/~a \";
}"
x
(mapcar #'escape-for-html
(get-lines-in-file
(cat "~/common-lisp/jordandashel.com/aoc2025/"
(format nil "day~a.lisp" x))))
x x))))
(css-safe-defaults)
(css
'("body" ((background-color lemonchiffon)
(padding-left 5%)
(padding-right 5%)))
'("h1" ((padding-left 20%)
(margin-bottom 5px)))
'("#top-part > h2" ((text-align center)
(margin-top 5px)
(margin-bottom 5px)))
'("#top-part" ((padding-bottom 25px)))
'("#aoc-link"
((padding-bottom 15px)))
'("#days" ((display grid)
(grid-template-columns "1fr 1fr 1fr 1fr")
(margin-bottom 20px)
(gap 10px)))
'(".day"
((background-color lightblue)
(padding-left 15px)
(border-style solid))))
(body
(div :id "top-part"
(h1 "advent of code 2025")
(h2 "by jwd")
(h2 "in common lisp"))
(div :id "days"
(loop for x from 1 to 8 collecting (div :class "day"
:onclick (format nil "showAocCode~a();" x)
(h2 (format nil "day ~a" x)))))
(div :id "aoc-link" "")
(code (pre :id "code-box" ""))
))))
(defun css-for-leftcol-item (element bg-color txt-color indent?)
`(,element
((background-color ,bg-color)
(color ,txt-color)
(padding 5%)
(margin-top 5%)
(min-width 60%)
(if indent?
(margin-left 15%)
(margin-left 5%))
(font-family sans-serif)
(display inline-block)
(border-style solid)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)))
)
(defun home ()
(html
(head
(title "jordandashel.com")
(viewport)
(css
'("h1"
((color crimson)
(text-shadow "2px 2px 0px #000000")
(font-size 3em)
(margin-bottom 14px)
(font-family sans-serif)))
'("body"
((background-color lemonchiffon)
(margin-bottom 65px)))
'("#grid"
((display grid)
(grid-template-columns "1fr 1fr")))
'("#main"
((background-color coral)
(display inline-block)
(border-style solid)
(border-color indigo)
(font-size 0.7em)
(padding-right 5%)))
(css-for-leftcol-item "#bike" "coral" "black" 'nil)
'("#ops"
((background-color dodgerblue)
(color white)
(padding 5%)
(margin 5%)
(min-width 60%)
(margin-left 15%)
(font-family sans-serif)
(display inline-block)
(border-style solid)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)))
'("#code"
((background-color darkgreen)
(color white)
(padding 5%)
(min-width 60%)
(font-family sans-serif)
(display inline-block)
(border-style solid)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)))
'("#resume"
((background-color purple)
(color white)
(padding 5%)
(min-width 60%)
(font-family sans-serif)
(display inline-block)
(border-style solid)
(margin 5%)
(margin-left 15%)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)))
'("#vim"
((background-color palevioletred)
(color white)
(padding 5%)
(min-width 60%)
(font-family sans-serif)
(display inline-block)
(border-style solid)
(margin-bottom 5%)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)
(margin-top 0%)))
'("#sicp"
((background-color yellow)
(color black)
(padding 5%)
(min-width 60%)
(font-family sans-serif)
(display inline-block)
(border-style solid)
(margin 5%)
(margin-left 15%)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)
(margin-top 0%)))
'("#art"
((background-color cornflowerblue)
(color white)
(padding 5%)
(min-width 60%)
(font-family sans-serif)
(display inline-block)
(border-style solid)
(margin-bottom 5%)
(border-color indigo)
(font-size 0.7em)
(padding-top 0%)
(margin-top 0%)))
'("#ops > a,a:active, #code > a,a:active, #resume > a,a:active, #vim > a,a:active, #art > a,a:active"
((color gold)))
'("img"
((max-width 80%)
(max-height 400px)
(display block)
(margin-left 5%)
(margin-right 5%)
(margin-bottom 5%)
(border-style ridge)
(border-width 6.5px)))
'("#right"
((padding-top 50p)))
'("li"
((font-size 1em)))
'("ul"
((padding-left 12%)))
'("a,a:active"
((text-decoration none)
(color darkgreen)
(font-family sans-serif)
(font-size 1.8em)))
'("#left")
'("#footer"
((position fixed)
(left "0")
(bottom "0")
(width 100%)
(background-color olive)
(color white)
(font-size 1em)
(font-family sans-serif)))
'(".portrait"
((margin-left 10%)))
'("#footer > p > a"
((color pink)))
`("@media screen and (max-width: 768px)"
,(inner-css
'("h1" ((font-size 2em)))
'("h2" ((font-size 1.2em)))
'("a,a:active" ((font-size 1.0em)))))
`("@media screen and (min-width: 950px)"
,(inner-css
'("body" ((max-width 900px)
(margin-left 25%)))))))
(body
(h1 "the website of jordan dashel .com")
(div :id "grid"
(div :id "left"
(p "i work with computers and music and various other things")
(h2 "various other things:")
(div :id "bike"
(h2 "i rode my bicycle from sea to nyc.")
(p "in 2018. this is how i moved cities and coasts")
(a :href "http://acrossthecountryin90days.com/"
" across the country in 90 days" ))
(div :id "ops"
(h2 "here's how i operate my code:")
(a :href "/psyduck" " psyduck writeup" ))
(div :id "code"
(h2 "here's some code i've written:")
(p "i've got loads more, but this is some of the stuff i like.")
(a :href "/source-listings" " source listings"))
(div :id "resume"
(h2 "this is my sre/software dev resume.")
(p "i've been doing this stuff professionally since 2015!")
(a :href "/resume.txt" " resume"))
(div :id "vim"
(h2 "my reference guide for the vi language")
(p "very terse. but helpful at a glance once the system is understood.")
(a :href "/vim-guide.txt" " vi(m) ref"))
(div :id "sicp"
(h2 "i <3 sicp")
(p "i read and watched all the SICP stuff. here are my notes.")
(a :href "http://jordandashel.com/sicp"
" structure and interpretation of computer programs" ))
(div :id "art"
(h2 "some of my visual art can be seen here (nsfw)")
(p "i love to paint and draw! note: some of these images contain stylized nudity.")
(a :href "http://safesnax.faith"
" safe snax" ))
)
(div :id "right"
(img :class "portrait" "/tree.jpg")
(img "/dc.jpeg")
(img :class "portrait" "/keys.jpg")))
(div :id "footer"
(p " view the "
(a :href "/home.lisp"
"source code")
" for this web page")))))
(defun psyduck ()
(html
(head
(title "jordandashel.com")
(viewport)
(css
'("h1"
((color orchid)
(text-shadow "1px 1px 0px #000000")
(font-size 3em)
(margin-bottom 14px)
(font-family sans-serif)))
'("#main-screenshot, #jorp, p"
((max-width 70%)))
'("body"
((padding-left 20%)
(background-color lemonchiffon)
(padding-bottom 10%)))
'(a
((text-decoration none)
(color forestgreen)))
`("@media screen and (max-width: 768px)"
,(inner-css
'("h1" ((font-size 2em)))
'("a,a:active" ((font-size 1.0em)))
'("#main-screenshot" ((max-width 90%)))
'("body" ((background-color green)
(padding-left 5%)
(color white)))))))
(body
(h1 "kodakku (psyduck)")
(p "i have a little computer in the corner of my apartment.")
(p "it has a figurine of a body-builder type psyduck"
" (the gen 1 pokémon) on top of it.")
(p "it's where i run the cicd etc software i've written... "
"i named the software system after the pokémon. "
"this is where i run the majority of administrative tasks for the systems i've written.")
(p "it's also where i host my own local git server")
(p "kodakku often acts as the front-end interface to the git server running on the device")
(p "here's a screenshot:")
(a :href "/kodakku.png"
(img :id "main-screenshot" "/kodakku.png"))
(p "the main boxes in the middle link to some of my most commonly-referenced and used repos,"
" from the git server hosted locally on the same device.")
(p "this is what it looks like when i select one of those projects:")
(a :href "/jorp.png"
(img :id "jorp" "/jorp.png"))
(p "i use a lisp-implemented auto-indexer i wrote to create an interactive "
"file server for the files i wish"
" to display. this is heavily influenced by nginx's autoindex functionality. selecting a"
" directory (on the center left) will open a new page with its contents. selecting a file"
" (on the right) will simply display the raw text of the file in the browser.")
(p "(on the far left) are other features of this build server system. many of these items are under"
" heavy active development as the system (kodakku) becomes more mature. a lot of that"
" maturity is discovered by using it to manage other projects. the projects start out"
" with their own quirky requirements, but over time, by babysitting the projects and "
"watching them grow, i am able to abstract those things away and make the system more flexible"
"and powerful.")
(p "two of the oldest and more mature (while also being more primitive) systems on the far left"
" there are those two with unobvious names:")
(ul
(li (a :href "/howl.html" "howl") " is my long-running file etc. server")
(li (a :href "/ooo.html" "ooo") " is my newer \"inspiration system\"")))))
(defun howl ()
(html
(head
(css-safe-defaults)
(viewport)
(css
'("body"
((background-color lightgoldenrodyellow)))
'("#ginsberg"
((background-color hotpink)
(border-style solid)
(width 30%)
(padding-left 2%)
(max-height 100%)
(line-height 2.1em)
(font-family sans-serif)
(display inline-block)))
'("#hh"
((border-style solid)))
'("#side-by-side > img"
((max-width 30%)
(max-height 300px)))))
(body
(h1 "howl")
(p "i've maintained this server for years. it looks like this:")
(a :href "/howl.png"
(img "/howl.png"))
(p "it contains a bunch of files i use on a day-to-day basis, including music"
"and reference documents as well as episodes of adventure time.")
(p "it is named after both miyazaki/jones's howl's moving castle as well as the"
" allen ginsberg poem, \"howl\".")
(div :id "side-by-side"
:style "display: flex; gap: 10px;"
(a :href "/howl.txt"
(div :id "ginsberg"
(p (strong "i saw the best minds of my generation destroyed by madness, starving hysterical naked"))))
(img :id "hh" "/howl_himself.jpg")))))
(defun ooo ()
(html
(head
(css-safe-defaults)
(viewport)
(css '("body" ((background-color lightgoldenrodyellow)))))
(body
(h1 "ooo")
(click-img "/ooo.png")
(p "this is a modulating system of links and prompts. each box and image "
"shuffles randomly on programmed time intervals.")
(p "it's hosted on my main daily-use desktop (called ooo, like in adventure time) so i often"
" access it via localhost,"
"although sometimes i use it from a remote device, such as when i want to view something"
"on the ipad.")
(p :style "margin-bottom: 2px;"
"here's an example configuration for what's visible above:")
(code
(pre :style "margin-top: 2px;"
"
(euro-unit (time-chunked-random-unit #'jordyn-daily-time-chunk))
(tune (time-chunked-random-tune #'jordyn-4hr-time-chunk))
(songbook-standard (time-chunked-random-standard #'jordyn-weekly-time-chunk))
(synth-etc (time-chunked-random-synthetc #'jordyn-3day-time-chunk))
(daily-image (time-chunked-random-image #'jordyn-daily-time-chunk))
(hourly-image (time-chunked-random-image #'jordyn-1hr-time-chunk))"))
(p "this keeps things changing throughout the day and across the days. it makes it fun to"
"check back regularly, especially if i seek inspiration. the varying time chunks allow for"
"something ineffable to be considered in the passing moment and across stretches of days at a time.")
(p :style "margin-bottom: 2px;"
" the jazz standard is a fun one:")
(p :style "margin-top: 2px;"
"using my custom lisp-implemented lilypad-based music engraver, i am able to create and read"
"music notation in order to study and make recordings in C (for flute, piano, guitar, etc.) "
"as well as Eb (alto sax) and Bb (clarinet) without needing to transpose by sight "
"from the real book"))))
(defun get-webpages ()
(append
(auto-index-routes "~/common-lisp/jordandashel.com/images/")
(list
(create-regex-dispatcher "^/home.lisp$" 'source-code)
(create-regex-dispatcher "^/source-listings$" 'source-listings)
(create-regex-dispatcher "^/aoc2025$" 'aoc2025)
(create-regex-dispatcher "^/$" 'home)
(create-regex-dispatcher "^/psyduck$" 'psyduck)
(create-regex-dispatcher "^/howl.html$" 'howl)
(create-regex-dispatcher "^/ooo.html$" 'ooo)
(register-static-file "^/photogal.el$" "~/common-lisp/jordandashel.com/photogal.el")
(register-static-file "^/resume.txt$" "~/common-lisp/jordandashel.com/resume.txt")
(register-static-file "^/vim-guide.txt$" "~/common-lisp/jordandashel.com/vim-guide.txt")
(register-static-file "^/howl.txt$" "~/common-lisp/jordandashel.com/howl.txt")
)))
(progn
(defvar *acceptor* nil)
(defun stop-server ()
(when *acceptor*
(hunchentoot:stop *acceptor*)))
(defun start-server ()
(stop-server)
(hunchentoot:start (setf *acceptor*
(make-instance 'hunchentoot:easy-acceptor
:port 7777))))
(start-server)
(setf hunchentoot:*dispatch-table* (get-webpages))
(do ()
(nil)
(sleep 1))
nil)