Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Advanced examples

Longer recipes that combine several modules.

Example results generated on 2026-10-08. Ones using now, today or randomness will differ when you run them: press Run on any example to run it in your browser, after editing it if you like.

travel and sky

a flight from Seattle to Tokyo: time in the air and local arrival

geo · units · time.zones

leave = date("2026-12-20T13:00-08:00") to "Seattle"
flight = great_circle("Seattle", "Tokyo") / 900 km/h
{in_the_air: flight.parts, landing: leave + flight to "Tokyo"}
# → {in_the_air: "8 h 33 min 5 s", landing: 2026-12-21 14:33:05 +09:00}

UTC hours when it’s 9 to 5 in New York, London and Berlin at once

time.zones · data.lists

office = |t| 9 <= t.hour < 17
day = date("2026-10-12T00:00Z") to UTC
hours = (0..24).map(|h| day + h * 1 h)
hours.filter(|t| office(t to "New York") && office(t to "London") && office(t to "Berlin")).map(|t| t.format("%H:%M"))
# → ["13:00", "14:00"]

hours of daylight on the 21st of each month, equator to arctic

time.sky · geo · data.charts · art.frames

places = ["Singapore", "Cairo", "Paris", "Oslo", "Reykjavik"]
rows = places.map(|p| (1..=12).map(|m| day_length(p, date(2026, m, 21)) / 1 h))
places.map(|p| p.pad(10)).join("\n").beside(rows.heatmap)
# → Singapore  ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
# → Cairo      ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░
# → Paris      ░░▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒░░░░
# → Oslo       ░░░░▒▒▓▓▓▓▓▓▓▓▓▓▒▒░░░░
# → Reykjavik    ░░▒▒▓▓▓▓████▓▓▒▒░░

where the sun sets within the next hour

geo · time.sky · time

cities().filter(|c| now <= sunset(c.name, today) < now + 1 h).map(|c| c.name).take(6)
# → ["Suva", "Tarawa", "Majuro", "Funafuti"]

the fastest a ping from New York could ever be: there and back through fiber at 2/3 c

geo · units.constants

["London", "Tokyo", "Sydney"].map(|p| 2 * great_circle("New York", p) / (2/3 * c) to ms)
# → [55.7408 ms, 108.562 ms, 160 ms]

dig straight down from Madrid: where do you come out?

geo

m = city("Madrid")
out = nearest(-m.lat, m.lon - 180)
{city: out.name, country: out.country, apart: great_circle("Madrid", out.name) to km}
# → {city: "Wellington", country: "New Zealand", apart: 19854.7 km}

the further north, the shorter December days: latitude vs. daylight across every city

geo · time.sky · math.stats

cs = cities()
corr(cs.map(|c| c.lat), cs.map(|c| day_length(c.name, date(2026, 12, 21)) / 1 h))
# → -0.96734

the day Oslo gains daylight fastest, and how fast

time.sky · math.stats · time

start = date(2026, 1, 1)
gains = (0..365).map(|i| day_length("Oslo", start + i * 1 d)).deltas
{day: start + (gains.find(gains.max) + 1) * 1 d, gained: gains.max to min, fastest_loss: gains.min to min}
# → {day: 2026-03-16, gained: 5.46001 min, fastest_loss: -5.37941 min}

money and science

a $400k mortgage from January 2027: cost, crossover, interest by year

finance · time · data.lists · data.charts

plan = amortize($400000, 6.5%/yr, 30 yr)
flip = plan.filter(|m| m.principal > m.interest).first
yearly = plan.chunks(12).map(|y| y.map(|m| m.interest).sum / $1)
{monthly: plan[0].payment, interest: plan.map(|m| m.interest).sum, crossover: date(2027, 1, 1) + (flip.n - 1) * 1 mo, by_year: yearly.sparkline}
# → {monthly: $2,528.27, interest: $510,177.95, crossover: 2046-05-01, by_year: "██████▇▇▇▇▇▇▇▆▆▆▆▅▅▅▅▄▄▄▃▃▂▂▂▁"}

a ski trip: who owes whom

finance · data.maps

paid = {ana: $640 + $85.50, ben: 3 * $42, cy: $0, dee: $310}
{each: share(paid.values.sum, 4)[0], settle: settle(paid)}
# → {each: $290.38, settle: ["cy pays ana $290.38", "ben pays ana $144.75", "ben pays dee $19.62"]}

