Skip to main content
Daniel Morgan

Projects

The Olive Free Library, my amazing local library, needed a simple way to share curated resources—think Linktree, but free and simpler. Meet ‘Olive Library Links’. It’s a static Next.js site with a PHP backend that pulls from Google Sheets, caches responses, and delivers a simple no nonsense list of links. The whole thing weighs in at just 170kb and scores a .2ms load time. It’s fast, lightweight, and runs completely free on Vercel’s static hosting with a simple PHP endpoint for data.

The architecture is simple: Next.js 15 generates the static UI, while a PHP 8.1+ script handles Google Sheets access with five-minute caching. No database needed–just a flat-file JSON cache that keeps things snappy even if the Sheets API goes down. Fork away and use it for your own purposes. Full details on GitHub.

IA Mirror

Internet Archive Logo

IA Mirror is a Dockerized utility for mirroring and downloading items from the Internet Archive. It wraps the official “ia” Python library with advanced features like parallel downloads, bandwidth throttling, and metadata caching to handle large-scale or complex downloads reliably. I started with adding parallel downloads and found I could make a tool that overcomes some of the instability and constraints of the IA server. The standard Python CLI tool is great for simple downloads, but this adds a lot of features for folks who need more control and reliability – all without hammering the IA servers.

Example usage:

docker run --rm \
  -v "$PWD/IAdownload:/downloads" \
  -e IA_IDENTIFIER=OTRR_Suspense_Singles \
  -e IA_DESTDIR=/downloads \
  -e IA_ACCESS_KEY=XXX \
  -e IA_SECRET_KEY=XXX \
  themorgantown/ia-mirror:latest

Docker Pulls

Features

It’s designed to be a “polite” mirror, with built-in backoff and caching to reduce pressure on the Internet Archive’s servers. If you find it useful, please consider donating to the Internet Archive.

View on Docker Hub

Randos.club

Interest beyond just ‘chance’ and ‘fate’ but into the paranormal, psychic phenomena, telekenesis, and new directions in quantum physics drew statisticians and experimenters to a new test: can someone get what they want from a random number generator and beat the odds? In a meta analysis of 380 studies in “Examining Psychokinesis: The Interaction of Human Intention with Random Number Generators” by three researchers, the answer can be summed up as:

Maybe.

“A significant but very small overall effect size was found. The study effect sizes were strongly and inversely related to sample size and were extremely heterogeneous.”

“Unknown to most academics, a large amount of experimental data has accrued testing the hypothesis of a direct connection between the human mind and the physical world.”

“If human intention can influence physical systems, it challenges materialistic conceptions of reality, suggesting a more interconnected relationship between consciousness and the physical world.”

“Over time, experimental and statistical methods improved, and, in 1991, Radin & Ferrari undertook a meta-analysis of the dice experiments, finding small but significant deviations from chance.”

“The transition from dice experiments to random number generators marked a shift toward greater experimental control but also introduced questions about whether psi effects operate on a quantum or macroscopic level.”

“Despite methodological refinements, the evidence for psychokinesis remains controversial, with skeptics attributing observed effects to experimenter bias, selective reporting, and statistical artifacts.”

My hope is that with a global userbase, a large number of sessions, and incredibly random randomness, we can figure this out together.

Drand Logo

How random is randos.club? I’ve implemented drand, a public service spearheaded by Cloudflare (also known as the The League of Entropy) which bills itself as “Verifiable, unpredictable and unbiased random numbers as a service.” The drand random number is mixed in with the timestamp, a salt of the username, and stirred up each second (stored as milliseconds after session start) for a mega random number which is hashed to get another number, from which a hash is generated. This hash either represents a 0 or 1 based on its value.

How random numbers are generated on Randos.club:

  1. drand_randomness value is obtained from the Drand network every 30 seconds.
  2. salt is generated from the user ID
  3. timestamp is recorded for each second past the initial session start, as millisecond
  4. combinedInput = drand_randomness + salt + timestamp
  5. hash = SHA-256(combinedInput)
  6. randomNumber = parseInt(hash.charAt(0), 16) % 2 (Take the first character of the hash, convert to a number 0-15, then mod 2 to get 0 or 1)

Try it out.

Playing with chance is an ancient game. Games where we feel like have control over what appears to be random chance have been popular for millenia:

Moonphase Generator

Building a service to show “what’s today’s moonphase” was a fun project. Today the moon looks like:

Learn more here.