author | Alan Dipert
<alan@dipert.org> 2025-10-08 04:24:13 UTC |
committer | Alan Dipert
<alan@dipert.org> 2025-10-08 04:24:13 UTC |
parent | 49ccd6c41a7100705bc8577f95f498e8ae1d80a8 |
.gitignore | +2 | -0 |
Makefile | +82 | -10 |
README.md | +23 | -0 |
md_export/AsyncAwaitGotchas.md | +32 | -0 |
md_export/CoffeeTime.md | +27 | -0 |
md_export/CoffeeTime/coffee_float_right_200px.jpg | +0 | -0 |
md_export/ConsultingPractice.md | +15 | -0 |
md_export/FairDivision.md | +41 | -0 |
md_export/GitOnSharedHost.md | +20 | -0 |
md_export/Home.md | +39 | -0 |
md_export/Home/headshot_2018_float_right_200px.jpg | +0 | -0 |
md_export/HomePhotos.md | +34 | -0 |
md_export/HomePhotos/Dockerfile | +36 | -0 |
md_export/HomePhotos/photoprism.png | +0 | -0 |
md_export/Lisp.md | +9 | -0 |
md_export/Lisp/CommonLisp.md | +10 | -0 |
md_export/Lisp/CommonLispIteration.md | +129 | -0 |
md_export/Lisp/GherkinHistory.md | +85 | -0 |
md_export/Lisp/GherkinHistory/IMG_2485.JPG | +0 | -0 |
md_export/Lisp/GherkinHistory/alan_wearing_gherkin_shirt.jpg | +0 | -0 |
md_export/PersonalBackground.md | +3 | -0 |
md_export/RandallRDipert.md | +10 | -0 |
md_export/TechSolutions.md | +29 | -0 |
md_export/TechWorks.md | +40 | -0 |
md_export/TechWorks/2015-04-20_ClojureWestBoot.pdf | +0 | -0 |
md_export/TechWorks/2020-01-28-RStudio-Conf-Integration-Testing-ePoster.pdf | +0 | -0 |
md_export/TechWorks/Dipert-FRP_in_ClojureScript_with_Javelin.pdf | +0 | -0 |
md_export/TechWorks/Dipert-ProgrammingWithValues.pdf | +0 | -0 |
md_export/TechWorks/jacl-demo-els-2020.pdf | +0 | -0 |
md_export/WellReadUndergrad.md | +35 | -0 |
md_export/WellReadUndergrad/phil-lt5.doc | +0 | -0 |
md_export/WellReadUndergrad/phil-lt5.docx | +0 | -0 |
tools/mdlink2html.awk | +47 | -0 |
tpl/foot.html | +8 | -0 |
tpl/head.html | +22 | -0 |
tpl/style.css | +77 | -0 |
diff --git a/.gitignore b/.gitignore index e1f60ea..61351e0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ auto-save-list tramp .\#* + +/out/ diff --git a/Makefile b/Makefile index 367edb0..a64d929 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,86 @@ -.PHONY: deploy +.PHONY: all assets clean deploy help tree check-git-clean -PAGES=$(shell find . -maxdepth 1 -name '*.md' -exec basename '{}' ';') -HTML=$(PAGES:%.md=OUT/%.html) +SRC := md_export +OUT := out +HEAD := tpl/head.html +FOOT := tpl/foot.html +CSS := tpl/style.css +MD2HTML ?= /usr/bin/cmark-gfm +CMARK_FLAGS := --to html --extension table --validate-utf8 +DEPLOY_HOST ?= arsien23i2@dreamhost:tailrecursion.com/~alan -all: $(HTML) +MD_FILES := $(shell find $(SRC) -type f -name '*.md' | LC_ALL=C sort) +HTML := $(patsubst $(SRC)/%.md,$(OUT)/%.html,$(MD_FILES)) -OUT/%.html: %.md template.html - pandoc --standalone --template=template.html --from=gfm+wikilinks_title_after_pipe --metadata title=$(basename $<) --metadata date="$(shell date -d @$(shell stat -c %Y $<))" --metadata date-meta=$(shell date -d @$(shell stat -c %Y $<) +%Y-%m-%d) --lua-filter=links-to-html.lua -o $@ $< - # Copy option resource directory for page (images, attachments, etc) - rsync --ignore-missing-args --delete -a $(basename $@) OUT +all: check-git-clean $(OUT)/style.css $(HTML) -deploy: - rsync -a OUT/ arsien23i2@dreamhost:tailrecursion.com/~alan +$(OUT)/style.css: $(CSS) + @mkdir -p $(OUT) + @cp $(CSS) $@ + +$(OUT): + @mkdir -p $(OUT) + +$(OUT)/%.html: $(SRC)/%.md $(HEAD) $(FOOT) tools/mdlink2html.awk | $(OUT) + @mkdir -p $(@D) + @awk -f tools/mdlink2html.awk $< > $@.rewritten.md + @if [ ! -x $(MD2HTML) ]; then \ + echo "Missing $(MD2HTML). Build it with:"; \ + echo " git clone https://github.com/github/cmark-gfm vendor/cmark-gfm"; \ + echo " cmake -S vendor/cmark-gfm -B vendor/cmark-gfm/build"; \ + echo " cmake --build vendor/cmark-gfm/build"; \ + echo " cp vendor/cmark-gfm/build/src/cmark-gfm bin/"; \ + echo "Then rerun make with MD2HTML=bin/cmark-gfm"; \ + exit 1; \ + fi + @$(MD2HTML) $(CMARK_FLAGS) $@.rewritten.md > $@.body.html + @css_prefix="$$(dirname "$@" | sed -e 's#^$(OUT)##' -e 's#^/##' -e 's#[^/][^/]*#../#g')"; \ + build_user=$$(whoami); \ + build_host=$$(hostname); \ + day=$$(date '+%-d'); \ + case $$day in 11|12|13) suffix=th ;; *1) suffix=st ;; *2) suffix=nd ;; *3) suffix=rd ;; *) suffix=th ;; esac; \ + dow=$$(date '+%A'); \ + month=$$(date '+%B'); \ + year=$$(date '+%Y'); \ + time=$$(date '+%-I:%M%p %Z'); \ + git_sha=$$(git rev-parse --short HEAD); \ + build_info="Built by $$build_user@$$build_host on $$dow, $$month $$day$$suffix $$year at $$time (git $$git_sha)"; \ + sed -e "s|@CSS@|$${css_prefix}|g" -e "s|@BUILDINFO@|$${build_info}|g" $(HEAD) > $@.head.html; \ + sed -e "s|@CSS@|$${css_prefix}|g" -e "s|@BUILDINFO@|$${build_info}|g" $(FOOT) > $@.foot.html; \ + cat $@.head.html $@.body.html $@.foot.html > $@; \ + rm -f $@.head.html $@.foot.html + @rm -f $@.rewritten.md $@.body.html + +assets: check-git-clean + @mkdir -p $(OUT) + @rsync -a --include='*/' --exclude='*.md' --exclude='*.MD' --prune-empty-dirs $(SRC)/ $(OUT)/ + +deploy: assets all + @if [ -z "$(DEPLOY_HOST)" ]; then \ + echo "DEPLOY_HOST is not set"; \ + exit 1; \ + fi + rsync -a $(OUT)/ $(DEPLOY_HOST) + +tree: + @printf 'Markdown sources: ' && find $(SRC) -type f -name '*.md' | wc -l + @printf 'HTML outputs: ' && if [ -d $(OUT) ]; then find $(OUT) -type f -name '*.html' | wc -l; else echo 0; fi + +clean: + rm -rf $(OUT) + +help: + @echo 'Static site generator targets:' + @echo ' make assets - copy non-Markdown assets into $(OUT)/' + @echo ' make - build HTML pages (same as make all)' + @echo ' make deploy - rsync $(OUT)/ to $$DEPLOY_HOST' + @echo ' make tree - count source and generated files' + @echo ' make clean - remove $(OUT)/' + @echo ' (requires clean git worktree before building)' + +check-git-clean: + @if [ -n "$$(git status --porcelain)" ]; then \ + echo 'Refusing to build: git worktree has uncommitted changes.'; \ + git status --short; \ + exit 1; \ + fi diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d4fc09 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Homepage static site generator + +This converts Markdown from `md_export/` to HTML in `out/` and can deploy the result to your shared host. + +## Usage +make assets && make +xdg-open out/index.html # or open on macOS + +> Note: builds require a clean git worktree. Commit or stash changes before running make. + +## Deploy +make deploy # uses rsync to upload to your shared host defined in DEPLOY_HOST + +## Build cmark + +This project defaults to `/usr/bin/cmark-gfm`. If it is missing on your system you can build a local copy: + +git clone https://github.com/github/cmark-gfm vendor/cmark-gfm +cmake -S vendor/cmark-gfm -B vendor/cmark-gfm/build +cmake --build vendor/cmark-gfm/build +cp vendor/cmark-gfm/build/src/cmark-gfm bin/ + +Then rerun make with `MD2HTML=bin/cmark-gfm`. diff --git a/md_export/AsyncAwaitGotchas.md b/md_export/AsyncAwaitGotchas.md new file mode 100644 index 0000000..c5f01c5 --- /dev/null +++ b/md_export/AsyncAwaitGotchas.md @@ -0,0 +1,32 @@ +# AsyncAwaitGotchas +Created Thursday 24 June 2021 + +Recent versions of JavaScript include support for [async functions and the await keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). Below, I enumerate a few edge cases of ``async``/``await`` in Google Chrome that produce obscure errors, and their solutions. I'm using Chrome 91.0.4472.114. I don't know if these are known bugs, but they were confusing to me. I'm grateful to anyone with the time and interest to officially catalog and/or fix them. + +Uncaught SyntaxError: missing ) after argument list +--------------------------------------------------- + +This one can come up when you use await in a function where it's not allowed. The following code doesn't work because neither the outer function nor inner arrow function were decorated with the ``async`` keyword. + + function foo(xs) { return xs.map(x => await x); } + VM856:1 Uncaught SyntaxError: missing ) after argument list + +You can still get the error even if the enclosing outer function is async: + + async function foo(xs) { return xs.map(x => await x); } + VM867:1 Uncaught SyntaxError: missing ) after argument list + +I can imagine how the compiler could make the inner async work, since the inner arrow function doesn't [escape](https://en.wikipedia.org/wiki/Escape_analysis) the outer function. I haven't looked at the specification, but I assume it's not supposed to work. It's OK with me that it doesn't work, because if it did, the rules about when ``async`` works would become more complicated. The error message could be better, though. + +Uncaught SyntaxError: Missing } in template expression +------------------------------------------------------ + +This one must be a consequence of the way [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) and the ``await`` keyword interact: + + function foo(x) { return `${await x}`; } + VM960:1 Uncaught SyntaxError: Missing } in template expression + +Contrary to the error message, the problem is unrelated to the template expression syntax. The problem is that the ``foo`` function needs to be ``async:`` + + async function foo(x) { return `${await x}`; } + diff --git a/md_export/CoffeeTime.md b/md_export/CoffeeTime.md new file mode 100644 index 0000000..3e5b2d0 --- /dev/null +++ b/md_export/CoffeeTime.md @@ -0,0 +1,27 @@ +# CoffeeTime +Created Monday 23 November 2020 + + + +Would you like to meet with me? Let's do it! I try to make time to reconnect with old friends and to make new ones. + + +* Send an e-mail to [alan@tailrecursion.com](mailto:alan@tailrecursion.com) with a times that would work for you, or a few other times that you're available. I'll try to make something work. I'm in the US Pacific time zone. +* Zoom and Google Meet are my go-to tools but I'm open to trying others. +* If we haven't met before, please suggest a discussion topic in your e-mail. + + +I'm open to discussing most subjects, but my own personal expertise and current interests include the following: + + +* Common Lisp +* Clojure +* Build tools and processes +* R and Shiny +* Compilers and interpreters +* Amateur radio +* JavaScript +* Drones +* Lawn care + + diff --git a/md_export/CoffeeTime/coffee_float_right_200px.jpg b/md_export/CoffeeTime/coffee_float_right_200px.jpg new file mode 100644 index 0000000..13d12be Binary files /dev/null and b/md_export/CoffeeTime/coffee_float_right_200px.jpg differ diff --git a/md_export/ConsultingPractice.md b/md_export/ConsultingPractice.md new file mode 100644 index 0000000..7468f8c --- /dev/null +++ b/md_export/ConsultingPractice.md @@ -0,0 +1,15 @@ +# ConsultingPractice +**As of November 2020 I'm booked and unavailable to start new projects, but please don't hesitate to e-mail me anyway at [alan@tailrecursion.com](mailto:alan@tailrecursion.com). I'll be happy to make your acquaintance and get back to you when I become available.** + +As of June 2020 I am an independent software consultant specializing in [Clojure](https://clojure.org/), [ClojureScript](https://clojurescript.org/), JavaScript, and web application design and architecture. I have over a decade of experience and have successfully built and operated applications in a wide variety of challenging technical and business environments. My practice is defined by the following mission statement: + + +1. **Deliver** reliable software solutions regularly and rapidly to my clients. +2. **Collaborate** whenever possible to avoid pitfalls and leverage existing expertise. +3. **Communicate** continuously to ensure solutions meet all expectations and requirements. +4. **Resolve**, immediately, any operational difficulties associated with delivered software. +5. **Improve** techniques and methodologies continuously as lessons are learned. + + +If you are interested in contracting my services and would like to discuss an engagement, please don't hesitate to send me an e-mail at [alan@tailrecursion.com](mailto:alan@tailrecursion.com). I look forward to hearing from you! + diff --git a/md_export/FairDivision.md b/md_export/FairDivision.md new file mode 100644 index 0000000..5443e87 --- /dev/null +++ b/md_export/FairDivision.md @@ -0,0 +1,41 @@ +# FairDivision +Created Monday 09 November 2020 + +I cut, you choose +----------------- + +The "[I cut, you choose](https://en.wikipedia.org/wiki/Divide_and_choose)" method of dividing something fairly between two people is well known. Given some divisible resource, like a pizza, two people may divide the resource using the following protocol: + + +1. One person is chosen at random to cut the pizza in two pieces. +2. The person who did not cut takes a piece. +3. The person who cut takes the remaining piece. + + +This protocol is easy to remember and to explain. It is also efficient in the sense that the minimal number of pieces — two — are created. + +If you haven't before, I encourage you to now take a moment to consider how a resource could be divided fairly between any number people, not just two. + +I thought about this recently myself when I needed to divide a large cookie between myself, my wife, and our 4-year-old daughter. I excused myself to think about how to proceed. When I returned, the cookie had been eaten! That's one protocol I *don't* recommend. + +The Fink protocol +----------------- + +Later (and after eating an entire large cookie without even telling my family about it) I sat down to research the problem. I consulted with my friend Micha Niskin and he suggested the following technique he had devised, which I discovered later is known as the [Fink protocol:](https://en.wikipedia.org/wiki/Fink_protocol) + + +1. If there are two people, perform "I cut, you choose". +2. If there are three people, two are chosen randomly. The two randomly chosen people perform "I cut, you choose". +3. The two people with a piece each cut their piece into thirds. +4. The third person without any pieces yet chooses one piece from each of the two with pieces. +5. All people now have two pieces each. +6. If a fourth person joins, each of the three with pieces cut each of their pieces in two. +7. The fourth person without any pieces yet chooses one piece from each of the three with pieces. +8. All people now have three pieces each. +9. ...and so on. + + +The biggest drawback of the Fink protocol is that each person ends up with n-1 pieces, where n is the number of people, instead of a single piece of size 1/n. On the other hand, like "I cut, you choose", this protocol is easy to remember, and is almost as easy to explain, even to children. + +There are actually many approaches to problem, all with various tradeoffs. I didn't find any of them nearly as easy to remember or explain (especially to *hungry* children!) as Fink, but if you want to do your own research, [Fair cake-cutting on Wikipedia](https://en.wikipedia.org/wiki/Fair_cake-cutting) is where I started. + diff --git a/md_export/GitOnSharedHost.md b/md_export/GitOnSharedHost.md new file mode 100644 index 0000000..b4e8bc2 --- /dev/null +++ b/md_export/GitOnSharedHost.md @@ -0,0 +1,20 @@ +# GitOnSharedHost +Created Friday 02 December 2022 + +Recently I set up read-only Git repository hosting on [Dreamhost](https://www.dreamhost.com/) for my project [JACL](https://tailrecursion.com/JACL). This was kind of tricky, so here are the steps: + + +1. In the Dreamhost control panel, [set up SSH for a user](https://help.dreamhost.com/hc/en-us/articles/216041267-SSH-overview). +2. Once you can log in with a password, you probably want to [set up key-based authentication](https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server). +3. On the remote host, ``cd`` into the directory corresponding to your hosted domain. +4. ``mkdir your-repo.git`` +5. ``cd your-repo.git`` +6. ``git init --bare`` +7. ``cp hooks/post-update.sample hooks/post-update`` +8. Back in your local repo, run a command like the following: ``git remote add origin ssh://user@northbend.dreamhost.com:/home/user/example.com/your-repo.git`` substituting ``user``, ``northbend.dreamhost.com``, and ``example.com`` with your particulars. +9. ``git push -u origin master`` +10. Now, you should be able to ``git push`` and anyone on the Internet should be able to ``git clone https://example.com/your-repo.git`` + + + + diff --git a/md_export/Home.md b/md_export/Home.md new file mode 100644 index 0000000..a2992e7 --- /dev/null +++ b/md_export/Home.md @@ -0,0 +1,39 @@ +# Alan's Homepage + + +Hello, and welcome to the personal [homepage](https://en.wikipedia.org/wiki/Home_page) and [wiki](https://en.wikipedia.org/wiki/Wiki) of Alan Dipert! + + +* [ConsultingPractice](./ConsultingPractice.md) is about the professional software engineering consulting services I provide. +* [PersonalBackground](./PersonalBackground.md) is about my personal history and interests. +* [TechWorks](./TechWorks.md) is a list of technical presentations, workshops, papers, and other works I've created or helped to create. + + +The best way to contact me is by email at [alan@tailrecursion.com](mailto:alan@tailrecursion.com). I also maintain a [CoffeeTime](./CoffeeTime.md) to meet with folks. In addition, you can find me on the follow social media websites: + + +* [Twitter](https://twitter.com/alandipert) is where I post infrequently, usually about technology. +* [GitHub](https://github.com/alandipert/) is where I typically collaborate on open source software and [star interesting projects](https://github.com/alandipert?tab=stars) I run across. +* [LinkedIn](https://www.linkedin.com/in/alandipert/) is where I maintain my work history and professional connections. +* [Hacker News](https://news.ycombinator.com/user?id=wooby) is where I occasionally submit links and engage The Internet in discussion. + + +Updates +------- +| Date | Note | +|:-----------|:-------------------------------------------------------------------------------------------------------------------------------------------| +| 2022-12-02 | Added [GitOnSharedHost](./GitOnSharedHost.md) to describe setting up a read-only Git repo on Dreamhost. | +| 2021-07-01 | Added [HomePhotos](./HomePhotos.md) to document family media archival strategy. | +| 2021-06-24 | Added [AsyncAwaitGotchas](./AsyncAwaitGotchas.md), about obscure async/await JavaScript errors in Google Chrome. | +| 2021-02-05 | Added SciCloj presentation comparing Common Lisp to Clojure to [TechWorks](./TechWorks.md). | +| 2020-12-31 | Added to [Lisp:CommonLispIteration](./Lisp/CommonLispIteration.md), added ClojureScript Podcast appearance to [TechWorks](./TechWorks.md). | +| 2020-12-15 | Added [TechSolutions](./TechSolutions.md) to record solutions to software problems and errors I encounter. | +| 2020-11-23 | Added [CoffeeTime](./CoffeeTime.md). | +| 2020-11-23 | Added [Lisp:CommonLispIteration](./Lisp/CommonLispIteration.md). | +| 2020-11-21 | Customized Zim export HTML/CSS template. | +| 2020-11-13 | Added [Lisp:GherkinHistory](./Lisp/GherkinHistory.md). | +| 2020-11-10 | Added three [Cognicast](https://www.cognitect.com/cognicast/) appearances to [TechWorks](./TechWorks.md). | +| 2020-11-09 | Added [FairDivision](./FairDivision.md). | +| 2020-11-02 | Deployed new [Zim](https://zim-wiki.org/)-based site and established redirects from previous URLs. | + + diff --git a/md_export/Home/headshot_2018_float_right_200px.jpg b/md_export/Home/headshot_2018_float_right_200px.jpg new file mode 100644 index 0000000..dc43b54 Binary files /dev/null and b/md_export/Home/headshot_2018_float_right_200px.jpg differ diff --git a/md_export/HomePhotos.md b/md_export/HomePhotos.md new file mode 100644 index 0000000..26ffb6f --- /dev/null +++ b/md_export/HomePhotos.md @@ -0,0 +1,34 @@ +# HomePhotos +Created Thursday 01 July 2021 + +Recently I migrated our family off of Amazon Prime Photos after many years of use. I found the cost to maintain videos prohibitive, and had also become increasingly concerned by how difficult getting things *out* of Prime Photos was becoming. Plus, like, privacy and stuff. + + + +My original plan was to develop my own minimal management software, so that I wouldn't be subject even to open source software churn. Since I plan on maintaining this photo archive for the rest of my life, I figured it made sense to double down on technique. After some prototyping I realized I'd bit off more than I could chew, despite the number of great libraries for working with media and metadata that there are. I was fortunate to then run across [PhotoPrism](https://photoprism.app/), which does what I'd hoped to do, and more, and seems to be very well designed. And, they're working on face recognition, which is the only thing I really miss from Prime Photos. + +I run PhotoPrism on Fedora on my old Lenovo T430s laptop with a 1TB SSD. I was able to import some 185gb of content - ~15,000 photos and ~300 videos - in about a day, with laptop fans blasting and all cores saturated. In addition, we're now running: + + +* [PhotoSync](https://www.photosync-app.com/home.html) on Android and iOS to sync photos from devices to PhotoPrism. +* Docker to run PhotoPrism in docker-compose, as a systemd unit ([tutorial](https://techoverflow.net/2020/10/24/create-a-systemd-service-for-your-docker-compose-project-in-10-seconds/)). +* [Tailscale VPN](https://tailscale.com/) so photos can be accessed and uploaded even while mobile. +* [Duplicity](http://duplicity.nongnu.org/) in cron (via [flock](https://linux.die.net/man/1/flock)) to back up regularly to AWS S3 Glacier Deep Archive. This is currently the cheapest way to store things in AWS long term. I started with [this tutorial](https://stuff.technology/making-offsite-backups-for-home-convenient-inexpensive-and-secure-4654680333e8) but ended up making my own Dockerfile and using a newer duplicity/requirements.txt: + * [Dockerfile](./HomePhotos/Dockerfile) + * [requirements.txt](https://gitlab.com/duplicity/duplicity/-/blob/d52fd888100b8fb105c696b38f2884c8173eb412/requirements.txt) + * I really like the look of [tarsnap](https://www.tarsnap.com/) but I find it a little too expensive for this use case. As far as I can tell, the killer feature it offers (beyond encryption) is incremental deletion. I hope to use it for system backups in the near future, though. I think it would also be good for storing recent security camera footage from [ZoneMinder](https://zoneminder.com/), once I get that set up. +* [healthchecks.io](https://healthchecks.io/) for heartbeats on the cron job. + + +Other options +------------- + +Getting this all going took a few hours and required a decent amount of Linux and Docker knowledge. For less effort, you might consider a [Synology NAS](https://www.synology.com/en-us). I've heard good things about Synology from various nerds I respect. Other options I'm aware of for running "home cloud" software on commodity hardware include [ownCloud](https://owncloud.com/) and [Unraid](https://unraid.net/). + +Future plans +------------ + +In the future, I look forward to working with PhotoPrism more, and maybe even getting involved with its development. I'm interested in adding OCR indexing and full text search to navigate the many documents I photograph with my phone. In my prototype I had some success with [Tesseract](https://github.com/nguyenq/tess4j) and [SQLite FTS 5](https://sqlite.org/fts5.html) for this purpose. I would also enjoy a more powerful textual search language. + +A local healthcheck service would be nice too. I'd like to see a [ESP8266](https://en.wikipedia.org/wiki/ESP8266) or something somewhere in my office with a green LED glowing to know everything is fine™. + diff --git a/md_export/HomePhotos/Dockerfile b/md_export/HomePhotos/Dockerfile new file mode 100644 index 0000000..d521eca --- /dev/null +++ b/md_export/HomePhotos/Dockerfile @@ -0,0 +1,36 @@ +FROM python:3-alpine + +ARG DUPLICITY_URL="https://launchpad.net/duplicity/0.8-series/0.8.20/+download/duplicity-0.8.20.tar.gz" + +ENV SRC='/mnt/backup/src' \ + MANPATH='MANPATH=/usr/local/share/man' \ + PAGER='less' + +COPY requirements.txt /tmp/ + +# Mixed Dev and Runtime dependencies +RUN apk add --no-cache \ + build-base \ + ca-certificates \ + gettext \ + libffi-dev \ + librsync-dev \ + gnupg \ + mandoc \ + openssl-dev \ + tzdata \ + musl-dev \ + python3-dev \ + libffi-dev \ + openssl-dev \ + libxml2-dev \ + libxslt-dev \ + cargo \ + && pip install -r /tmp/requirements.txt \ + $DUPLICITY_URL \ + && rm /tmp/requirements.txt + +# Cache and GPG key +VOLUME [ "/root" ] +WORKDIR /root +CMD ["duplicity"] diff --git a/md_export/HomePhotos/photoprism.png b/md_export/HomePhotos/photoprism.png new file mode 100644 index 0000000..dc2bed9 Binary files /dev/null and b/md_export/HomePhotos/photoprism.png differ diff --git a/md_export/Lisp.md b/md_export/Lisp.md new file mode 100644 index 0000000..5fbde47 --- /dev/null +++ b/md_export/Lisp.md @@ -0,0 +1,9 @@ +# Lisp +Created Thursday 12 November 2020 + +I have been interested in all things Lisp since around 2009, when I learned Clojure. + + +* [Lisp:GherkinHistory](./Lisp/GherkinHistory.md) provides context around an interpreter I wrote in 2013 that was extremely gratifying. + + diff --git a/md_export/Lisp/CommonLisp.md b/md_export/Lisp/CommonLisp.md new file mode 100644 index 0000000..178fa30 --- /dev/null +++ b/md_export/Lisp/CommonLisp.md @@ -0,0 +1,10 @@ +# CommonLisp +Created Friday 13 November 2020 + +I've been tinkering with Common Lisp since about 2010 but did not study it in earnest until around 2016. + + +* In 2020 I shared an implementation I've been working on, [JavaScript Assisted Common Lisp (JACL)](https://tailrecursion.com/JACL/). +* I wrote up a bunch of different ways to achieve [CommonLispIteration](./CommonLispIteration.md). + + diff --git a/md_export/Lisp/CommonLispIteration.md b/md_export/Lisp/CommonLispIteration.md new file mode 100644 index 0000000..70ab944 --- /dev/null +++ b/md_export/Lisp/CommonLispIteration.md @@ -0,0 +1,129 @@ +# Common Lisp iteration +Created Monday 23 November 2020 + +Each of the following definitions of a [factorial](https://en.wikipedia.org/wiki/Factorial) function demonstrate a way to [iterate](https://en.wikipedia.org/wiki/Iteration#Computing) in [Common Lisp](https://en.wikipedia.org/wiki/Common_Lisp), with brief notes. I hope that by demonstrating many different ways that the same thing can be written, you can develop a sense for the character of the constructs afforded by the language, and of the variety of possible styles. Common Lisp is famously syntactically extensible via [macros](https://en.wikipedia.org/wiki/Common_Lisp#Macros), so keep in mind that my examples are by no means the *only* ways to iterate. + +For further reading on the iteration and control structures of Common Lisp, I heartily recommend: + + +* [Chapter 7](http://www.gigamonkeys.com/book/macros-standard-control-constructs.html) and [Chapter 22](http://www.gigamonkeys.com/book/loop-for-black-belts.html) of [Practical Common Lisp](https://amzn.to/3nOWKa2) by Peter Siebel. +* A reasonably-priced used copy of [ANSI Common Lisp](https://amzn.to/2UUTfm3) by Paul Graham. + + +*Note: several of the examples return nonsensical results for negative inputs. The addition of ``(assert (not (minusp n)) ``or similar is a good idea, but I have omitted it here for clarity.* + +DOTIMES +------- + (defun factorial-dotimes (n &aux (prod 1)) + (dotimes (i n prod) + (setq prod (* prod (1+ i))))) + + +* [``&aux`` lambda list keyword](http://www.lispworks.com/documentation/HyperSpec/Body/03_dae.htm) names a local variable ``prod``. [``LET``](http://www.lispworks.com/documentation/HyperSpec/Body/s_let_l.htm) could also be used for this purpose, but at the cost of more indentation. +* [``DOTIMES``](http://www.lispworks.com/documentation/lw50/CLHS/Body/m_dotime.htm) binds ``i`` successively from 0 to 1-n and finally evaluates to ``prod``. + + +DO +-- + (defun factorial-do (n) + (do ((i 1 (1+ i)) + (prod 1 (* prod i))) + ((> i n) prod))) + + +* [``DO``](http://www.lispworks.com/documentation/lw50/CLHS/Body/m_do_do.htm) binds ``i`` to 1 and then to (1+ i) in subsequent iterations. ``prod`` is bound first to 1 and then to ``(* prod i)`` in subsequent iterations. +* When the test clause ``(> i n)`` becomes true, ``prod`` is returned. Contrast with the test clause of ``for`` loops in other languages, which terminate the loop when they become *false*. +* I like the way Paul Graham explains ``DO ``and`` DO*`` in [ANSI Common Lisp](https://amzn.to/2UUTfm3). + + +LOOP +---- + (defun factorial-loop (n) + (loop + for i from 1 to n + for prod = 1 then (* prod i) + finally (return prod))) + + +* ``i`` is bound from 1 to ``n`` inclusive. +* ``prod`` is bound to 1 and then ``(* prod i)`` in subsequent iterations in a manner similar to ``DO``. +* In the ``finally`` clause, ``prod`` is returned by [``RETURN``](http://www.lispworks.com/documentation/lw60/CLHS/Body/m_return.htm#return) once iteration is complete. The [``BLOCK``](http://www.lispworks.com/documentation/lw60/CLHS/Body/s_block.htm#block) named NIL established by ``LOOP`` is the point of return. +* [``LOOP``](http://www.lispworks.com/documentation/lw50/CLHS/Body/m_loop.htm) supports a comprehensive iteration and accumulation [DSL](https://en.wikipedia.org/wiki/Domain-specific_language). [Chapter 22](http://www.gigamonkeys.com/book/loop-for-black-belts.html) of [Practical Common Lisp](https://amzn.to/3nOWKa2) offers a great introduction. + + +The preceding example demonstrates the "extended" form of ``LOOP``. There's also "simple" form: + + (defun factorial-simple-loop (n &aux (i 0) (prod 1)) + (loop + (when (eql i n) + (return prod)) + (setq prod (* prod (incf i))))) + +Recursion +--------- + (defun factorial-recursive (n) + (if (zerop n) + 1 + (* n (factorial-recursive (1- n))))) + + +* ``FACTORIAL-RECURSIVE`` calls itself, but when ``n`` exceeds the maximum stack size supported by the implementation, an error is signaled. + + + (defun factorial-tail-recursive (n) + (labels ((recur (n prod) + (if (zerop n) + prod + (recur (1- n) (* n prod))))) + (recur n 1))) + + +* ``FACTORIAL-TAIL-RECURSIVE ``does not call itself directly. +* Instead, it defines with [``LABELS``](http://www.lispworks.com/documentation/HyperSpec/Body/s_flet_.htm) an internal and recursive helper function, ``recur``. +* recur [calls itself in tail position](https://en.wikipedia.org/wiki/Tail_call) and the stack never overflows in implementations that implement tail-call elimination. + + + (defun factorial-tail-recursive-opt (n &optional (prod 1)) + (if (zerop n) + prod + (factorial-tail-recursive-opt (1- n) (* n prod)))) + + + +* ``FACTORIAL-TAIL-RECURSIVE-OPT`` is also tail recursive, but uses the ``&OPTIONAL`` lambda list keyword to maintain ``prod`` across iterations. This approach has the downside of exposing ``prod`` as part of the public interface of the function. Arguably, ``prod`` is an implementation detail, best kept internal. + + +PROG +---- + (defun factorial-prog (n) + (prog ((i 0) (prod 1)) + begin + (when (eql i n) + (return prod)) + (setq prod (* prod (incf i))) + (go begin))) + + +* PROG supports both declaring local lexical variables (``i`` and ``prod``) and naming GO tags (``begin``). +* ``begin`` names a label within the *implicit ``TAGBODY``* enclosed by ``PROG`` that may be jumped to. +* [``WHEN``](http://www.lispworks.com/documentation/HyperSpec/Body/m_when_.htm) ``i`` is [``EQL``](http://www.lispworks.com/documentation/HyperSpec/Body/f_eql.htm) to ``n``, [``RETURN``](http://www.lispworks.com/documentation/lw60/CLHS/Body/s_ret_fr.htm) returns ``prod``. +* [``GO``](http://www.lispworks.com/documentation/HyperSpec/Body/s_go.htm) jumps to ``begin``. + + +TAGBODY +------- + (defun factorial-tagbody (n &aux (i 0) (prod 1)) + (tagbody + begin + (when (eql i n) + (return-from factorial-tagbody prod)) + (setq prod (* prod (incf i))) + (go begin))) + + +* [``TAGBODY``](http://www.lispworks.com/documentation/HyperSpec/Body/s_tagbod.htm) is the most general but also the lowest-level and most verbose iteration construct. +* [``&aux`` lambda list keyword](http://www.lispworks.com/documentation/HyperSpec/Body/03_dae.htm) names local variables ``i`` and ``prod``, initializing them to 0 and 1, respectively. +* [``WHEN``](http://www.lispworks.com/documentation/HyperSpec/Body/m_when_.htm) ``i`` is [``EQL``](http://www.lispworks.com/documentation/HyperSpec/Body/f_eql.htm) to ``n``, [``RETURN-FROM``](http://www.lispworks.com/documentation/lw60/CLHS/Body/s_ret_fr.htm) returns ``prod`` from the [``BLOCK``](http://www.lispworks.com/documentation/lw60/CLHS/Body/s_block.htm#block) named after the function by [``DEFUN``](http://www.lispworks.com/documentation/lw60/CLHS/Body/m_defun.htm). +* [``GO``](http://www.lispworks.com/documentation/HyperSpec/Body/s_go.htm) jumps to ``begin``. + + diff --git a/md_export/Lisp/GherkinHistory.md b/md_export/Lisp/GherkinHistory.md new file mode 100644 index 0000000..87f4f4a --- /dev/null +++ b/md_export/Lisp/GherkinHistory.md @@ -0,0 +1,85 @@ +# GherkinHistory +Created Thursday 12 November 2020 + +[Gherkin](https://github.com/alandipert/gherkin) is an interpreter I wrote in bash in 2013 for a Clojure-inspired dialect of [Lisp](../Lisp.md). Gherkin was the most sophisticated Lisp implementation I had attempted up to that point. I announced Gherkin during a [lightning talk at Clojure/conj 2013](https://www.youtube.com/watch?v=bmHTFo2Rf2w#t=28m55s). Working on and sharing Gherkin brought me great joy, and inspired others in ways that continue to inspire *me*. Gherkin is one of the most gratifying projects I've ever worked on, and the experience continues to pay dividends. + +So, you want to be a Lisp hacker... +----------------------------------- + +Before starting on Gherkin, I had long nursed an interest in Lisp implementation [wizardry](http://www.catb.org/jargon/html/H/heavy-wizardry.html). After learning Clojure around 2009, I began work at Relevance (now [Cognitect](https://www.cognitect.com/)) where I was presented with opportunities to make small contributions to Clojure itself. At Relevance, I had the great fortune of being a fly on the wall during discussions between experts including Rich Hickey, the creator of Clojure, about exciting and mysterious aspects of language design and implementation. + +While my position at Relevance afforded me a front row seat to the business of language development, I was still a relatively junior programmer, and I'd never gotten my own language to a state of anything close to completion. I had been programming long enough to develop an intuition about how things like lexical scope should work, but my understanding of how such things were actually *implemented* was fuzzy at best. + +In a quest to become a **Real Lisp Hacker**, I bounced around Google search results and a small friend group of kindred spirits for a couple of years and found myself reading stuff like the following: + + +* [Closure conversion: How to compile lambda,](http://matt.might.net/articles/closure-conversion/) a blog post by [Matt Might](http://matt.might.net/) +* [Paradigms of Artificial Intelligence (PAIP),](https://amzn.to/3px57ZJ) a book by [Peter Norvig.](https://norvig.com/) This book is now also [freely available](https://github.com/norvig/paip-lisp) online. +* [(How to Write a (Lisp) Interpreter (in Python))](https://norvig.com/lispy.html), a page by Peter Norvig +* [Henry Baker's Archive of Research Papers](https://web.archive.org/web/20190927121406/http://home.pipeline.com/~hbaker1/) + + +Of the stuff I read, [PAIP](https://amzn.to/3px57ZJ) probably propelled me the furthest along, but I struggled to develop a really solid comprehension of the basic implementation mechanics of things like closures. In retrospect, this is almost surely because I was experimenting in Clojure, but the examples were in [Common Lisp](./CommonLisp.md), a language I didn't know well. + +In the fall of 2013, in the month before Clojure/conj, I ran across [awklisp](https://github.com/darius/awklisp) by [Darius Bacon](http://wry.me/~darius/). I became obsessed with it. + +awklisp had a few properties unique among available implementations at the time. I believe this set of properties made it especially compelling to me as a learning aid: + + +1. It was not written in C. This kept the code small and focused. +2. It consisted of only 500 lines of code, all on one page. It was possible for me to understand the whole thing at one time. +3. It included a mark-and-sweep garbage collector, and so illuminates the same problems of memory management confronted by Lisp's inventors. This is something most Lisp interpreters written in high-level languages do not tackle. +4. It was written in a "lower level" language than Lisp and implemented a call stack. The emergence of Lisp is thus striking, and the mechanics of function calls are exposed. + + +After messing with awklisp, I had the idea to write something like it, but in a different language. Bash is what I decided on, and Gherkin was born. Most of Gherkin was written in the week preceding Clojure/conj 2013. + +A pickle is plucked +------------------- + +I picked bash because I knew it would be a real challenge, and boy, was I not disappointed! The reader, the first piece I wrote, was especially challenging because Lisp syntax involves various characters that have special meaning in a shell context, like ``*``. I got hung up many times by things like the differences between " and ', the consequences of various options to set, and bash ``eval``. + +Once I had the reader basically working I started to gain serious momentum. I felt I was over the bash syntax/craziness hump. I extended awklisp's memory model to account for more data types. awklisp only had conses, symbols, and numbers; Gherkin had these, and also arrays, strings, and closures. Objects were represented as bash strings that start with a special marker character, followed by a type tag, followed by an index into the heap for objects of that type, followed by a payload. Interestingly, because Gherkin had its own memory model and heap, and because Gherkin was larger than any C program I'd written, I experienced real pointer debugging for the first time - in bash. + +Implementing closures presented a special opportunity for programming skill growth. Before this work, calling conventions, memory models, and closure semantics were topics I could hand-wave about but did not understand deeply. After this work, I reached a new, palpable level of understanding. The moment I reached this new level of understanding is unforgettable. I think (I hope!) I've grown a lot in various ways over my years of programming, but never so much, and in so little time. + +My resulting tighter grasp on closure implementation and memory management primed me for work with and on [R](https://en.wikipedia.org/wiki/R_(programming_language)). The R language is implemented in C and features first-class lexical environments. I worked extensively with R and R extensions in C and C++ during my time at [RStudio](https://rstudio.com/). I'm positive I would not have been as successful with R were it not for my prior experience writing Gherkin. + +The Conj +-------- + +By the time I arrived at Clojure/conj, Gherkin was working well enough that I signed up to give a lightning talk about it. I was at the conference with my coworkers from LonoCloud, all Lisp and Clojure enthusiasts and afficionados themselves. They got a kick out of it and provided encouragement. One, [Joel Martin](https://twitter.com/bus_kanaka), was especially excited, and contributed ideas and code for a much cleaner reader. + +From my perspective, the presentation ([up on YouTube](https://www.youtube.com/watch?v=bmHTFo2Rf2w#t=28m55s)) was surreal. When I looked to the audience after moments I thought would elicit laughter, there was none. When I made what I thought was a serious observation, there was laughter! I feared I'd embarrassed myself. I was relieved to learn later from members of the audience that they thoroughly enjoyed themselves. + +Post-Conj developments +---------------------- + +After the talk, [Paula Gearon,](https://twitter.com/quoll) [Jeremy Heiler](https://twitter.com/jeremyheiler?lang=en), and [Devin Walters](https://twitter.com/devn) kindly contributed core functions. [Craig Andera](https://twitter.com/craigandera) even made an Emacs mode, [gherkin-mode.el](https://github.com/candera/gherkin-mode). I'm very grateful to these and my other friends for their interest, encouragement, and involvement. + +After a flurry of conference activity, progress slowed down. My stated ambition for the project, that it would replace bash, was never completely serious; ironically, I became so inured to bash that I lost what little motivation I did originally have to replace it. The evaluator and garbage collector also had serious flaws that would have required a lot of work to rectify. I think I was satisfied enough with myself for perceiving these flaws that I saw little additional value in addressing them. In 2015, after two years of quiet, I "archived" the project on GitHub. + +mal +--- + +[mal](https://github.com/kanaka/mal) or "make-a-lisp" by [Joel Martin](https://twitter.com/bus_kanaka) is a Clojure-inspired Lisp interpreter and much, *much* more. Joel started by writing an interpreter in GNU Make shortly after I showed him Gherkin at Clojure/conj. His choice of Make was audacious compared even to my choice of bash. Then he took a huge step further, and codified the interpreter development experience into a structured, gamified series of language-agnostic steps. Thanks to Joel, anyone who wants to make a Lisp for any language has resources to start from that exceed even awklisp in educational value. + +I highly recommend Joel's talk on YouTube, [Achievement Unlocked: A Better Path to Language Learning](https://www.youtube.com/watch?v=lgyOAiRtZGw) if you want to learn more about his fantastic project. + +Other related projects +---------------------- + +I'm aware of these projects that were inspired by or otherwise related to Gherkin. If you know of others, please let me know at [alan@tailrecursion.com](mailto:alan@tailrecursion.com) and I will happily list them below. + + +* [timl](https://github.com/tpope/timl) by [Tim Pope](https://tpo.pe/) is an impressive Clojure-like language that *compiles* to VimL. It is a much more sophisticated and comprehensive effort than Gherkin. Tim [was moved](https://twitter.com/tpope/status/1202261256859729920) to create timl after seeing my lightning talk. +* [Fleck](https://github.com/chr15m/flk) by [Chris McCormick](https://mccormick.cx/) is "a Clojure-like LISP that runs wherever Bash is". +* Andy Chu [reported on Twitter](https://twitter.com/oilshellblog/status/1327317599558897666) that he used Gherkin at one point [as part of the tests](https://t.co/ud7Uf3bhVf?amp=1) for the parser of his [oil shell](https://www.oilshell.org/). + + +Proper BDFL attire +------------------ + +Clinton Dreisbach made me an awesome Gherkin shirt in December of 2013, at the height of Gherkin-mania. Here I am modeling it. Thanks Clinton! + + diff --git a/md_export/Lisp/GherkinHistory/IMG_2485.JPG b/md_export/Lisp/GherkinHistory/IMG_2485.JPG new file mode 100644 index 0000000..9bb297b Binary files /dev/null and b/md_export/Lisp/GherkinHistory/IMG_2485.JPG differ diff --git a/md_export/Lisp/GherkinHistory/alan_wearing_gherkin_shirt.jpg b/md_export/Lisp/GherkinHistory/alan_wearing_gherkin_shirt.jpg new file mode 100644 index 0000000..bf98015 Binary files /dev/null and b/md_export/Lisp/GherkinHistory/alan_wearing_gherkin_shirt.jpg differ diff --git a/md_export/PersonalBackground.md b/md_export/PersonalBackground.md new file mode 100644 index 0000000..a5450cf --- /dev/null +++ b/md_export/PersonalBackground.md @@ -0,0 +1,3 @@ +# PersonalBackground +TODO + diff --git a/md_export/RandallRDipert.md b/md_export/RandallRDipert.md new file mode 100644 index 0000000..d387965 --- /dev/null +++ b/md_export/RandallRDipert.md @@ -0,0 +1,10 @@ +# RandallRDipert +Created Tuesday 17 November 2020 + +Randall Roy Dipert (1951-2019) was my father. This page honors his memory and legacy. + + +* [Randall Dipert on Wikipedia](https://en.wikipedia.org/wiki/Randall_Dipert) +* [WellReadUndergrad](./WellReadUndergrad.md) is a list of philosophy readings my dad suggested for undergraduate students. + + diff --git a/md_export/TechSolutions.md b/md_export/TechSolutions.md new file mode 100644 index 0000000..1fc9141 --- /dev/null +++ b/md_export/TechSolutions.md @@ -0,0 +1,29 @@ +# TechSolutions +Created Tuesday 15 December 2020 + +Errors messages I've run across and how I resolved them. + +#### Google Meet in Google Chrome on Fedora 32 (2021-06-04) + +**Error:** Can't present screen +**Solution:** Navigate to <chrome://flags> and enable "WebRTC PipeWire support" +**Context:** Wayland, Fedora, WebRTC, PipeWire, Chrome, Meet + +#### GNU screen (2021-02-22) + +**Error:** ``Utmp slot not found`` +**Solution:** Add ``deflogin off`` to ``~/.screenrc`` +**Context:** Debian, Ubuntu, WSL + +#### aws s3 command (2021-02-05) + +**Error:** ``fatal error: An error occurred (RequestTimeTooSkewed) when calling the ListObjectsV2 operation: The difference between the request time and the current time is too large.`` +**Solution:** ``sudo ntpdate pool.ntp.org`` or similar to update your local system time. +**Context:** awscli, AWS, s3, Debian, Ubuntu, Linux + +#### Docker on Debian Buster (2020-12-15) + +**Error:** ``Running iptables --wait -t nat -L -n failed with message:`` +**Solution:** ``update-alternatives --set iptables /usr/sbin/iptables-legacy`` +**Context:** ``docker start``, Docker, Debian Buster, ``/var/log/docker.log`` + diff --git a/md_export/TechWorks.md b/md_export/TechWorks.md new file mode 100644 index 0000000..1fc38e2 --- /dev/null +++ b/md_export/TechWorks.md @@ -0,0 +1,40 @@ +# TechWorks +The following are technical presentations, workshops, papers, and other works I've created or helped to create. + +| Date | Venue | Title | Format | Role | With | +|:-----------|:----------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------|:-------------------|:---------------------------| +| 2021-01-28 | [SciCloj](https://scicloj.github.io/) | [Common Lisp for the Curious Clojurian](https://www.youtube.com/watch?v=44Q9ew9JH_U) | Meetup | Presenter | | +| 2020-12-23 | [ClojureScript Podcast](https://soundcloud.com/user-959992602/s4-e19-hoplon-with-alan-dipert) | [S4 E19 Hoplon with Alan Dipert](https://soundcloud.com/user-959992602/s4-e19-hoplon-with-alan-dipert) | Interview | Interviewee | Jacek Schae | +| 2020-04-28 | [ELS](https://www.european-lisp-symposium.org/) | [JACL: A Common Lisp for Developing Single-Page Web Applications](https://www.youtube.com/watch?v=HGuTqsVh59w) | Presentation | Presenter | | +| 2020-04-27 | [ELS](https://www.european-lisp-symposium.org/) | [JACL: A Common Lisp for Developing Single-Page Web Applications](./TechWorks/jacl-demo-els-2020.pdf) | Academic Paper | Author | | +| 2020-01-31 | rstudio::conf | [Integration Testing in Shiny Apps and Modules](./TechWorks/2020-01-28-RStudio-Conf-Integration-Testing-ePoster.pdf) | Poster | Presenter | | +| 2019-12-11 | WWW | [Just Lisp Things](https://tailrecursion.com/jlt/) | Author | Blog | | +| 2019-11-19 | [OCRUG](https://ocrug.org/) | [Integrating React.js and Shiny](https://www.meetup.com/OC-RUG/events/265511792/), [code](https://github.com/alandipert/ocrug-2018-11-27) | Presentation | Presenter | | +| 2019-11-16 | [OCRUG](https://ocrug.org/) | [Interview with Alan Dipert](https://ocrug.org/blog/2019/11/19/2019-11-19-interview-alan-dipert/) | Interview | Interviewee | | +| 2019-01-24 | rstudio::conf | [Integrating React.js and Shiny](https://rstudio.com/resources/rstudioconf-2019/integrating-react-js-and-shiny/) | Presentation | Presenter | | +| 2018-12-17 | [Orange Combinator](https://www.meetup.com/fr-FR/orange-combinator/events/lxvjrpyxqbwb/) | [Old School FP: A Common Lisp Experience Report](https://tailrecursion.com/~alan/documents/2018-12-17-CommonLispOrangeCombinator.pdf) | Meetup | Presenter | | +| 2018-09-06 | rstudio.com | [Load testing Shiny](https://rstudio.com/resources/webinars/load-testing-shiny/) | Webinar | Presenter | | +| 2018-02-02 | rstudio::conf | [Make Shiny fast by doing as little work as possible](https://rstudio.com/resources/rstudioconf-2018/make-shiny-fast-by-doing-as-little-work-as-possible/), [slides](https://github.com/alandipert/fast-shiny) | Presentation | Presenter | | +| 2018-01-31 | rstudio::conf | Intermediate Shiny | Workshop | Teaching assistant | | +| 2017-10-13 | WWW | [Wondr: Thoughts on R programming](https://tailrecursion.com/wondr/) | Blog | Author | | +| 2016-11-03 | [The Cognicast](https://www.cognitect.com/cognicast/) | [Episode 112](https://www.cognitect.com/cognicast/112) | Interview | Interviewee | Craig Andera, Micha Niskin | +| 2016-10-18 | [The Cognicast](https://www.cognitect.com/cognicast/) | [Episode 111](https://www.cognitect.com/cognicast/111) | Interview | Interviewee | Craig Andera, Micha Niskin | +| 2015-11-06 | [Øredev](https://archive.oredev.org/2015/2015.html) | [Programmable Builds with Boot](https://vimeo.com/144997124) | Presentation | Presenter | | +| 2015-11-04 | [Øredev](https://archive.oredev.org/2015/2015.html) | [Hoplon: A Simpler Way to Program the Web](https://vimeo.com/144696304) | Presentation | Presenter | | +| 2015-10-02 | [ClojureBridge](https://clojurebridge.org/) | ClojureBridge Durham | Workshop | Teaching assistant | Yoko Harada | +| 2015-10-01 | No Starch Press | [Clojure for the Brave and True](https://www.amazon.com/Clojure-Brave-True-Ultimate-Programmer/dp/1593275919/ref=as_li_ss_tl?dchild=1&keywords=clojure+brave+true&qid=1606509052&sr=8-1&linkCode=ll1&tag=adipert-20&linkId=6377033a07b0c6d35bdd0535a5bc8fd6&language=en_US) | Book | Technical editor | Daniel Higginbotham | +| 2015-04-20 | [Clojure/West](https://web.archive.org/web/20150325185906/http://clojurewest.org/) | [Boot Can Build It](https://www.youtube.com/watch?v=TcnzB2tB-8Q), [slides](./TechWorks/2015-04-20_ClojureWestBoot.pdf) | Presentation | Presenter | Micha Niskin | +| 2014-03-24 | [Clojure/West](https://web.archive.org/web/20141115162625/http://www.clojurewest.org/) | [Web Programming with Hoplon](https://www.youtube.com/watch?v=wVXjExRiFy0) | Presentation | Presenter | Micha Niskin | +| 2014-03-18 | [The Cognicast](https://www.cognitect.com/cognicast/) | [Episode 52](https://www.cognitect.com/cognicast/052-alan-dipert) | Interview | Interviewee | Craig Andera | +| 2013-11-14 | [Clojure/conj](https://web.archive.org/web/20131010003442/http://clojure-conj.org/) | [Gherkin, a Lisp 1 in Bash 4](https://www.youtube.com/watch?v=bmHTFo2Rf2w#t=28m55s), [code](https://github.com/alandipert/gherkin) | Lightning talk | Presenter | | +| 2013-03-18 | Clojure/West | [FRP in ClojureScript with Javelin](http://www.infoq.com/presentations/ClojureScript-Javelin), [slides](./TechWorks/Dipert-FRP_in_ClojureScript_with_Javelin.pdf) | Presentation | Presenter | | +| 2012-11-16 | [Clojure/conj](http://2012.clojure-conj.org/) | [FRP in ClojureScript with Flapjax](https://www.youtube.com/watch?v=xaxF5RDdVRE#t=22m21s), [code](https://www.youtube.com/watch?v[[https://github.com/alandipert/flapjax-demo), [demo](http://alandipert.github.io/flapjax-demo/) | Lightning talk | Presenter | | +| 2012-10-06 | BarCamp Rochester 10 | Your Own Compiler in 20 Minutes, [slides](https://github.com/alandipert/barcamp2012-jsonscript) | Presentation | Presenter | | +| 2012-07-19 | OSCON | Computing with Clojure, [slides](https://github.com/alandipert/oscon2012-clojure) | Workshop | Trainer | Clinton Dreisbach | +| 2012-07-13 | Pluralsight | [Clojure Fundamentals - Part 1](https://www.pluralsight.com/courses/clojure-fundamentals-part-one) | Course | Trainer | Craig Andera | +| 2012-03-16 | Clojure/West | [Programming with Values in Clojure](https://www.infoq.com/presentations/Programming-with-Values-in-Clojure/), [slides](https://web.archive.org/web/20120216230608/http://clojurewest.org/[[.\\Dipert-ProgrammingWithValues.pdf) | Presentation | Presenter | | +| 2011-11-12 | [Clojure/conj](https://web.archive.org/web/20111023154311/http://clojure-conj.org/) | [Uberlisp, a Lisp for Arduino](https://www.youtube.com/watch?v=tSw3x0rVh88#t=18m30s), [code](https://github.com/alandipert/wombat) | Lightning talk | Presenter | Jon Distad | +| 2011-08-25 | The Ruby Hoedown V | Functional Programming with Ruby | Presentation | Presenter | | +| 2005-01-14 | Linux.com | [My workstation OS: NetBSD](https://web.archive.org/web/20080201010726/http://www.linux.com/articles/41523) | Article | Author | | + + diff --git a/md_export/TechWorks/2015-04-20_ClojureWestBoot.pdf b/md_export/TechWorks/2015-04-20_ClojureWestBoot.pdf new file mode 100644 index 0000000..30615c5 Binary files /dev/null and b/md_export/TechWorks/2015-04-20_ClojureWestBoot.pdf differ diff --git a/md_export/TechWorks/2020-01-28-RStudio-Conf-Integration-Testing-ePoster.pdf b/md_export/TechWorks/2020-01-28-RStudio-Conf-Integration-Testing-ePoster.pdf new file mode 100644 index 0000000..4740eec Binary files /dev/null and b/md_export/TechWorks/2020-01-28-RStudio-Conf-Integration-Testing-ePoster.pdf differ diff --git a/md_export/TechWorks/Dipert-FRP_in_ClojureScript_with_Javelin.pdf b/md_export/TechWorks/Dipert-FRP_in_ClojureScript_with_Javelin.pdf new file mode 100644 index 0000000..b1c9994 Binary files /dev/null and b/md_export/TechWorks/Dipert-FRP_in_ClojureScript_with_Javelin.pdf differ diff --git a/md_export/TechWorks/Dipert-ProgrammingWithValues.pdf b/md_export/TechWorks/Dipert-ProgrammingWithValues.pdf new file mode 100644 index 0000000..16f4ee8 Binary files /dev/null and b/md_export/TechWorks/Dipert-ProgrammingWithValues.pdf differ diff --git a/md_export/TechWorks/jacl-demo-els-2020.pdf b/md_export/TechWorks/jacl-demo-els-2020.pdf new file mode 100644 index 0000000..d33e882 Binary files /dev/null and b/md_export/TechWorks/jacl-demo-els-2020.pdf differ diff --git a/md_export/WellReadUndergrad.md b/md_export/WellReadUndergrad.md new file mode 100644 index 0000000..bb80506 --- /dev/null +++ b/md_export/WellReadUndergrad.md @@ -0,0 +1,35 @@ +# WellReadUndergrad +Created Tuesday 17 November 2020 + +The following is adapted from a Word document titled [What Every Educated Person Should Know about Philosophy](./WellReadUndergrad/phil-lt5.doc). My dad [RandallRDipert](./RandallRDipert.md) created the document in 1998 while he was a philosophy professor at [West Point](https://www.westpoint.edu/). The document was later [available on his web site,](https://web.archive.org/web/20000919054115/http://www.neologic.net/rd/courses.htm) where he described it as: + +*A list of books and articles, concepts, and quotations which I suggest every college graduate should know; also, extended to a graduate who is a philosophy major. A bit grandiose, overreaching, and pompous--but maybe suggestive of something useful.* + + +***** + +What Every Educated Person Should Know in Philosophy +---------------------------------------------------- + +A well-read undergraduate should ideally have read, or at least be somewhat familiar with the content of, many or most of the works in **boldface**. (Works that can be read first have one asterisk; works to read next, two asterisks; and the hardest introductory works have three asterisks.) Other works are listed as part of a suggested reading list for a well-read undergraduate major in philosophy. + +### Novels and other Literature with Philosophical Substance + +| Author | Work | +|:--------------------------------|:--------------------------------------------------------------------------------------------------------------------------------| +| Aristophanes | *The Clouds* (satire of philosophy and Socrates) | +| Alexander Pope | *Essay on Man* (long poem in English, religious metaphysics) | +| Voltaire | *Candide* (parody of Leibniz) and other short works | +| J.W. von Goethe | *Faust* | +| Fyodor Dostoevsky | ***Crime and Punishment (or Notes from the Underground)***, ***The Brothers Karamazov*** (esp. section "Grand Inquisitor") | +| Hermann Hesse | ***Siddharta*** (novella) | +| Albert Camus | **The Stranger**; The Plague (novels)<br>, The Myth of Sisyphus (essays, meaning of life, suicide) | +| Ayn Rand | *The Fountainhead, Atlas Shrugged* | +| Jean-Paul Sartre | ****No Exit** (drama) | +| Lewis Carroll (Charles Dodgson) | ****Alice in Wonderland** (read as an adult, preferably after<br> studying some logic)<br>, *Through the Looking Glass* (logic) | +| T.S. Eliot | Several works, especially *The Waste Land and Four Quartets* | +| Robert Pirsig | ***Zen and the Art of Motorcycle Maintenance<br>**, Lila | + + +TODO + diff --git a/md_export/WellReadUndergrad/phil-lt5.doc b/md_export/WellReadUndergrad/phil-lt5.doc new file mode 100644 index 0000000..101f900 Binary files /dev/null and b/md_export/WellReadUndergrad/phil-lt5.doc differ diff --git a/md_export/WellReadUndergrad/phil-lt5.docx b/md_export/WellReadUndergrad/phil-lt5.docx new file mode 100644 index 0000000..cf5e9d2 Binary files /dev/null and b/md_export/WellReadUndergrad/phil-lt5.docx differ diff --git a/tools/mdlink2html.awk b/tools/mdlink2html.awk new file mode 100755 index 0000000..315fa5b --- /dev/null +++ b/tools/mdlink2html.awk @@ -0,0 +1,47 @@ +#!/usr/bin/env awk -f +# Rewrite Markdown links to point at generated HTML pages. + +function rewrite_url(url, path, frag, hash_pos, lower) { + if (url ~ /:\/\//) { + return url + } + if (substr(url, 1, 1) == "#") { + return url + } + + hash_pos = index(url, "#") + if (hash_pos) { + frag = substr(url, hash_pos) + path = substr(url, 1, hash_pos - 1) + } else { + frag = "" + path = url + } + + lower = tolower(path) + if (lower ~ /\.md$/) { + path = substr(path, 1, length(path) - 3) ".html" + } else if (path != "") { + if (lower ~ /\.(html|png|jpg|jpeg|gif|svg|pdf|css|js|zip)$/) { + # leave as-is + } else if (path !~ /\.[A-Za-z0-9]+$/ && path ~ /^[A-Za-z0-9._\-\/]+$/) { + path = path ".html" + } + } + + return path frag +} + +{ + output = "" + remaining = $0 + while (match(remaining, /\]\([^)]+\)/)) { + prefix = substr(remaining, 1, RSTART - 1) + url = substr(remaining, RSTART + 2, RLENGTH - 3) + rewritten = rewrite_url(url) + output = output prefix "](" rewritten ")" + remaining = substr(remaining, RSTART + RLENGTH) + } + output = output remaining + print output +} diff --git a/tpl/foot.html b/tpl/foot.html new file mode 100644 index 0000000..31e606f --- /dev/null +++ b/tpl/foot.html @@ -0,0 +1,8 @@ + </div> + </div> + <footer class="site-foot"> + <p>@BUILDINFO@</p> + </footer> + </div> +</body> +</html> diff --git a/tpl/head.html b/tpl/head.html new file mode 100644 index 0000000..a83a59b --- /dev/null +++ b/tpl/head.html @@ -0,0 +1,22 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <title>Wiki</title> + <link rel="stylesheet" href="@CSS@style.css"> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-XCMVL5K44X"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'G-XCMVL5K44X'); + </script> +</head> +<body> + <div id="main"> + <header class="site-head"> + <h1><a href="@CSS@Home.html">Home</a></h1> + </header> + <div class="pages"> + <div class="content"> diff --git a/tpl/style.css b/tpl/style.css new file mode 100644 index 0000000..f506c5a --- /dev/null +++ b/tpl/style.css @@ -0,0 +1,77 @@ +:root{--fg:#2e3436;--bg:#ffffff;--muted:#6c757d;--link:#1a73e8;--shadow:0 4px 8px rgba(0,0,0,.2),0 6px 20px rgba(0,0,0,.19)} +html{ + --s:82px; + --c1:#b2b2b2; + --c2:#ffffff; + --c3:#d9d9d9; + --_g:var(--c3) 0 120deg,#0000 0; + background: + conic-gradient(from -60deg at 50% calc(100%/3),var(--_g)), + conic-gradient(from 120deg at 50% calc(200%/3),var(--_g)), + conic-gradient(from 60deg at calc(200%/3),var(--c3) 60deg,var(--c2) 0 120deg,#0000 0), + conic-gradient(from 180deg at calc(100%/3),var(--c1) 60deg,var(--_g)), + linear-gradient(90deg,var(--c1) calc(100%/6),var(--c2) 0 50%, + var(--c1) 0 calc(500%/6),var(--c2) 0); + background-size:calc(1.732*var(--s)) var(--s); +} +body{ + margin:0; + padding:0; + font:16px/1.6 "Segoe UI",Roboto,Helvetica,Arial,sans-serif; + color:var(--fg); +} +#main{ + margin:40px auto; + max-width:800px; + padding:1.5em; + background:var(--bg); + border-radius:.75em; + box-shadow:var(--shadow); +} +.site-head{ + margin-bottom:1.5rem; + border-bottom:1px solid rgba(0,0,0,.08); + padding-bottom:.75rem; +} +.site-head h1{ + margin:0; + font-size:1.5rem; +} +.site-head a{ + color:var(--link); + text-decoration:none; +} +.site-head a:hover{ + text-decoration:underline; +} +.content h1, +.content h2, +.content h3, +.content h4, +.content h5{ + color:#cc3b12; + line-height:1.25; +} +.content p{margin-top:0;} +.content pre, +.content code{background:#f7f7f7;} +.content pre{padding:.75rem;overflow:auto;} +a{color:var(--link);} +img[src*="float_right"]{float:right;border-radius:.75em;} +img[src*="200px"]{width:200px;} +.content table{width:100%;border-collapse:collapse;margin:1.5rem 0;box-shadow:inset 0 -1px 0 rgba(0,0,0,.05);} +.content th, +.content td{padding:.5rem .75rem;border-bottom:1px solid rgba(0,0,0,.08);} +.content thead th{background:rgba(0,0,0,.04);font-weight:600;text-align:left;} +.content td[align="right"], +.content th[align="right"]{text-align:right;} +.content td[align="center"], +.content th[align="center"]{text-align:center;} +.site-foot{ + margin-top:2rem; + border-top:1px solid rgba(0,0,0,.08); + padding-top:1rem; + color:var(--muted); + font-size:.875rem; +} +.site-foot p{margin:0;}