weigh the Earth with a pendulum; errors carry through every step

math.uncertainty · units.constants

L = 1.000 ± 0.005 m
T = (20.07 ± 0.1 s) / 10    # timed 10 swings
g = 4 * pi ** 2 * L / T ** 2 to m/s^2
M = g * (6371 km) ** 2 / G to kg
{g: g, off_by: percent(g.value / g0 - 1, 2), earth: M}
# → {g: 9.80088 ± 0.109272 m/s^2, off_by: "-0.06%", earth: 5.96039e24 ± 6.64533e22 kg}

a ball thrown at 20 m/s, 35° up: landing, peak and arc

math.calculus · math.trig · data.charts

v = 20; a = 35 deg; g = 9.81
y = |t| v * sin(a) * t - g / 2 * t ** 2
land = root(y, 0.1, 10)
peak = root(|t| deriv(y, t), 0, land)
{seconds: round(land, 2), meters: round(v * cos(a) * land, 1), peak: round(y(peak), 2), arc: (0..=30).map(|i| y(land * i / 30)).sparkline}
# → {seconds: 2.34, meters: 38.3, peak: 6.71, arc: "▁▂▃▄▄▅▅▆▆▇▇█████████▇▇▆▆▅▅▄▄▃▂▁"}

fractions closing in on pi: convergents of its continued fraction, and how far off each is

math.numtheory · data.lists

terms = pi.cfrac(5)
fold = |ts| ts.reverse.drop(1).reduce(ts.last, |acc, t| t + 1 / acc)
(1..=5).map(|n| fold(terms.take(n))).map(|c| [c to frac, sci(abs(c - pi), 1)])
# → [[3, "1.4e-1"], [22/7, "1.3e-3"], [333/106, "8.3e-5"], [355/113, "2.7e-7"], [103993/33102, "5.8e-10"]]

units.kitchen · data.maps

cups = {flour: 2.25 cup, sugar: 0.75 cup, butter: 1 cup, honey: 2 tbsp}
cups.entries.map(|[k, v]| [k, round(v * 60 / 24 * density(k) to g)]).from_entries
# → {flour: 705 g, sugar: 377 g, butter: 568 g, honey: 105 g}

a Fermi estimate with honest error bars: piano tuners in Chicago

math.uncertainty · units

pianos = (2.7e6 ± 0.1e6) / (2.5 ± 0.5) * (5% ± 2%)    # people / household * share with a piano
per_tuner = (4 ± 1) / d * 250 d / yr
pianos / yr / per_tuner
# → 54 ± 17.4372

three receipts, three unknown prices: coffee, bagel, juice

math.linalg · units.money

# rows: [coffees, bagels, juices] on each receipt
solve([[2, 1, 0], [1, 2, 1], [0, 1, 2]], [$9.50, $11.50, $8.50])
# → [$3.50, $2.50, $3.00]

text, data and dev

how far apart were the errors in a log, and what were they?

text · time · math.stats · data.lists

log = "08:59:58 INFO start
09:00:03 ERROR db timeout
09:00:41 INFO retry
09:02:15 ERROR db timeout
09:07:50 ERROR disk full"
errors = log.grep("ERROR")
times = errors.map(|l| date("2026-10-06 " + l.match(r"^\S+")))
{gaps: times.deltas.map(|d| d.parts), kinds: errors.map(|l| l.split("ERROR ")[1]).count_by(|k| k)}
# → {gaps: ["2 min 12 s", "5 min 35 s"], kinds: {db timeout: 2, disk full: 1}}

crack a Caesar cipher: try every shift, keep the one with the most real words

text.ciphers · text.layout · data

secret = "wkh vhfuhw sdvvzrug lv vzruglvk"
common = ["the", "is", "and", "a", "of", "to", "secret", "password", "in"]
score = |s| s.words.filter(|w| w in common).len
(0..26).map(|k| secret.caesar(-k)).sort(score).last
# → "the secret password is swordish"

a running log as CSV; h:m:s times become durations by a dot product

fs · data.tables · math.linalg · units

