PageSourceSearch

https://zander.wtf/search

html zander.wtf collected 2026-09-25 21:08:37 UTC 40,489 bytes, 73 lines download raw bytes

1<!DOCTYPE html><html lang="en"> <head><!-- Global Metadata --><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v5.16.15"><!-- Canonical URL --><link rel="canonical" href="https://zander.wtf/search"><!-- Primary Meta Tags --><title>Search | Zander Martineau</title><meta name="title" content="Search | Zander Martineau"><meta name="description" content="Search blog posts, code notes, projects and more"><link rel="author" href="Zander Martineau"><meta name="author" content="Zander Martineau"><meta name="geo.region" content="GB"><meta name="geo.placename" content="London"><link rel="me" href="https://github.com/mrmartineau" type="text/html"><!-- Open Graph. These are `property`, not `name` — Facebook, LinkedIn and
2     Slack ignore the `name` spelling, so the share card came out untitled. --><meta property="og:type" content="website"><meta property="og:url" content="https://zander.wtf/search"><meta property="og:site_name" content="Zander Martineau"><meta property="og:locale" content="en_GB"><meta property="og:title" content="Search | Zander Martineau"><meta property="og:description" content="Search blog posts, code notes, projects and more"><meta property="og:image" content="https://zander.wtf/opengraph/search/og.png"><!-- Twitter / X --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="Search | Zander Martineau"><meta name="twitter:description" content="Search blog posts, code notes, projects and more"><meta name="twitter:image" content="https://zander.wtf/opengraph/search/og.png"><link rel="preload" href="/fonts/MozillaText-VF.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="/fonts/AlphaLyrae-Medium.woff2" as="font" type="font/woff2" crossorigin><link rel="preconnect" href="https://icons.duckduckgo.com"><link rel="dns-prefetch" href="https://icons.duckduckgo.com"><link rel="alternate" href="https://zander.wtf/blog.rss.xml" type="application/rss+xml" title="Zander's Blog RSS Feed"><link rel="alternate" href="https://zander.wtf/links.rss.xml" type="application/rss+xml" title="Zander's Link RSS Feed"><link rel="alternate" href="https://zander.wtf/worklog.rss.xml" type="application/rss+xml" title="Zander's Worklog RSS Feed"><link rel="manifest" href="/app.webmanifest"><link rel="apple-touch-icon-precomposed" sizes="500x500" href="/images/favicon/[email protected]"><meta name="theme-color" content="#21262c">
2<script>
3      // The URL prefix picks the front end. Keep in sync with src/utils/uiMode.ts
4      var zmMode = (location.pathname.match(/^\/(desktop|tui|txt)(?=\/|$)/) || [])[1];
5      document.documentElement.classList.add(zmMode || 'classic');
6      if (zmMode === 'txt') {
7        // Plain text: no stylesheets, ever — the browser's own styles only.
8        var zmStrip = function (root) {
9          root.querySelectorAll('link[rel="stylesheet"], style').forEach(function (el) {
10            el.remove();
11          });
12        };
13        zmStrip(document);
14        new MutationObserver(function (records) {
15          records.forEach(function (r) {
16            r.addedNodes.forEach(function (n) {
17              if (n.nodeType !== 1) return;
18              if (n.matches('link[rel="stylesheet"], style')) n.remove();
19              else zmStrip(n);
20            });
21          });
22        }).observe(document.documentElement, { childList: true, subtree: true });
23        document.addEventListener('DOMContentLoaded', function () {
24          // The greeting belongs to the home page only
25          if (document.body.dataset.slug !== 'home') document.getElementById('greeting')?.remove();
26          // The big name is a full-width SVG; without CSS it swallows the page
27          document.querySelectorAll('.zm-bigname').forEach(function (el) { el.remove(); });
28          // Stay in plain text: site links get the prefix
29          document.querySelectorAll('a[href^="/"]').forEach(function (a) {
30            var href = a.getAttribute('href');
31            if (/^\/(desktop|tui|txt)(\/|$)/.test(href) || /\.[a-z0-9]+$/i.test(href.split(/[?#]/)[0])) return;
32            a.setAttribute('href', '/txt' + (href === '/' ? '/' : href));
33          });
34          // The mode card was built for the website; here, plain text is
35          // current and the website is a link back
36          var plain = location.pathname.replace(/^\/txt(?=\/|$)/, '') || '/';
37          document.querySelectorAll('.zm-modes').forEach(function (card) {
38            var site = card.querySelector('.zm-mode.is-current');
39            var txt = card.querySelector('a.zm-mode[href^="/txt"]');
40            var here = card.querySelector('.zm-mode-here');
41            if (!site || !txt) return;
42            var link = document.createElement('a');
43            link.className = 'zm-mode';
44            link.href = plain;
45            link.innerHTML = site.innerHTML;
46            link.querySelector('.zm-mode-here')?.remove();
47            site.replaceWith(link);
48            var current = document.createElement('div');
49            current.className = 'zm-mode is-current';
50            current.setAttribute('aria-current', 'true');
51            current.innerHTML = txt.innerHTML;
52            if (here) current.querySelector('div, span').append(here);
53            txt.replaceWith(current);
54          });
55        });
56      }
57    </script>
57<style>.zm-block[data-astro-cid-rsd2vusr]{--block-bg: var(--bg-block);--block-padding: var(--space-m-l);--block-colour: var(--colour-text);color:var(--block-colour);border-radius:var(--block-radius);background-color:var(--block-bg);padding:var(--block-padding);height:100%}.zm-block[data-astro-cid-rsd2vusr] a[data-astro-cid-rsd2vusr]{--colour: var(--colour-text-bright);--colour-decoration: transparent}header[data-astro-cid-rsd2vusr]{margin-block-end:var(--space-s)}.zm-block-title[data-astro-cid-rsd2vusr]{font-variation-settings:"wght" 500;font-size:var(--step-1);color:var(--colour-text-bright)}.zm-block-subtitle[data-astro-cid-rsd2vusr]{margin-block-start:var(--space-3xs)}.zm-note-items[data-astro-cid-rrqzcqar]{container:note-item / inline-size;display:flex;flex-direction:column;gap:var(--space-2xs)}.zm-note-item[data-astro-cid-rrqzcqar]{border-radius:var(--space-2xs);transition:background-color .2s ease-in-out;text-decoration:none;color:inherit}.zm-note-item[data-astro-cid-rrqzcqar]:hover{background-color:var(--bg-block)}.title[data-astro-cid-rrqzcqar]{font-weight:600;line-height:1.3;display:block;flex-shrink:0;padding:var(--space-4xs) 0}.emoji[data-astro-cid-rrqzcqar]{margin-inline-end:var(--space-3xs)}.tags[data-astro-cid-rrqzcqar]{display:flex;align-items:center;gap:.25rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.date[data-astro-cid-rrqzcqar]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.7;font-size:var(--step--2)}@container note-item (min-width: 480px){.date[data-astro-cid-rrqzcqar]{flex-shrink:0;margin-block-start:0}}
58.zm-blog-items[data-astro-cid-35dpazjw]{container:blog-item / inline-size;display:flex;flex-direction:column;gap:var(--space-l)}.title[data-astro-cid-35dpazjw]{line-height:1.2;display:block;margin-block-end:var(--space-2xs);font-size:var(--step-0);font-family:var(--font-headings)}.subtitle[data-astro-cid-35dpazjw]{font-size:var(--step--1);font-variation-settings:"wght" 200}.is-article[data-astro-cid-35dpazjw]{padding:var(--space-s);border-radius:1rem;background-color:var(--bg-article);rotate:var(--tilt, 0deg);transition:rotate .2s ease-in-out}.is-article[data-astro-cid-35dpazjw]:hover{rotate:0deg}.is-article[data-astro-cid-35dpazjw] .title[data-astro-cid-35dpazjw]{font-size:var(--step-2)}.is-article[data-astro-cid-35dpazjw] .subtitle[data-astro-cid-35dpazjw]{font-size:var(--step-0)}.is-worklog[data-astro-cid-35dpazjw]{--mono-scale: .9;scroll-margin-block-start:var(--space-m)}.is-worklog[data-astro-cid-35dpazjw] .title[data-astro-cid-35dpazjw],.is-worklog[data-astro-cid-35dpazjw] .flow[data-astro-cid-35dpazjw]{font-family:var(--font-mono)}.is-worklog[data-astro-cid-35dpazjw] .title[data-astro-cid-35dpazjw]{font-size:calc(var(--step-0) * var(--mono-scale))}.is-worklog[data-astro-cid-35dpazjw] .flow[data-astro-cid-35dpazjw]{font-size:var(--step--2)}.is-worklog[data-astro-cid-35dpazjw] .flow[data-astro-cid-35dpazjw] pre.astro-code{font-size:.875rem}.label[data-astro-cid-35dpazjw]{text-transform:uppercase;letter-spacing:.06em;font-size:var(--step--2);font-family:var(--font-mono);margin-inline-start:var(--space-2xs)}.date[data-astro-cid-35dpazjw]{font-family:var(--font-mono);opacity:.7;font-feature-settings:"calt" 1,"liga" 1,"rlig" 1,"rvrn" 1,"kern" 1,"rclt" 1,"tnum" 1;font-size:var(--step--1)}@container blog-item (min-width: 480px){.zm-blog-item[data-astro-cid-35dpazjw]{display:flex;gap:var(--space-xs)}.info[data-astro-cid-35dpazjw]{order:2}.date[data-astro-cid-35dpazjw]{min-width:9rem;order:1;font-size:unset;line-height:1.2;flex-shrink:0}.label[data-astro-cid-35dpazjw]{display:block;margin-inline-start:0;margin-block-start:var(--space-3xs)}.is-article[data-astro-cid-35dpazjw]{margin-inline:calc(var(--space-s) * -1)}}
59@keyframes astroFadeInOut{0%{opacity:1}to{opacity:0}}@keyframes astroFadeIn{0%{opacity:0;mix-blend-mode:plus-lighter}to{opacity:1;mix-blend-mode:plus-lighter}}@keyframes astroFadeOut{0%{opacity:1;mix-blend-mode:plus-lighter}to{opacity:0;mix-blend-mode:plus-lighter}}@keyframes astroSlideFromRight{0%{transform:translate(100%)}}@keyframes astroSlideFromLeft{0%{transform:translate(-100%)}}@keyframes astroSlideToRight{to{transform:translate(100%)}}@keyframes astroSlideToLeft{to{transform:translate(-100%)}}@media(prefers-reduced-motion){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}[data-astro-transition-scope]{animation:none!important}}
60.search-form[data-astro-cid-s6z2d6yt]{display:flex;align-items:center;gap:var(--space-xs);width:100%}.search-input[data-astro-cid-s6z2d6yt]{appearance:none;border:0;display:block;border-radius:0;line-height:1.4rem;padding:var(--space-2xs) var(--space-xs);width:100%;background:transparent;font-size:var(--step-1);border-bottom:2px solid var(--colour-muted)}.search-input[data-astro-cid-s6z2d6yt]:focus{border-bottom:2px solid var(--colour-accent);outline:none}.search-input[data-astro-cid-s6z2d6yt]::placeholder{color:var(--colour-text);opacity:.5}.search-icon[data-astro-cid-s6z2d6yt]{opacity:.5;pointer-events:none;font-size:2rem}
61.badge[data-astro-cid-622nxk7t]{display:inline-flex;flex-shrink:0;border-radius:9999px;--tw-bg-opacity: 1;
61background-color:rgb(228 228 231 / var(--tw-bg-opacity, 1));padding:.125rem .625rem;font-size:var(--step--2);line-height:1rem;text-decoration:none;font-weight:400;font-family:var(--font-mono);font-size:var(--step--3)}
62</style>
63<link rel="stylesheet" href="/_astro/_slug_.BWZKSHqd.css">
64<style>.search-page[data-astro-cid-ipsxrsrh]{display:flex;flex-direction:column;gap:var(--space-m)}.filters[data-astro-cid-ipsxrsrh]{display:flex;flex-wrap:wrap;gap:var(--space-2xs)}.filter[data-astro-cid-ipsxrsrh]{display:inline-flex;padding:.125rem .625rem;border-radius:99px;border:1px solid var(--colour-muted);font-family:var(--font-mono);font-size:var(--step--2);text-decoration:none}.filter[data-astro-cid-ipsxrsrh]:hover{color:var(--colour-accent);border-color:var(--colour-accent)}.filter[data-astro-cid-ipsxrsrh].active{border-color:var(--colour-accent);color:var(--colour-accent)}.search-summary[data-astro-cid-ipsxrsrh]{opacity:.8}.search-summary[data-astro-cid-ipsxrsrh] strong[data-astro-cid-ipsxrsrh]{color:var(--colour-accent)}.error[data-astro-cid-ipsxrsrh]{color:var(--colour-error, #ef4444)}.zm-search-items[data-astro-cid-ipsxrsrh]{container:search-item / inline-size;display:flex;flex-direction:column;gap:var(--space-s)}.title[data-astro-cid-ipsxrsrh]{line-height:1.2;display:block;margin-block-end:var(--space-3xs)}.emoji[data-astro-cid-ipsxrsrh]{margin-inline-end:var(--space-3xs)}.snippet[data-astro-cid-ipsxrsrh]{opacity:.7;font-size:var(--step--1);line-height:1.4}.snippet[data-astro-cid-ipsxrsrh] mark{background-color:var(--colour-accent);color:var(--bg);padding-inline:.1em}.meta[data-astro-cid-ipsxrsrh]{display:flex;align-items:center;gap:var(--space-2xs);margin-block-start:var(--space-3xs);align-self:start}.date[data-astro-cid-ipsxrsrh]{opacity:.7;font-size:var(--step--1);font-feature-settings:"calt" 1,"liga" 1,"rlig" 1,"rvrn" 1,"kern" 1,"rclt" 1,"tnum" 1}@container search-item (min-width: 480px){.zm-search-item[data-astro-cid-ipsxrsrh]{display:flex;gap:var(--space-xs);justify-content:space-between}.info[data-astro-cid-ipsxrsrh]{order:1}.meta[data-astro-cid-ipsxrsrh]{order:2;flex-shrink:0;margin-block-start:0}}.search-prompt[data-astro-cid-ipsxrsrh]{opacity:.7}.empty-state[data-astro-cid-ipsxrsrh]{display:grid;grid-template-columns:1fr;gap:var(--space-m);align-items:start}@media(min-width:700px){.empty-state[data-astro-cid-ipsxrsrh]{grid-template-columns:1fr 1fr}}
65h2[data-astro-cid-im4g7foa]{font-size:var(--step-1);font-variation-settings:"wght" 300,"wdth" 100,"ital" 0;line-height:1.1;color:var(--colour-text-bright);margin-block-start:var(--space-xs);opacity:.65}h1[data-astro-cid-azbpcp4f]{font-family:var(--font-headings);font-size:var(--step-5);font-variation-settings:"wght" 900,"wdth" 125,"ital" 10;line-height:1;text-transform:uppercase;letter-spacing:.02em;color:var(--colour-accent)}@media screen and (min-width:700px){h1[data-astro-cid-azbpcp4f]{font-size:var(--step-8)}}header[data-astro-cid-wu5dj4rx]{margin-block-end:var(--space-m)}.zm-articleMetadata[data-astro-cid-wu5dj4rx]{font-family:var(--font-mono)}
66h1[data-astro-cid-guvttfii]{font-family:var(--font-headings);font-size:var(--step-4);font-variation-settings:"wght" 300,"wdth" 100,"ital" 0;line-height:1.1;color:var(--colour-accent)}@media screen and (min-width:700px){h1[data-astro-cid-guvttfii]{font-size:var(--step-4)}}
67</style>
67<script type="module" src="/_astro/page.B1D-nYk3.js"></script>
67</head> <body data-slug="search"> <noscript> <nav class="nojs-nav"> <a href="/">Home</a> <a href="/blog">Blog</a><a href="/projects">Projects</a><a href="/links">Links</a> <a href="/cv">CV/Resume</a><a href="/notes">Code Notes</a><a href="/feeds">Feeds</a><a href="/colophon">Colophon</a><a href="/now">Now</a><a href="/uses">Uses</a><a href="/zed-stack">Zed Stack</a><a href="https://lab.zander.wtf">Lab</a><a href="https://github.com/mrmartineau">GitHub</a><a href="https://bsky.app/profile/zander.wtf">Bluesky</a> </nav> </noscript> <header class="site-header" data-astro-cid-3ef6ksr2> <div class="zm-bigname" data-astro-cid-wlaoyf3i> <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 232 2212 360" data-astro-cid-wlaoyf3i> <path d="M0 592h327.343V464.505H163.265L327.343 113.69V0H10.559v128.307h152.706L0 479.122V592ZM351.266 592h142.147l11.371-97.449h79.602L596.57 592h142.147L646.118 0H442.24l-90.974 592Zm164.89-211.139 14.621-124.246 10.559-121.811h5.686l12.184 120.998 12.996 125.059h-56.046ZM763.275 592h133.211V464.505l-7.31-163.227h4.874L959.843 592h151.897V0H978.525v125.059l7.31 169.723h-5.685L916.793 0H763.275v592ZM1157.51 592h131.59c190.07 0 230.68-120.999 230.68-295.594C1519.78 77.146 1443.43 0 1289.1 0h-131.59v592Zm145.39-127.495v-337.01h12.19c43.86 0 58.48 38.98 58.48 165.663 0 114.502-8.12 171.347-58.48 171.347h-12.19ZM1554.12 592h269.67V464.505h-125.9V349.191h114.53V230.628h-114.53V127.495h125.9V0h-269.67v592ZM1861.1 592h145.4V390.606h20.3c27.62 0 28.43 34.107 28.43 62.53v87.704c0 10.556 1.63 34.919 6.5 51.16h147.02c-3.25-17.053-5.69-34.919-5.69-60.093v-95.013c0-58.469-13.8-111.253-59.29-119.374v-5.685c41.43-14.617 68.23-62.529 68.23-139.676C2212 39.791 2136.46 0 2024.37 0H1861.1v592Zm145.4-315.084V127.495h9.74c34.93 0 49.55 19.49 49.55 74.711 0 47.912-8.93 74.71-48.73 74.71h-10.56Z" data-astro-cid-wlaoyf3i></path> </svg> </div>  <nav data-astro-cid-3ef6ksr2> <ul data-astro-cid-3ef6ksr2> <li data-astro-cid-3ef6ksr2><a href="/" data-astro-cid-3ef6ksr2>Home</a></li> <li data-astro-cid-3ef6ksr2> <a href="/blog" data-astro-cid-3ef6ksr2> Blog </a> </li><li data-astro-cid-3ef6ksr2> <a href="/projects" data-astro-cid-3ef6ksr2> Projects </a> </li><li data-astro-cid-3ef6ksr2> <a href="/links" data-astro-cid-3ef6ksr2> Links </a> </li> <li data-astro-cid-3ef6ksr2> <a href="/search" class="search-link active" aria-label="Search" title="Search (press / anywhere)" data-astro-cid-3ef6ksr2> <i class="ph-duotone ph-magnifying-glass" aria-hidden="true" data-astro-cid-3ef6ksr2></i> <span class="sr-only" data-astro-cid-3ef6ksr2>Search</span> <kbd aria-hidden="true" data-astro-cid-3ef6ksr2>/</kbd> </a> </li> </ul> </nav> </header>  
67<script type="module" src="/_astro/Header.astro_astro_type_script_index_0_lang.D34d4Kqh.js"></script>
67 <!-- prettier-ignore --><div id="greeting" class="zm-greeting" data-astro-cid-prqibpzc> <div class="zm-intro" role="img" aria-label="Hi! I’m Zander, I make web apps and iOS apps and design systems and npm packages and Raycast extensions" data-astro-cid-prqibpzc="true"><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>H</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>i</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>!</span> <span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>I</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>’</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>m</span> <span class="name" data-astro-cid-prqibpzc><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>Z</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>a</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>n</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>d</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>e</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>r</span><img src="/images/avatars/zm-avatar-08-2026.webp" class="avatar" width="180" height="180" alt="Stylised (pixellated) picture of Zander" data-astro-cid-prqibpzc></span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>,</span> <span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>I</span> <span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>m</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>a</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>k</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>e</span> <span class="rotator" data-words="[&#34;web apps&#34;,&#34;iOS apps&#34;,&#34;design systems&#34;,&#34;npm packages&#34;,&#34;Raycast extensions&#34;]" data-astro-cid-prqibpzc><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>w</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>e</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>b</span> <span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>a</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>p</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>p</span><span class="letter" aria-hidden="true" data-astro-cid-prqibpzc>s</span></span></div> <!-- Announces each new word. Polite, so it waits for the reader to pause. --> <p class="visually-hidden" aria-live="polite" aria-atomic="true" data-live data-astro-cid-prqibpzc></p> <button type="button" class="zm-intro-pause" aria-pressed="false" aria-label="Pause the rotating words" hidden data-astro-cid-prqibpzc> <i class="ph-fill ph-pause" aria-hidden="true" data-astro-cid-prqibpzc></i> </button> </div> 
67<script type="module">const S=["ss01","ss02","ss03","ss04","ss05"];const i=document.querySelector(".rotator"),g=document.querySelector("#greeting [data-live]"),r=document.querySelector(".zm-intro-pause"),s=JSON.parse(i?.dataset.words??"[]");for(let t=s.length-1;t>1;t--){const a=1+Math.floor(Math.random()*t);[s[t],s[a]]=[s[a],s[t]]}const u=window.matchMedia("(prefers-reduced-motion: reduce)");if(i&&s.length>1){let t=0,a=!0,n=!1,d;const m=()=>[...i.children],w=e=>{i.replaceChildren(...[...e].map(c=>{const o=document.createElement("span");return o.className="letter",o.setAttribute("aria-hidden","true"),o.textContent=c,o}))},M=()=>{for(const e of m()){const c=S[Math.floor(Math.random()*S.length)];e.style.fontFeatureSettings=Math.random()<.7?`'${c}' 1`:""}},h=()=>{for(const e of m())e.style.fontFeatureSettings=""},L=()=>{const e=performance.now();let c=!1;const o=()=>{const p=performance.now()-e;if(p>=400){h(),f(4e3);return}!c&&p>=400/2&&(t=(t+1)%s.length,w(s[t]),g&&(g.textContent=`I make ${s[t]}`),c=!0),M(),d=window.setTimeout(o,55)};o()},f=e=>{window.clearTimeout(d),!(!a||document.hidden||u.matches||n)&&(d=window.setTimeout(L,e))},y=()=>{window.clearTimeout(d),h()},l=()=>{a&&!document.hidden&&!u.matches&&!n?f(4e3):y()};new IntersectionObserver(([e])=>{a=e.isIntersecting,l()}).observe(i),document.addEventListener("visibilitychange",l),u.addEventListener("change",l),r&&(r.hidden=!1,r.addEventListener("click",()=>{n=!n,r.setAttribute("aria-pressed",String(n)),r.setAttribute("aria-label",n?"Play the rotating words":"Pause the rotating words"),r.querySelector("i")?.classList.toggle("ph-pause",!n),r.querySelector("i")?.classList.toggle("ph-play",n),l()}))}</script>
67  <main id="page">  <div class="zm-contentContainer"> <header data-astro-cid-wu5dj4rx> <h1 data-astro-cid-guvttfii>Search</h1>  <h2 data-astro-cid-im4g7foa>Search blog posts, code notes, projects and more</h2>   </header>   <div class="search-page" data-astro-cid-ipsxrsrh> <!-- The site-wide "/" shortcut (see Header.astro) focuses this input when present --><form action="/search" method="GET" class="search-form" data-astro-cid-s6z2d6yt> <!-- <i class="ph-duotone ph-magnifying-glass search-icon"></i> --> <input type="search" name="q" value placeholder="Search the site..." class="search-input" autofocus autocomplete="off" data-astro-cid-s6z2d6yt> <button type="submit" class="visually-hidden" data-astro-cid-s6z2d6yt>Search</button> </form>   <p class="search-prompt" data-astro-cid-ipsxrsrh>Search blog posts, code notes, projects and more. In the meantime, here's the latest:</p> <div class="empty-state" data-astro-cid-ipsxrsrh> <div class="zm-block" data-astro-cid-rsd2vusr> <header data-astro-cid-rsd2vusr> <h3 class="zm-block-title" data-astro-cid-rsd2vusr>Blog</h3> <p class="zm-block-subtitle" data-astro-cid-rsd2vusr>  </p> </header>  <div class="zm-blog-items" data-astro-cid-35dpazjw> <div class="zm-blog-item" data-astro-cid-35dpazjw> <div class="info" data-astro-cid-35dpazjw> <a href="/blog/reps" class="title" data-astro-cid-35dpazjw data-astro-transition-persist="astro-tt7sz6s3-1"> Reps: Wordle, but with JavaScript </a> <p class="subtitle" data-astro-cid-35dpazjw data-astro-transition-persist="astro-cxa4epkg-2"> A write-up of the interesting parts of the daily JavaScript puzzle game I built in June. Puzzles as YAML data, a Web Worker sandbox, and a CI pipeline that deploys a playable preview of every submitted puzzle. </p> </div> <div class="date" data-astro-cid-35dpazjw data-astro-transition-persist="astro-qyg76mdd-3"> <time datetime="2026-09-24T00:00:00.000Z">24 Sept 2026</time> <span class="label" data-astro-cid-35dpazjw> article </span> </div> </div><div class="zm-blog-item" data-astro-cid-35dpazjw> <div class="info" data-astro-cid-35dpazjw> <a href="/blog/green-claws" class="title" data-astro-cid-35dpazjw data-astro-transition-persist="astro-tt7sz6s3-4"> Green Claws now available on the App Store </a> <p class="subtitle" data-astro-cid-35dpazjw data-astro-transition-persist="astro-cxa4epkg-5"> My third iOS app is out. How a plant list I made because I&#39;m a bad gardener turned into a microsite anyone can generate, and then into Green Claws, an iOS gardening app for the UK. </p> </div> <div class="date" data-astro-cid-35dpazjw data-astro-transition-persist="astro-qyg76mdd-6"> <time datetime="2026-09-23T00:00:00.000Z">23 Sept 2026</time> <span class="label" data-astro-cid-35dpazjw> article </span> </div> </div> </div>  <a href="/blog" class="zm-block-link" data-astro-cid-ipsxrsrh>View all articles →</a>  </div>  <div class="zm-block" data-astro-cid-rsd2vusr> <header data-astro-cid-rsd2vusr> <h3 class="zm-block-title" data-astro-cid-rsd2vusr>Code Notes</h3> <p class="zm-block-subtitle" data-astro-cid-rsd2vusr>  </p> </header>  <div class="zm-note-items" data-astro-cid-rrqzcqar> <a href="/notes/stimulus-cheatsheet" class="zm-note-item flex flex-col gap-1" data-astro-cid-rrqzcqar> <span class="title" data-astro-cid-rrqzcqar>  Stimulus cheatsheet </span> <div class="tags" data-astro-cid-rrqzcqar> <span class="badge" style="background-color: hsla(161,50%,50%,0.6);" data-astro-cid-622nxk7t>javascript</span>  </div> <div class="date" data-astro-cid-rrqzcqar> <time datetime="2026-08-25T00:00:00.000Z">25 Aug 2026</time> </div> </a><a href="/notes/regex" class="zm-note-item flex flex-col gap-1" data-astro-cid-rrqzcqar> <span class="title" data-astro-cid-rrqzcqar> <span class="emoji" data-astro-cid-rrqzcqar>🔍</span> Regular expressions </span> <div class="tags" data-astro-cid-rrqzcqar> <span class="badge" style="background-color: hsla(161,50%,50%,0.6);" data-astro-cid-622nxk7t>javascript</span> <span class="badge" style="background-color: hsla(43,50%,50%,0.6);" data-astro-cid-622nxk7t>typescript</span> <span class="badge" style="background-color: hsla(320,50%,50%,0.6);" data-astro-cid-622nxk7t>cheatsheet</span>  </div> <div class="date" data-astro-cid-rrqzcqar> <time datetime="2026-07-28T00:00:00.000Z">28 Jul 2026</time> </div> </a><a href="/notes/scroll-lock" class="zm-note-item flex flex-col gap-1" data-astro-cid-rrqzcqar> <span class="title" data-astro-cid-rrqzcqar> <span class="emoji" data-astro-cid-rrqzcqar>🔒</span> Locking scroll </span> <div class="tags" data-astro-cid-rrqzcqar> <span class="badge" style="background-color: hsla(235,50%,50%,0.6);" data-astro-cid-622nxk7t>css</span> <span class="badge" style="background-color: hsla(161,50%,50%,0.6);" data-astro-cid-622nxk7t>javascript</span>  </div> <div class="date" data-astro-cid-rrqzcqar> <time datetime="2026-07-21T15:30:00.000Z">21 Jul 2026</time> </div> </a> </div>  <a href="/notes" class="zm-block-link" data-astro-cid-ipsxrsrh>View all notes →</a>  </div>  </div>  </div>  </div>  </main> <div id="status-banner" hidden data-astro-cid-tvtxql23><a href="/cdn-cgi/l/email-protection#9af2f3b1fff4ebeff3e8e3dae0fbf4feffe8b4edeefc" data-astro-cid-tvtxql23><div data-astro-cid-tvtxql23>I'm available for work right now.</div><span data-astro-cid-tvtxql23>
68Get in touch <i class="ph-duotone ph-paper-plane-right" data-astro-cid-tvtxql23></i></span></a><button type="button" aria-label="Hide this banner permanently" title="Hide this banner permanently" data-astro-cid-tvtxql23><i class="ph-fill ph-x-circle" data-astro-cid-tvtxql23></i></button></div>
vendor: 108 bytes, line 68
68<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
68<script type="module">const e=document.getElementById("status-banner");e&&(localStorage.getItem("zm:hide-status")!=="true"&&(e.hidden=!1),e.querySelector("button")?.addEventListener("click",()=>{localStorage.setItem("zm:hide-status","true"),e.hidden=!0}));</script>
68 <footer class="zm-mainContainer" data-astro-cid-sz7xmlte> <div class="grid gap-l" data-astro-cid-sz7xmlte> <nav data-astro-cid-sz7xmlte> <ul class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2xs" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte> <a href="/cv" data-astro-cid-sz7xmlte> CV/Resume  </a> </li><li data-astro-cid-sz7xmlte> <a href="/notes" data-astro-cid-sz7xmlte> Code Notes  </a> </li><li data-astro-cid-sz7xmlte> <a href="/feeds" data-astro-cid-sz7xmlte> Feeds  </a> </li><li data-astro-cid-sz7xmlte> <a href="/colophon" data-astro-cid-sz7xmlte> Colophon  </a> </li><li data-astro-cid-sz7xmlte> <a href="/now" data-astro-cid-sz7xmlte> Now  </a> </li><li data-astro-cid-sz7xmlte> <a href="/uses" data-astro-cid-sz7xmlte> Uses  </a> </li><li data-astro-cid-sz7xmlte> <a href="/zed-stack" data-astro-cid-sz7xmlte> Zed Stack  </a> </li><li data-astro-cid-sz7xmlte> <a href="https://lab.zander.wtf" data-astro-cid-sz7xmlte> Lab <i class="ph-duotone ph-arrow-up-right" data-astro-cid-sz7xmlte></i> </a> </li><li data-astro-cid-sz7xmlte> <a href="https://github.com/mrmartineau" data-astro-cid-sz7xmlte> GitHub <i class="ph-duotone ph-arrow-up-right" data-astro-cid-sz7xmlte></i> </a> </li><li data-astro-cid-sz7xmlte> <a href="https://bsky.app/profile/zander.wtf" rel="me" data-astro-cid-sz7xmlte> Bluesky <i class="ph-duotone ph-arrow-up-right" data-astro-cid-sz7xmlte></i> </a> </li> <li data-astro-cid-sz7xmlte><a href="/ascii" data-astro-cid-sz7xmlte>ASCII mode <i class="ph-duotone ph-terminal" data-astro-cid-sz7xmlte></i></a></li> </ul> </nav> <div data-astro-cid-sz7xmlte> <p data-astro-cid-sz7xmlte>
69&copy; 2026 Zander Martineau • <a href="https://github.com/mrmartineau/zander.wtf/commit/d3cb681
70" class="commit-hash" data-astro-cid-sz7xmlte>#d3cb681
71</a> • This site is always under construction. 🚧
72</p> </div> <section class="zm-modes" aria-label="Ways to view this site" data-astro-cid-6ncj2sss> <p class="zm-modes-title" data-astro-cid-6ncj2sss>This site comes in four flavours.</p> <ul class="zm-modes-options" data-astro-cid-6ncj2sss> <li data-astro-cid-6ncj2sss> <div class="zm-mode is-current" aria-current="true" data-astro-cid-6ncj2sss> <i class="ph-duotone ph-browser" aria-hidden="true" data-astro-cid-6ncj2sss></i> <div data-astro-cid-6ncj2sss> <strong data-astro-cid-6ncj2sss>Website</strong> <span data-astro-cid-6ncj2sss>The ordinary site.</span> <span class="zm-mode-here" data-astro-cid-6ncj2sss> You are here.</span> </div> </div> </li><li data-astro-cid-6ncj2sss> <a class="zm-mode" href="/desktop/search" data-astro-cid-6ncj2sss> <i class="ph-duotone ph-app-window" aria-hidden="true" data-astro-cid-6ncj2sss></i> <div data-astro-cid-6ncj2sss> <strong data-astro-cid-6ncj2sss>Desktop</strong> <span data-astro-cid-6ncj2sss>Windows, a menu bar and Spotlight, like an old Mac.</span> </div> </a> </li><li data-astro-cid-6ncj2sss> <a class="zm-mode" href="/tui/search" data-astro-cid-6ncj2sss> <i class="ph-duotone ph-terminal-window" aria-hidden="true" data-astro-cid-6ncj2sss></i> <div data-astro-cid-6ncj2sss> <strong data-astro-cid-6ncj2sss>Terminal</strong> <span data-astro-cid-6ncj2sss>Keyboard only. Arrow keys, Enter and Esc.</span> </div> </a> </li><li data-astro-cid-6ncj2sss> <a class="zm-mode" href="/txt/search" data-astro-cid-6ncj2sss> <i class="ph-duotone ph-text-aa" aria-hidden="true" data-astro-cid-6ncj2sss></i> <div data-astro-cid-6ncj2sss> <strong data-astro-cid-6ncj2sss>Plain text</strong> <span data-astro-cid-6ncj2sss>No stylesheets. Just the browser defaults.</span> </div> </a> </li> </ul> </section>  </div> </footer> <div class="zm-bigname mt-l" data-astro-cid-wlaoyf3i> <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 2212 400" data-astro-cid-wlaoyf3i> <path d="M0 592h327.343V464.505H163.265L327.343 113.69V0H10.559v128.307h152.706L0 479.122V592ZM351.266 592h142.147l11.371-97.449h79.602L596.57 592h142.147L646.118 0H442.24l-90.974 592Zm164.89-211.139 14.621-124.246 10.559-121.811h5.686l12.184 120.998 12.996 125.059h-56.046ZM763.275 592h133.211V464.505l-7.31-163.227h4.874L959.843 592h151.897V0H978.525v125.059l7.31 169.723h-5.685L916.793 0H763.275v592ZM1157.51 592h131.59c190.07 0 230.68-120.999 230.68-295.594C1519.78 77.146 1443.43 0 1289.1 0h-131.59v592Zm145.39-127.495v-337.01h12.19c43.86 0 58.48 38.98 58.48 165.663 0 114.502-8.12 171.347-58.48 171.347h-12.19ZM1554.12 592h269.67V464.505h-125.9V349.191h114.53V230.628h-114.53V127.495h125.9V0h-269.67v592ZM1861.1 592h145.4V390.606h20.3c27.62 0 28.43 34.107 28.43 62.53v87.704c0 10.556 1.63 34.919 6.5 51.16h147.02c-3.25-17.053-5.69-34.919-5.69-60.093v-95.013c0-58.469-13.8-111.253-59.29-119.374v-5.685c41.43-14.617 68.23-62.529 68.23-139.676C2212 39.791 2136.46 0 2024.37 0H1861.1v592Zm145.4-315.084V127.495h9.74c34.93 0 49.55 19.49 49.55 74.711 0 47.912-8.93 74.71-48.73 74.71h-10.56Z" data-astro-cid-wlaoyf3i></path> </svg> </div>   <style>astro-island,astro-slot,astro-static-slot{display:contents}</style>
72<script>(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).only=e;window.dispatchEvent(new Event("astro:only"));})();</script>
72<script>(()=>{var A=Object.defineProperty;var g=(i,o,a)=>o in i?A(i,o,{enumerable:!0,configurable:!0,writable:!0,value:a}):i[o]=a;var d=(i,o,a)=>g(i,typeof o!="symbol"?o+"":o,a);{let i={0:t=>m(t),1:t=>a(t),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(a(t)),5:t=>new Set(a(t)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(t),9:t=>new Uint16Array(t),10:t=>new Uint32Array(t),11:t=>1/0*t},o=t=>{let[l,e]=t;return l in i?i[l](e):void 0},a=t=>t.map(o),m=t=>typeof t!="object"||t===null?t:Object.fromEntries(Object.entries(t).map(([l,e])=>[l,o(e)]));class y extends HTMLElement{constructor(){super(...arguments);d(this,"Component");d(this,"hydrator");d(this,"hydrate",async()=>{var b;if(!this.hydrator||!this.isConnected)return;let e=(b=this.parentElement)==null?void 0:b.closest("astro-island[ssr]");if(e){e.addEventListener("astro:hydrate",this.hydrate,{once:!0});return}let c=this.querySelectorAll("astro-slot"),n={},h=this.querySelectorAll("template[data-astro-template]");for(let r of h){let s=r.closest(this.tagName);s!=null&&s.isSameNode(this)&&(n[r.getAttribute("data-astro-template")||"default"]=r.innerHTML,r.remove())}for(let r of c){let s=r.closest(this.tagName);s!=null&&s.isSameNode(this)&&(n[r.getAttribute("name")||"default"]=r.innerHTML)}let p;try{p=this.hasAttribute("props")?m(JSON.parse(this.getAttribute("props"))):{}}catch(r){let s=this.getAttribute("component-url")||"<unknown>",v=this.getAttribute("component-export");throw v&&(s+=` (export ${v})`),console.error(`[hydrate] Error parsing props for component ${s}`,this.getAttribute("props"),r),r}let u;await this.hydrator(this)(this.Component,p,n,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),this.dispatchEvent(new CustomEvent("astro:hydrate"))});d(this,"unmount",()=>{this.isConnected||this.dispatchEvent(new CustomEvent("astro:unmount"))})}disconnectedCallback(){document.removeEventListener("astro:after-swap",this.unmount),document.addEventListener("astro:after-swap",this.unmount,{once:!0})}connectedCallback(){if(!this.hasAttribute("await-children")||document.readyState==="interactive"||document.readyState==="complete")this.childrenConnectedCallback();else{let e=()=>{document.removeEventListener("DOMContentLoaded",e),c.disconnect(),this.childrenConnectedCallback()},c=new MutationObserver(()=>{var n;((n=this.lastChild)==null?void 0:n.nodeType)===Node.COMMENT_NODE&&this.lastChild.nodeValue==="astro:end"&&(this.lastChild.remove(),e())});c.observe(this,{childList:!0}),document.addEventListener("DOMContentLoaded",e)}}async childrenConnectedCallback(){let e=this.getAttribute("before-hydration-url");e&&await import(e),this.start()}async start(){let e=JSON.parse(this.getAttribute("opts")),c=this.getAttribute("client");if(Astro[c]===void 0){window.addEventListener(`astro:${c}`,()=>this.start(),{once:!0});return}try{await Astro[c](async()=>{let n=this.getAttribute("renderer-url"),[h,{default:p}]=await Promise.all([import(this.getAttribute("component-url")),n?import(n):()=>()=>{}]),u=this.getAttribute("component-export")||"default";if(!u.includes("."))this.Component=h[u];else{this.Component=h;for(let f of u.split("."))this.Component=this.Component[f]}return this.hydrator=p,this.hydrate},e,this)}catch(n){console.error(`[astro-island] Error hydrating ${this.getAttribute("component-url")}`,n)}}attributeChangedCallback(){this.hydrate()}}d(y,"observedAttributes",["props"]),customElements.get("astro-island")||customElements.define("astro-island",y)}})();</script>
72<astro-island uid="1A3teS" component-url="/_astro/Desktop.CDwBa-uR.js" component-export="default" renderer-url="/_astro/client.-5aZ-SLx.js" props="{&quot;nav&quot;:[1,[[0,{&quot;text&quot;:[0,&quot;Blog&quot;],&quot;url&quot;:[0,&quot;/blog&quot;]}],[0,{&quot;text&quot;:[0,&quot;Projects&quot;],&quot;url&quot;:[0,&quot;/projects&quot;]}],[0,{&quot;text&quot;:[0,&quot;Links&quot;],&quot;url&quot;:[0,&quot;/links&quot;]}]]],&quot;more&quot;:[1,[[0,{&quot;text&quot;:[0,&quot;CV/Resume&quot;],&quot;url&quot;:[0,&quot;/cv&quot;]}],[0,{&quot;text&quot;:[0,&quot;Code Notes&quot;],&quot;url&quot;:[0,&quot;/notes&quot;]}],[0,{&quot;text&quot;:[0,&quot;Feeds&quot;],&quot;url&quot;:[0,&quot;/feeds&quot;]}],[0,{&quot;text&quot;:[0,&quot;Colophon&quot;],&quot;url&quot;:[0,&quot;/colophon&quot;]}],[0,{&quot;text&quot;:[0,&quot;Now&quot;],&quot;url&quot;:[0,&quot;/now&quot;]}],[0,{&quot;text&quot;:[0,&quot;Uses&quot;],&quot;url&quot;:[0,&quot;/uses&quot;]}],[0,{&quot;text&quot;:[0,&quot;Zed Stack&quot;],&quot;url&quot;:[0,&quot;/zed-stack&quot;]}],[0,{&quot;text&quot;:[0,&quot;Lab&quot;],&quot;url&quot;:[0,&quot;https://lab.zander.wtf&quot;],&quot;external&quot;:[0,true]}],[0,{&quot;text&quot;:[0,&quot;GitHub&quot;],&quot;url&quot;:[0,&quot;https://github.com/mrmartineau&quot;],&quot;external&quot;:[0,true]}],[0,{&quot;text&quot;:[0,&quot;Bluesky&quot;],&quot;url&quot;:[0,&quot;https://bsky.app/profile/zander.wtf&quot;],&quot;rel&quot;:[0,&quot;me&quot;],&quot;external&quot;:[0,true]}]]]}" ssr client="only" opts="{&quot;name&quot;:&quot;Desktop&quot;,&quot;value&quot;:&quot;solid-js&quot;}"></astro-island> <astro-island uid="lrCEv" component-url="/_astro/Tui.Bf44HOvL.js" component-export="default" renderer-url="/_astro/client.-5aZ-SLx.js" props="{&quot;nav&quot;:[1,[[0,{&quot;text&quot;:[0,&quot;Blog&quot;],&quot;url&quot;:[0,&quot;/blog&quot;]}],[0,{&quot;text&quot;:[0,&quot;Projects&quot;],&quot;url&quot;:[0,&quot;/projects&quot;]}],[0,{&quot;text&quot;:[0,&quot;Links&quot;],&quot;url&quot;:[0,&quot;/links&quot;]}]]],&quot;more&quot;:[1,[[0,{&quot;text&quot;:[0,&quot;CV/Resume&quot;],&quot;url&quot;:[0,&quot;/cv&quot;]}],[0,{&quot;text&quot;:[0,&quot;Code Notes&quot;],&quot;url&quot;:[0,&quot;/notes&quot;]}],[0,{&quot;text&quot;:[0,&quot;Feeds&quot;],&quot;url&quot;:[0,&quot;/feeds&quot;]}],[0,{&quot;text&quot;:[0,&quot;Colophon&quot;],&quot;url&quot;:[0,&quot;/colophon&quot;]}],[0,{&quot;text&quot;:[0,&quot;Now&quot;],&quot;url&quot;:[0,&quot;/now&quot;]}],[0,{&quot;text&quot;:[0,&quot;Uses&quot;],&quot;url&quot;:[0,&quot;/uses&quot;]}],[0,{&quot;text&quot;:[0,&quot;Zed Stack&quot;],&quot;url&quot;:[0,&quot;/zed-stack&quot;]}],[0,{&quot;text&quot;:[0,&quot;Lab&quot;],&quot;url&quot;:[0,&quot;https://lab.zander.wtf&quot;],&quot;external&quot;:[0,true]}],[0,{&quot;text&quot;:[0,&quot;GitHub&quot;],&quot;url&quot;:[0,&quot;https://github.com/mrmartineau&quot;],&quot;external&quot;:[0,true]}],[0,{&quot;text&quot;:[0,&quot;Bluesky&quot;],&quot;url&quot;:[0,&quot;https://bsky.app/profile/zander.wtf&quot;],&quot;rel&quot;:[0,&quot;me&quot;],&quot;external&quot;:[0,true]}]]]}" ssr client="only" opts="{&quot;name&quot;:&quot;Tui&quot;,&quot;value&quot;:&quot;solid-js&quot;}"></astro-island> 
72<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"225ef7a9362a46828626c0cb9752ecf0","r":1,"spa":2}' crossorigin="anonymous"></script>
vendor: 1 bytes, line 72
72
73<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a40d01550f5ef833',t:'MTc5MDM3MDUxNw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
73</body></html> 

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.