runs = "date,km,time\n2026-09-01,5,0:27:30\n2026-09-04,10,0:58:10\n2026-09-08,5,0:26:05\n2026-09-12,21.1,2:05:40".from_csv
dur = |t| dot(t.split(":").map(int), [1 h, 1 min, 1 s])
pretty(runs.map(|r| {date: r.date, km: r.km, per_km: dur(r.time) / r.km to min}).table.sort_by("per_km"))
# →  #  date          km      per_km
# → ────────────────────────────────
# →  0  2026-09-08     5  5 min 13 s
# →  1  2026-09-01     5  5 min 30 s
# →  2  2026-09-04    10  5 min 49 s
# →  3  2026-09-12  21.1  5 min 57 s
# → ────────────────────────────────
# →  4 rows · 3 columns

carve a /22 into /24s and see which one each server lands in

dev.net · data.tables

servers = ["10.0.1.20", "10.0.3.7", "10.0.3.250", "10.0.0.9"]
pretty(subnets("10.0.0.0/22", 24).map(|b| {
  block: b, hosts: cidr(b).hosts, servers: servers.filter(|s| in_cidr(s, b)).join(" "),
}).table)
# →  #  block        hosts  servers
# → ───────────────────────────────────────────
# →  0  10.0.0.0/24    254  10.0.0.9
# →  1  10.0.1.0/24    254  10.0.1.20
# →  2  10.0.2.0/24    254  
# →  3  10.0.3.0/24    254  10.0.3.7 10.0.3.250
# → ───────────────────────────────────────────
# →  4 rows · 3 columns

six hues, each as light as it can be while still readable on white

dev.colors · data.lists

readable = |h| (20..=70).map(|l| hsl(h, 75, l)).filter(|c| contrast(c, "white") >= 4.5).last
(0..6).map(|i| readable(i * 60)).map(|c| "{swatch(c)} {round(contrast(c, "white"), 2)}").join("\n")
# →      #e12d2d 4.55
# →      #787811 4.67
# →      #138613 4.72
# →      #128181 4.68
# →      #6363e9 4.68
# →      #cd1dcd 4.51

when were this token and this ID minted, in Tokyo time?

dev · dev.ids · time.zones

token = jwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZGEiLCJpYXQiOjE1MTYyMzkwMjJ9.c2ln")
id = uuid_info("01890a5d-ac96-774b-bcce-b302099a8057")
[token.payload.iat, id.timestamp].map(|d| [d to "Tokyo", d.relative])
# → [[2018-01-18 10:30:22 +09:00, "9 years ago"], [2023-06-30 12:34:18 +09:00, "3 years ago"]]

anagram groups: words that sort to the same letters

text.layout · data.lists

words = "listen silent enlist google tinsel inlets banana stone tones notes onset".words
words.group_by(|w| w.chars.sort.join).values.filter(|g| g.len > 1)
# → [["listen", "silent", "enlist", "tinsel", "inlets"], ["stone", "tones", "notes", "onset"]]

a spellchecker in one line: each word’s closest match in a dictionary

text.compare · text.layout

dict = "the quick brown fox jumps over lazy dog".words
"teh qiuck bronw fox jumsp ovr the lazzy dgo".words.map(|w| w.closest(dict)).join(" ")
# → "the quick brown fox jumps over the lazy dog"

newest release per major version, by semver precedence rather than string order

dev · data.lists · data.maps

tags = ["1.9.3", "1.10.0", "2.0.0-rc.1", "2.0.0", "1.2.11", "2.1.0-beta"]
tags.group_by(|t| semver(t).major).map_values(|vs| vs.sort(semver).last)
# → {1: "1.10.0", 2: "2.1.0-beta"}

how many files until two CRC-32s probably collide?

math.random · math.calculus

half = root(|k| birthday_paradox(round(k), 2 ** 32) - 0.5, 1, 1e6)
{even_odds_at: round(half), at_10k_files: odds(birthday_paradox(10000, 2 ** 32))}
# → {even_odds_at: 77164, at_10k_files: "1 in 86: about as likely as rolling double sixes (1 in 36)"}

proof of work: the first nonce whose SHA-256 starts with 000

text.hash · math

n = 0
while !"zil:{n}".sha256.starts_with("000") { n += 1 }
{nonce: n, hash: "zil:{n}".sha256[..16], expected_tries: 16 ** 3}
# → {nonce: 419, hash: "000fead2fe0984b8", expected_tries: 4096}

puzzles and play

prime dates: days of 2027 whose YYYYMMDD is prime

math.numtheory · time · data.lists

days = (0..365).map(|i| date(2027, 1, 1) + i * 1 d)
primes = days.filter(|d| is_prime(int(d.format("%Y%m%d"))))
{count: primes.len, first: primes.take(3).map(|d| d.format("%b %d")), by_month: primes.count_by(|d| d.format("%b"))}
# → {count: 19, first: ["Jan 19", "Jan 23", "Feb 03"], by_month: {Jan: 2, Feb: 1, Mar: 2, Apr: 1, May: 2, Jun: 2, Jul: 2, Aug: 2, Sep: 2, Nov: 3}}

numbers that are palindromes in both decimal and binary

math.bases · data.lists

pal = |n| n.digits == n.digits.reverse
(1..1000).filter(|n| pal(n) && pal(n to bin))
# → [1, 3, 5, 7, 9, 33, 99, 313, 585, 717]

which points are in the Mandelbrot set? escape step, or stays

math.complex · data.maps

escapes = fn(c) { z = 0; for n in 1..=50 { z = z * z + c; if abs(z) > 2 { return n } }; return "stays" }
[0, -1, 1, 1i, 0.3 + 0.5i, -0.75 + 0.1i].map(|c| [str(c), escapes(c)]).from_entries
# → {0: "stays", -1: "stays", 1: 3, 1i: "stays", 0.3 + 0.5i: "stays", -0.75 + 0.1i: 33}

the exact chance of a poker full house

math.numtheory · math.random

p = 13 * choose(4, 3) * 12 * choose(4, 2) / choose(52, 5)
[p to frac, odds(p)]
# → [6/4165, "1 in 694: about as likely as flipping ten heads in a row (1 in 1,024)"]

files, shell and network (shown, not run)

disk usage by file type, as a bar chart

fs · data.lists · data.maps · data.charts

files = glob("**/*").filter(|f| f.type == "file")
files.group_by(|f| f.name.ext).map_values(|fs| fs.map(|f| f.size).sum to KB).bars

which weekdays you commit on

sys · time · data.lists · data.charts

sh("git log --format=%ad --date=short").lines.count_by(|d| date(d).weekday).bars

PATH entries that point nowhere

sys · fs

sep = if env("OS") == "Windows_NT" { ";" } else { ":" }
env("PATH").split(sep).filter(|p| !exists(p))

files with the most TODOs

fs · text · data.tables

todos = glob("src/**/*.rs").map(|f| {file: f.name, todos: read_file(f.name).grep("TODO").len})
todos.filter(|r| r.todos > 0).table.sort_by_desc("todos")

sort Downloads into a folder per month

fs · time

for f in ls("Downloads").where(|f| f.type == "file") {
  dir = path_join("Downloads", f.modified.format("%Y-%m"))
  mkdir(dir)
  mv(path_join("Downloads", f.name), path_join(dir, f.name))
}

a weight log: zil weigh.zil 71.2 adds today’s entry and charts them all

sys · fs · time · data.charts

if !exists("weight.csv") { write_file("weight.csv", "date,kg") }
append_file("weight.csv", "{today.format("%Y-%m-%d")},{args()[0]}")
read_file("weight.csv").from_csv.kg.sparkline

describe any CSV column: zil stats.zil data.csv price

sys · fs · math.stats

[file, col] = args()
read_file(file).from_csv.map(|r| r[col]).describe

GitHub stars, straight from the API

sys · fs

["rust-lang/rust", "zanbowie138/zil"].map(|r| fetch("https://api.github.com/repos/{r}").from_json.stargazers_count)

the weather in Oslo, in Fahrenheit

sys · fs · units

now_oslo = fetch("https://wttr.in/Oslo?format=j1").from_json.current_condition[0]
{temp: int(now_oslo.temp_C) * 1 C to F, feels_like: int(now_oslo.FeelsLikeC) * 1 C to F, sky: now_oslo.weatherDesc[0].value}

a 9-day trip at $150 a day, in local money (live rates)

sys · units.money · geo

allow_network_access()
{japan: $150 * 9 to "Japan", vietnam: $150 * 9 to "Vietnam", mexico: $150 * 9 to "Mexico"}

one phrase, three languages

text.translation · sys

allow_network_access()
["es", "ja", "de"].map(|l| "where is the train station?".translate(l))