<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>al9000.com</title>
  <link href="https://al9000.com/"/>
  <updated>2026-08-06T15:44:31-04:00</updated>
  <author>
    <name>alan w smith</name>
  </author>
  <id>urn:uuid:39128ebc-da76-4085-a176-9e52ca29bddc</id>

  
  <entry>
    <title>Better nom Error Messages with nom_locate</title><link href="https://al9000.com&#x2f;rust&#x2f;nom&#x2f;better-error-messages/"/><id>urn:uuid:7841fc1d-c96d-5c8b-b21a-b5328694c922</id>
    <updated>2026-08-02T14:02:00-04:00</updated>
    <summary><![CDATA[<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="/styles/main.css" />

    <script src="&#x2f;scripts.raw&#x2f;bitty&#x2f;bitty-9.0.0-beta1.source.js" type="module"></script>

<link rel="shortcut icon" href="/favicon.ico" />
<title>Better nom Error Messages with nom_locate</title>
<meta property="og:title" content="Better nom Error Messages with nom_locate" />
<meta name="description" content="from alan w smith" />
<meta property="og:description" content="from alan w smith" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://al9000.com/rss/feed.xml" />
<meta property="og:image" content="https://al9000.com&#x2f;rust&#x2f;nom&#x2f;better-error-messages/og-image.jpg" />
<link rel="apple-touch-icon" sizes="180x180" href="&#x2f;favicons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="16x16" href="&#x2f;favicons/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="&#x2f;favicons/favicon-32x32.png" />
<link rel="manifest" href="&#x2f;favicons/site.webmanifest" />
<link rel="mask-icon" href="&#x2f;favicons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="alternate" type="application/atom+xml" title="al9000.com" href="/rss/feed.xml" />
<link
  rel="site.standard.publication"
  href="at://did:plc:hehia4csii5iipebsgolxxal/site.standard.publication&#x2f;3mp5l453r552a"
/>




    
    
    
    

    


    <style>
    </style>
    
  </head>
  <body class="page">
<noscript>
  <p>
    NOTE: Some pages on this site rely on JavaScript. 
    It's not currently available in your
    browser/reader. Depending on the page,
    some or all of the content may not
    work correctly without it. 
  </p>

</noscript>

    <div class="payload">
      

<header class="default-wrapper xlarge-bottom-margin xlarge-bottom-padding small-font-size">
<noscript>
  <p>
    NOTE: This site use JavaScript which appears to be turned off. 
    Some content will be fine, but some things won't work.
  </p>

</noscript>
  <div class="top-nav">
    <a href="/">home</a>
    <a href="/tools">tools</a>
    <a href="/rss/">rss</a> |
    <a href="https://bittyjs.com/">bitty</a>
  </div>


</header>


<main class="default default-wrapper default-flow">

  <hgroup class="default">
      <div class="title-wrapper">
        <h1>Better nom Error Messages with nom_locate</h1>
      </div>
        <div class="date">August 2026</div>
  </hgroup>


<p>UPDATE: The original version of this post
only passed the name of the last parser
in the chain. This version is updated
to show all the parsers that lead
to the error.</p>
<h2>Parsing Parser Errors</h2>
<p>I designed a note taking format called
NeoDoc<sup class="footnote-link" id="footnote-link-nd"><a href="#footnote-ref-nd">nd</a></sup>.
It currently exists only as an embedded
feature of my personal static site generator.
I'm in the process of extracting it
to its own library. That means
digging into the <em>nom</em><sup class="footnote-link" id="footnote-link-nom"><a href="#footnote-ref-nom">nom</a></sup>
parser/combinator and its cryptic as
hell error messages.</p>
<p>&quot;Just how cryptic?&quot; you ask. Let me
give you an example.</p>
<h2>A First Look</h2>
<p>This codes makes a tiny rust app that
uses <em>nom</em>'s <code>alt</code> feature to attempt
to use two child parsers to process
a piece of text.</p>
<details><summary>Cargo.toml</summary>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text plain">[package]
<span class="line-marker" data-line="2"></span>name = &quot;default_errors&quot;
<span class="line-marker" data-line="3"></span>version = &quot;0.1.0&quot;
<span class="line-marker" data-line="4"></span>edition = &quot;2024&quot;
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>[dependencies]
<span class="line-marker" data-line="7"></span>nom = &quot;8.0.0&quot;</span></pre></div></div></details>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">branch<span class="punctuation accessor rust">::</span></span>alt<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">bytes<span class="punctuation accessor rust">::</span></span><span class="meta path rust">complete<span class="punctuation accessor rust">::</span></span>tag<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>IResult<span class="punctuation separator rust">,</span> Parser</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span>fs<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="7"></span>  <span class="storage type rust">let</span> input <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>charlie delta<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="8"></span>  <span class="storage type rust">let</span> result <span class="keyword operator rust">=</span> <span class="support function rust">alt</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>alfa<span class="punctuation separator rust">,</span> bravo</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>input</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="9"></span>  <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>write<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>output.txt<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> <span class="support macro rust">format!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{:#?}</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span> result<span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="10"></span>    .<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="11"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="12"></span>
<span class="line-marker" data-line="13"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">alfa</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span><span class="variable parameter rust">input</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">IResult<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span>, <span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="14"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>input<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>xxx<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>input</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="15"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>input<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="16"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="17"></span>
<span class="line-marker" data-line="18"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">bravo</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span><span class="variable parameter rust">input</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">IResult<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span>, <span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="19"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>input<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>yyy<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>input</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="20"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>input<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="21"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<p>The parsers attempt to process the
words &quot;charlie delta&quot; as input. They both fail
since neither of their patterns
(i.e. &quot;xxx&quot; or &quot;yyy&quot;) match the word.
The result is that <em>nom</em>
throws this error:</p>
<section class="output-wrapper"><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">Err(
<span class="line-marker" data-line="2"></span>    Error(
<span class="line-marker" data-line="3"></span>        Error {
<span class="line-marker" data-line="4"></span>            input: &quot;charlie delta&quot;,
<span class="line-marker" data-line="5"></span>            code: Tag,
<span class="line-marker" data-line="6"></span>        },
<span class="line-marker" data-line="7"></span>    ),
<span class="line-marker" data-line="8"></span>)</span></pre></section>
<ul>
<li>
<p>The <code>input: &quot;charlie delta&quot;</code> shows us what
the parser attempted to process.</p>
</li>
<li>
<p>The <code>code: Tag</code> lets us know that the
error was generated because on of the
attempts to use a <code>.tag()</code> failed.</p>
<p>Critically, it doesn't tell us which
one of them failed.</p>
</li>
</ul>
<p>Figuring out the issue in this example is
no big deal. It's quick to see that
neither the <code>alfa</code> nor the <code>bravo</code>
parsers match the &quot;charlie delta&quot;
input passed to them.
Things aren't so obvious in
real world parsers. There are tons
of different functions branching
out and interacting with
each other. It doesn't take long to cross a
threshold where figuring out where
an error occurred is a non-trivial
task.</p>
<p>I used to use a crate called
<em>nom_supreme</em><sup class="footnote-link" id="footnote-link-ns"><a href="#footnote-ref-ns">ns</a></sup>
to help with this. It
provided errors with more details
about where they came from.
Unfortunately, it doesn't
work with the most recent version
of <em>nom</em>.</p>
<p>That's where the <em>nom_locate</em> crate enters
the scene.</p>
<h2>Locating Errors</h2>
<p><em>nom_locate</em><sup class="footnote-link" id="footnote-link-nl"><a href="#footnote-ref-nl">nl</a></sup> works by adding a
<code>LocatedSpan</code> struct to the mix.
Your input goes inside and
gets passed around as a passenger.
For example:</p>
<details><summary>Cargo.toml</summary>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text plain">[package]
<span class="line-marker" data-line="2"></span>name = &quot;locate_basic&quot;
<span class="line-marker" data-line="3"></span>version = &quot;0.1.0&quot;
<span class="line-marker" data-line="4"></span>edition = &quot;2024&quot;
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>[dependencies]
<span class="line-marker" data-line="7"></span>nom = &quot;8.0.0&quot;
<span class="line-marker" data-line="8"></span>nom_locate = &quot;5.0.0&quot;</span></pre></div></div></details>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">bytes<span class="punctuation accessor rust">::</span></span><span class="meta path rust">complete<span class="punctuation accessor rust">::</span></span>tag<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>IResult<span class="punctuation separator rust">,</span> Parser</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom_locate<span class="punctuation accessor rust">::</span></span>LocatedSpan<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span>fs<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="storage type type rust">type</span> <span class="entity name type rust">Content</span><span class="keyword operator rust">&lt;</span><span class="storage modifier lifetime rust">&#39;a</span><span class="keyword operator rust">&gt;</span> <span class="keyword operator rust">=</span> <span class="meta generic rust">LocatedSpan<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage modifier lifetime rust">&#39;a</span> <span class="storage type rust">str</span>, <span class="meta generic rust">Vec<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage modifier lifetime rust">&#39;a</span> <span class="storage type rust">str</span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="9"></span>  <span class="storage type rust">let</span> input <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alfa not bravo<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="10"></span>  <span class="storage type rust">let</span> content <span class="keyword operator rust">=</span> <span class="meta path rust">Content<span class="punctuation accessor rust">::</span></span>new_extra<span class="meta group rust"><span class="punctuation section group begin rust">(</span>input<span class="punctuation separator rust">,</span> <span class="support macro rust">vec!</span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="punctuation section group end rust">]</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="11"></span>  <span class="storage type rust">let</span> result <span class="keyword operator rust">=</span> <span class="support function rust">alfa_parser</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>  <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>write<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>output.txt<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> <span class="support macro rust">format!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{:#?}</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span> result<span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="13"></span>    .<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="14"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="15"></span>
<span class="line-marker" data-line="16"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">alfa_parser</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="17"></span>  <span class="storage modifier rust">mut</span> <span class="variable parameter rust">content</span><span class="punctuation separator rust">:</span> Content
<span class="line-marker" data-line="18"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">IResult<span class="punctuation definition generic begin rust">&lt;</span>Content, <span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="19"></span>  content.extra.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alfa_parser<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="20"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alfa <span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="21"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> bravo_parser.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="22"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="23"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="24"></span>
<span class="line-marker" data-line="25"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">bravo_parser</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="26"></span>  <span class="storage modifier rust">mut</span> <span class="variable parameter rust">content</span><span class="punctuation separator rust">:</span> Content
<span class="line-marker" data-line="27"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">IResult<span class="punctuation definition generic begin rust">&lt;</span>Content, <span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="28"></span>  content.extra.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>bravo_parser<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="29"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>xxx<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="30"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="31"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<p>That codes contains an intentional error
where the <code>bravo_parser</code> fails.
This is the error that gets produced:</p>
<section class="output-wrapper"><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">Err(
<span class="line-marker" data-line="2"></span>    Error(
<span class="line-marker" data-line="3"></span>        Error {
<span class="line-marker" data-line="4"></span>            input: LocatedSpan {
<span class="line-marker" data-line="5"></span>                offset: 5,
<span class="line-marker" data-line="6"></span>                line: 1,
<span class="line-marker" data-line="7"></span>                fragment: &quot;not bravo&quot;,
<span class="line-marker" data-line="8"></span>                extra: [
<span class="line-marker" data-line="9"></span>                    &quot;alfa_parser&quot;,
<span class="line-marker" data-line="10"></span>                    &quot;bravo_parser&quot;,
<span class="line-marker" data-line="11"></span>                ],
<span class="line-marker" data-line="12"></span>            },
<span class="line-marker" data-line="13"></span>            code: Tag,
<span class="line-marker" data-line="14"></span>        },
<span class="line-marker" data-line="15"></span>    ),
<span class="line-marker" data-line="16"></span>)</span></pre></section>
<p>The <code>input</code> of the <code>Error</code> now contains a
<code>LocatedSpan</code> with more details about where
the error occurred. The <code>extra</code>
field contains the values we appended
to its Vec on lines 19 and 28. Collectively
they give us the path to the parser
that failed.</p>
<p>That's a huge improvement. And, it gets even
better.</p>
<h2>Showing Off Errors</h2>
<p>We'll use a little more complicated example
to demonstrate what <em>nom_locate</em> can do.
It starts by defining two parser functions:</p>
<details><summary>Cargo.toml</summary>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text plain">[package]
<span class="line-marker" data-line="2"></span>name = &quot;locate_report&quot;
<span class="line-marker" data-line="3"></span>version = &quot;0.1.0&quot;
<span class="line-marker" data-line="4"></span>edition = &quot;2024&quot;
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>[dependencies]
<span class="line-marker" data-line="7"></span>nom = &quot;8.0.0&quot;
<span class="line-marker" data-line="8"></span>nom_locate = &quot;5.0.0&quot;</span></pre></div></div></details>
<div class="highlight-wrapper"><div class="file-name">src/first_parser.rs</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="keyword other rust">crate</span><span class="meta path rust"><span class="punctuation accessor rust">::</span></span>Content<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span><span class="keyword other rust">use</span> <span class="keyword other rust">crate</span><span class="meta path rust"><span class="punctuation accessor rust">::</span></span>second_parser<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">bytes<span class="punctuation accessor rust">::</span></span><span class="meta path rust">complete<span class="punctuation accessor rust">::</span></span>tag<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">character<span class="punctuation accessor rust">::</span></span><span class="meta path rust">complete<span class="punctuation accessor rust">::</span></span>line_ending<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="6"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>IResult<span class="punctuation separator rust">,</span> Parser</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span><span class="meta function rust"><span class="meta function rust"><span class="storage modifier rust">pub</span> <span class="storage type function rust">fn</span> </span><span class="entity name function rust">first_parser</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="9"></span>  <span class="storage modifier rust">mut</span> <span class="variable parameter rust">content</span><span class="punctuation separator rust">:</span> Content
<span class="line-marker" data-line="10"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">IResult<span class="punctuation definition generic begin rust">&lt;</span>Content, Content<span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="11"></span>  content.extra.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>first_parser<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alfa<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="13"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> line_ending.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="14"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> <span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>bravo<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="15"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span>
<span class="line-marker" data-line="16"></span>    second_parser.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="17"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="18"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<p>and</p>
<div class="highlight-wrapper"><div class="file-name">src/second_parser.rs</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="keyword other rust">crate</span><span class="meta path rust"><span class="punctuation accessor rust">::</span></span>Content<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">bytes<span class="punctuation accessor rust">::</span></span><span class="meta path rust">complete<span class="punctuation accessor rust">::</span></span>tag<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>IResult<span class="punctuation separator rust">,</span> Parser</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta function rust"><span class="meta function rust"><span class="storage modifier rust">pub</span> <span class="storage type function rust">fn</span> </span><span class="entity name function rust">second_parser</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="7"></span>  <span class="storage modifier rust">mut</span> <span class="variable parameter rust">content</span><span class="punctuation separator rust">:</span> Content
<span class="line-marker" data-line="8"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">IResult<span class="punctuation definition generic begin rust">&lt;</span>Content, Content<span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="9"></span>  content.extra.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>second_parser<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="10"></span>  <span class="storage type rust">let</span> <span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span>
<span class="line-marker" data-line="11"></span>    <span class="support function rust">tag</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>fail here<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>content<span class="punctuation separator rust">,</span> result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="13"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<p>These are the same basic type of parsers from the
prior example. The big difference is that <code>first_parser</code>
does a little more work to get us down to a second
line before passing off to <code>second_parser</code>.
That'll help demonstrate the error output
of this <em>report</em> function:</p>
<div class="highlight-wrapper"><div class="file-name">src/report.rs</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="keyword other rust">crate</span><span class="meta path rust"><span class="punctuation accessor rust">::</span></span>Content<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta path rust">error<span class="punctuation accessor rust">::</span></span>Error<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span><span class="support type rust">Err</span><span class="punctuation separator rust">,</span> Finish</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom_locate<span class="punctuation accessor rust">::</span></span>LocatedSpan<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="6"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span>fs<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span><span class="storage type type rust">type</span> <span class="entity name type rust">ResultHolder</span><span class="keyword operator rust">&lt;</span><span class="storage modifier lifetime rust">&#39;a</span><span class="keyword operator rust">&gt;</span> <span class="keyword operator rust">=</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span>
<span class="line-marker" data-line="9"></span>  <span class="punctuation section group begin rust">(</span><span class="meta generic rust">Content<span class="punctuation definition generic begin rust">&lt;</span><span class="storage modifier lifetime rust">&#39;a</span><span class="punctuation definition generic end rust">&gt;</span></span>, <span class="meta generic rust">Content<span class="punctuation definition generic begin rust">&lt;</span><span class="storage modifier lifetime rust">&#39;a</span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation section group end rust">)</span>,
<span class="line-marker" data-line="10"></span>  <span class="meta generic rust">Err<span class="punctuation definition generic begin rust">&lt;</span><span class="meta generic rust">Error<span class="punctuation definition generic begin rust">&lt;</span><span class="meta generic rust">LocatedSpan<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage modifier lifetime rust">&#39;a</span> <span class="storage type rust">str</span>, <span class="meta generic rust">Vec<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage modifier lifetime rust">&#39;a</span> <span class="storage type rust">str</span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation definition generic end rust">&gt;</span></span>,
<span class="line-marker" data-line="11"></span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>
<span class="line-marker" data-line="13"></span><span class="meta function rust"><span class="meta function rust"><span class="storage modifier rust">pub</span> <span class="storage type function rust">fn</span> </span><span class="entity name function rust">report</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span><span class="variable parameter rust">result</span><span class="punctuation separator rust">:</span> ResultHolder</span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="14"></span>  <span class="keyword control rust">match</span> result.<span class="support function rust">finish</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="15"></span>    <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">_</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=&gt;</span> <span class="support macro rust">println!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>Parsing successful<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="16"></span>    <span class="support type rust">Err</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>e</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=&gt;</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="17"></span>      <span class="storage type rust">let</span> error_message <span class="keyword operator rust">=</span> <span class="support macro rust">format!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust">
<span class="line-marker" data-line="18"></span>        <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>PARSING ERROR:<span class="constant character escape rust">\n</span>-&gt; <span class="constant other placeholder rust">{}</span><span class="constant character escape rust">\n</span>failed at:<span class="constant character escape rust">\n</span><span class="constant other placeholder rust">{}</span><span class="constant character escape rust">\n</span>on line <span class="constant other placeholder rust">{}</span> column <span class="constant other placeholder rust">{}</span>:<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="19"></span>        e.input.extra.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant character escape rust">\n</span>-&gt; <span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="20"></span>        e.input.<span class="support function rust">fragment</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="21"></span>        e.input.<span class="support function rust">location_line</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="22"></span>        e.input.<span class="support function rust">get_utf8_column</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="23"></span>      <span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="24"></span>      <span class="storage type rust">let</span> error_line <span class="keyword operator rust">=</span> <span class="support type rust">String</span><span class="meta path rust"><span class="punctuation accessor rust">::</span></span>from_utf8<span class="meta group rust"><span class="punctuation section group begin rust">(</span>
<span class="line-marker" data-line="25"></span>        e.input.<span class="support function rust">get_line_beginning</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">to_vec</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="26"></span>      </span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="27"></span>      .<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="28"></span>      <span class="storage type rust">let</span> pointer_line <span class="keyword operator rust">=</span> <span class="support macro rust">format!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust">
<span class="line-marker" data-line="29"></span>        <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{}</span>^<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="30"></span>        <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span> <span class="punctuation definition string end rust">&quot;</span></span>.<span class="support function rust">repeat</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>e.input.<span class="support function rust">get_utf8_column</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">-</span> <span class="constant numeric integer decimal rust">1</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="31"></span>      <span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="32"></span>      <span class="storage type rust">let</span> parts <span class="keyword operator rust">=</span> <span class="meta group rust"><span class="punctuation section group begin rust">[</span>
<span class="line-marker" data-line="33"></span>        error_message.<span class="support function rust">to_string</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="34"></span>        error_line.<span class="support function rust">to_string</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="35"></span>        pointer_line.<span class="support function rust">to_string</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="36"></span>      <span class="punctuation section group end rust">]</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="37"></span>      <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>write<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>output.txt<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> parts.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant character escape rust">\n</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="38"></span>        .<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="39"></span>    </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="40"></span>  </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="41"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<p>Here's the overview of how it works:</p>
<ul>
<li>
<p>The <code>type ResultHolder&lt;'a&gt;</code> lines just keep us from
having to put the entire signature in the function
definition.</p>
</li>
<li>
<p>The <code>result.finish()</code> call on line 14 combines
a couple of different <em>nom</em> error types so they can
be matched in a single call.</p>
</li>
<li>
<p>Line 15 prints a success message of everything
parsed properly.</p>
</li>
<li>
<p>The <code>Err</code> branch that starts on line 16 does
a bunch of formatting to print out a nice
error message.</p>
</li>
<li>
<p>The <code>e.input</code> field from the error contains
the LocatedSpan struct that was passed in
to the report.</p>
<p><code>e.input.extra</code> on line 19 pulls the
vec with the values of the names of
the parsers we added with <code>content.extra.push()</code>
in the parsers.</p>
<p><code>e.input.fragment()</code> on line 20 gets
the text that was attempting to be
parsed where the failure occurred.</p>
<p><code>e.input.location_line()</code> on line 21 gets
the line number from the original input where
the error occured (which will be 2 in our
case since first_parser got us to the second line).</p>
<p><code>e.input.get_utf8_column()</code> on line 22
give us the column of the <code>.location_line()</code>
where the error starts. (There's a similar
<code>.get_column()</code> that can be used if all
you've got is ASCII, but I don't mess with that.)</p>
</li>
<li>
<p>Lines 24-27 contain <code>e.input.get_line_beginning()</code>
that pulls in the full line that the
error occured on. It comes in as <code>&amp;[u8]</code> so the
<code>.to_vec()</code> and <code>String::from_utf8()</code> calls
are used to turn it into text.</p>
</li>
<li>
<p>The rest of the funciton is the formatting
that shows the line where the error
occurred and puts a <code>^</code> under the column
where the error started.</p>
</li>
</ul>
<p>We tie all that toghter in this <em>main.rs</em> file:</p>
<div class="highlight-wrapper"><div class="file-name">src/main.rs</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="meta module rust"><span class="storage type module rust">mod</span> <span class="entity name module rust">first_parser</span><span class="punctuation terminator rust">;</span></span>
<span class="line-marker" data-line="2"></span><span class="meta module rust"><span class="storage type module rust">mod</span> <span class="entity name module rust">report</span><span class="punctuation terminator rust">;</span></span>
<span class="line-marker" data-line="3"></span><span class="meta module rust"><span class="storage type module rust">mod</span> <span class="entity name module rust">second_parser</span><span class="punctuation terminator rust">;</span></span>
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span><span class="keyword other rust">use</span> <span class="meta path rust">first_parser<span class="punctuation accessor rust">::</span></span>first_parser<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="6"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom<span class="punctuation accessor rust">::</span></span>Parser<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="7"></span><span class="keyword other rust">use</span> <span class="meta path rust">nom_locate<span class="punctuation accessor rust">::</span></span>LocatedSpan<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="8"></span><span class="keyword other rust">use</span> <span class="meta path rust">report<span class="punctuation accessor rust">::</span></span>report<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="9"></span><span class="keyword other rust">use</span> <span class="meta path rust">second_parser<span class="punctuation accessor rust">::</span></span>second_parser<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="10"></span>
<span class="line-marker" data-line="11"></span><span class="storage type type rust">type</span> <span class="entity name type rust">Content</span><span class="keyword operator rust">&lt;</span><span class="storage modifier lifetime rust">&#39;a</span><span class="keyword operator rust">&gt;</span> <span class="keyword operator rust">=</span> <span class="meta generic rust">LocatedSpan<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage modifier lifetime rust">&#39;a</span> <span class="storage type rust">str</span>, <span class="meta generic rust">Vec<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage modifier lifetime rust">&#39;a</span> <span class="storage type rust">str</span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>
<span class="line-marker" data-line="13"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="14"></span>  <span class="storage type rust">let</span> input <span class="keyword operator rust">=</span> <span class="meta path rust">Content<span class="punctuation accessor rust">::</span></span>new_extra<span class="meta group rust"><span class="punctuation section group begin rust">(</span>
<span class="line-marker" data-line="15"></span>    <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alfa<span class="constant character escape rust">\n</span>bravo charlie delta<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="16"></span>    <span class="support macro rust">vec!</span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="17"></span>  </span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="18"></span>  <span class="storage type rust">let</span> result <span class="keyword operator rust">=</span> first_parser.<span class="support function rust">parse</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>input</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="19"></span>  <span class="support function rust">report</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>result</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="20"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<p>And, when we run it, we get this:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">PARSING ERROR:
<span class="line-marker" data-line="2"></span>-&gt; first_parser
<span class="line-marker" data-line="3"></span>-&gt; second_parser
<span class="line-marker" data-line="4"></span>failed at:
<span class="line-marker" data-line="5"></span> charlie delta
<span class="line-marker" data-line="6"></span>on line 2 column 6:
<span class="line-marker" data-line="7"></span>bravo charlie delta
<span class="line-marker" data-line="8"></span>     ^</span></pre></div></div>
<p>Orders of magnititude more useful than
the original.</p>
<h2>Outro</h2>
<p>It took an hour or two to figure
out the approach and dial things in.
It took the rest of the day to write
this post. At 8pm I've done
zero work on the parser itself. I'm
cool with that. I'll be able to move
so much faster with these upgraded
error messages. I'll make up
the time in nothing flat.</p>
<p>-a</p>

<div class="end-of-line"></div>


<div class="backmatter default-flow">
    <h2>Endnote</h2>
<ul>
<li>
<p>I'm not knocking
<em>nom</em> for the terse error messages. It's
designed to be as fast as possible.
You can use the error payload to figure
out where issues are. It just takes
a lot more effort.</p>
<p>I expect I'm taking a hit on the parsing
speed by using <em>nom_locate</em>. I can't tell
though. It rips through blog posts so
fast it might as well be instentaneous.</p>
</li>
</ul>
<h2>Footnotes</h2>
<ul>
<li>
<p><a class="footnote-ref" id="footnote-ref-nd" href="#footnote-link-nd">nd</a>
<a href="/neodoc/">NeoDoc</a> is a note taking format. It's similar to
<a href="https://www.markdownguide.org/">Markdown</a>, but much more powerful.
It's currently embedded in my personal
static site generator. I want to be able
to do more with it so I'll pulling it
out to its own library.</p>
</li>
<li>
<p><a class="footnote-ref" id="footnote-ref-nom" href="#footnote-link-nom">nom</a>
<a href="https://docs.rs/nom/latest/nom/">nom</a> is a
<a href="https://en.wikipedia.org/wiki/Parser_combinator">parser combinator</a>
(aka text processig on steriods). The
learning curve is significant. I recommend
against learning it at the same time
you're learning Rust. Ask me how I know.</p>
</li>
<li>
<p><a class="footnote-ref" id="footnote-ref-ns" href="#footnote-link-ns">ns</a>
<a href="https://docs.rs/nom-supreme/latest/nom_supreme/">nom_supreme</a>
was my go to helper for improving
<em>nom</em> error messages in <em>nom</em> v7. It was a
bit tricky to set up though. Even if
it was available in the current
<em>nom</em> v8 I'd probably still use the
<em>nom_locate</em> approach as it's simpler
to get going.</p>
</li>
<li>
<p><a class="footnote-ref" id="footnote-ref-nl" href="#footnote-link-nl">nl</a>
<a href="https://docs.rs/nom_locate/latest/nom_locate/index.html">nom_locate</a>
is my new best friend. Judging by the 30 million
downloads on <a href="https://crates.io/crates/nom_locate">crates.io</a>
it looks like I'm not alone. It's going to save
me sooo much time. It almost feels like cheating.</p>
</li>
</ul>

</div>

</main>

<footer class="default">
  <div>
    from <a href="https://bsky.app/profile/alanwsmith.com">alan w smith</a>
  </div>
  <div>
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  

      
</footer>


    </div>


    <div class="templates" hidden>
      <bitty-9 data-connect="/bits/default.js"></bitty-9>
      <script type="module" src="/bits/components.js"></script>



    </div>
  </body>
</html>
]]></summary>
  </entry>
  
  <entry>
    <title>Week Notes 2026-30</title><link href="https://al9000.com&#x2f;weeknotes&#x2f;2026&#x2f;30/"/><id>urn:uuid:ae90736d-d0a4-5826-9157-d88dcc9d8cf2</id>
    <updated>2026-07-27T07:53:00-04:00</updated>
    <summary><![CDATA[

<h2>Monday, July 27th</h2>
<ul>
<li>I went ahead and bought
<code>neodoc.style</code> for the Neopolitan
lexicon for the AT Proto
Atmosphere.</li>
</ul>
<p>I'm excited to get to work on
it for real when I get
back to my house (I'm still
on a road trip helping
a relative move).</p>
<p>time passes...</p>
<p>scratch that. I set up the
<a href="https://neodoc.style/">home page</a>
and <a href="https://bsky.app/profile/neodoc.style">a bluesky</a>
account.</p>
<p>The idea is singing in my head.
I could see it doing really well.
(I don't think I'm getting manic,
but it's a big idea in the
grandeous sense)</p>
<ul>
<li>I didn't do much on the color
picker today. All my dev time
went into the neodoc site.</li>
</ul>
<p>I want to get that wrapped
up, but my brain latched
onto getting the first
iteration of the neodoc
site out.</p>
<p>By the way, Neopolitan is
officially renamed to Neodoc
now.</p>
<ul>
<li>
<p>Did some family moving stuff
to.</p>
</li>
<li>
<p>I didn't bring my good headphones
with me on the trip. Just earbuds.
The air handler of the place I'm
staying is super loud. Enough
that it bugs me. Went out
and got a pair of cheap headphones
yesterday from target. I mean,
$10 cheap. They sound pretty
good. They get uncomfortable after
a bit though. Worth it to block
out the noise from the A/C.</p>
</li>
</ul>
<h2>Wednesday, July 29th</h2>
<ul>
<li>
<p>Did the 10 hour drive to return home.
Was listening to music and thinking
about NeoDoc the entire time.
(You can always tell when I'm
deep in though on a road trip
if I don't to any podcasts
or audio books.)</p>
</li>
<li>
<p>Ended up streaming a little
bit and started working on
a new extract for the NeoDoc
parser.</p>
</li>
</ul>
<h2>Thursday, July 30th</h2>
<ul>
<li>
<p>A little more work on the
parser.</p>
</li>
<li>
<p>Went to the retirement
party for the last boss I
had at the PGA TOUR. Couldn't
have asked to work for a
better dude. Even at the party
he was saying that he didn't
do anything but try to clear
the way for us to do our work.</p>
</li>
</ul>
<p>Which, I don't think you could
ask for a better approach.</p>
<p>And, as someone pointed out
there was <strong>a lot</strong> of stuff to
clear.</p>
<h2>The Rest of the Week</h2>
<ul>
<li>Launched <a href="https://neodoc.style/">NeoDoc.style</a>
and <a href="https://bsky.app/profile/neodoc.style">neodoc.style</a>.</li>
</ul>
<p>Spent most of my energy writing
and not as much on the parser.
That's fine, but I'm ready to
get back to extracting the
parser so I can start building
on top of it.</p>


]]></summary>
  </entry>
  
  <entry>
    <title>Week Notes 2026-29</title><link href="https://al9000.com&#x2f;weeknotes&#x2f;2026&#x2f;29/"/><id>urn:uuid:e22111ac-a070-50cf-8782-8f9c75348c9a</id>
    <updated>2026-07-22T16:44:29-04:00</updated>
    <summary><![CDATA[

<h2>Monday - June 20</h2>
<ul>
<li>Wrote <a href="/rust/apps/base32_timestamp_cleanup/">a script</a>
to update the IDs for my sites
pages to make them sort chronologically.
I though I has them set up that way.
There was a bug that means sorting
got messed up if the IDs had numbers
in them (which a high portion will have).</li>
</ul>
<h2>Tuesday - June 21</h2>
<ul>
<li>
<p>Set up Static Site Builder
9000 to automatically
generate Open Graph Image
(i.e. the images that show up
when you post a link on
a social media site). The
text for each is the
title of the post/page
they are associated with.</p>
<p>I did the work on stream
which was a good time. It
turned out to be more
straight-forward than I
had expected. All thanks
to <a href="https://imagemagick.org/">ImageMagick</a>.</p>
<p>I still need to get things
set up to automatically read
alt text from the image files.
That's pretty high on the TODO
list.</p>
</li>
<li>
<p>Migrated my <a href="/texture-maker">Background
Texture Maker</a>
to al9000.com. I cleaned it
up a little in the process
by moving the SVG that's used
for the texture into a variable.
Don't make any real difference.
Just more idiomatic.</p>
</li>
</ul>
<h2>Wednesday - June 22</h2>
<ul>
<li>
<p>Spent some time working on my
new <a href="/color-picker">color picker</a>.
I think it's the fourth one I've
made. Maybe the fifth. I've
got a good feeling about this one.</p>
</li>
<li>
<p>Realized that this new al9000.com
site has light and dark mode in the
style sheet. I though it was just
dark mode because my system setting
are set to that so that's all
I saw. (Since I haven't built a
manual switch in yet, there's no
way to change).</p>
</li>
</ul>
<p>Oops.</p>
<p>I've temporarily set the dark
mode styles to point to light
mode so everything works the same.</p>
<h2>Thursday - July 23</h2>
<ul>
<li>
<p>Did a bunch of work on the
<a href="/color-picker">Color Picker</a>.
The initial mechanics were mostly
done so this was mainly design
and layout work. It's making
good progress.</p>
</li>
<li>
<p>I made some changes to
Static Site Generator 9000.
Mainly, I change the way
I access data from JSON and
content files. I used to break
things up as keys like.</p>
<p>d.some.path.to.index.title</p>
<p>The <code>index</code> is really <code>index.html</code>
but I removed the extension.
I did that originally to
keep from having to use brackets
around the keys like this:</p>
<p>d.some.path.to[&quot;index.html&quot;].title</p>
<p>Because the <code>.</code> in the filename would
have been seen as a new level.
It's generally fine since there aren't
two files at that same place, but
depending on how I implement
<a href="/neopoligen">Neopoligen</a> that
may not be the case. Still TBD,
but I wanted to fix it now.</p>
<p>Also, going key by key is a pain.
For example, if I'm doing a for loop
with file paths like</p>
<p>/some/path/to/index.html</p>
<p>I have to do:</p>
<p>d.some.path.to[&quot;index.html&quot;].title</p>
<p>I realized there's no reason not
to just use the file path itself
as the key. So, now I do this:</p>
<p>d[&quot;/some/path/to/index.html&quot;].title</p>
<p>Much nicer.</p>
</li>
</ul>
<h2>Friday - June 24</h2>
<ul>
<li>
<p>Road tripping.</p>
</li>
<li>
<p>Listened to a Shot Talk Show
podcast episode with Dan Abramov
talking about AT Proto and
the Atmosphere. It started me
thinking about making a lexicon
for Neopolitan.</p>
</li>
</ul>
<h2>Sunday - June 26</h2>
<ul>
<li>
<p>I'm on a road trip. Helping a family
member finish up a move.</p>
</li>
<li>
<p>Over the past few days I've
been thinking a lot about Neopolitan
and the AT Proto Atmosphere. The idea
is more and more solid in my brain.
I've started writing up notes
about how it'll work.</p>
</li>
<li>
<p>Spent a bunch of time
working on <a href="/color-picker">my Color Picker</a>.
It's still a work in progress. Even more
so since I've been refactoring it
basically from scratch. The
reason for the overhaul is I've
come up with a better general approach
to naming, initializing, and file storage.
Basically, each component gets its
own <code>.js</code> and <code>.html</code> files that isolate
it from other components.
Then the standard naming convention is for
<code>componentInit</code>, <code>componentSet</code>, and
<code>componentUpdate</code> for the core
functionality.</p>
<p>I'm really liking the approach. It's
a lot easier to keep things focused
in my head.</p>
</li>
<li>
<p>I bought the domain neoprose.com
for the Neopolitan lexicon. I'm
not sure I'm going to use it
though. Thinking about <code>neodoc.style</code>
instead which feels more like
it's focused on the format
than creating a service
(which is how I plan on playing
things)</p>
</li>
</ul>
<h2>Overall</h2>
<ul>
<li>
<p>I did a bunch of work on
Static Site Builder 9000
(which will eventually
<a href="/ssg9000/">be here</a> if it's
not by the time you read this).</p>
<p>It's the new builder I'm
using for al9000.com. I'm really
happy with the way it's shaping
up.</p>
</li>
<li>
<p>I've stream a few times this week.
It's been fun. Definitely
helps me get back into the
swing of working on things.</p>
</li>
</ul>
<p>Hope y'all had a good week and
a better one in the week go come.</p>
<p>-a</p>

]]></summary>
  </entry>
  
  <entry>
    <title>CSS Sticky Sidebar</title><link href="https://al9000.com&#x2f;css&#x2f;sticky-sidebar/"/><id>urn:uuid:651421b9-b836-514d-9fbc-00731124811a</id>
    <updated>2026-07-26T08:09:00-04:00</updated>
    <summary><![CDATA[

<header class="default-wrapper xlarge-bottom-margin xlarge-bottom-padding small-font-size">
<noscript>
  <p>
    NOTE: This site use JavaScript which appears to be turned off. 
    Some content will be fine, but some things won't work.
  </p>

</noscript>
  <div class="top-nav">
    <a href="/">home</a>
    <a href="/tools">tools</a>
    <a href="/rss/">rss</a> |
    <a href="https://bittyjs.com/">bitty</a>
  </div>


</header>

  <main>
    <h1>CSS Sticky Sidebar</h1>
    <div class="package-1">
      <div class="content-1"><p>This is my reference for how to make a non-responsive
layout with a content area and a sticky
sidebar.</p>
<p>The HTML looks like this:</p>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text html basic">  <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">main</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">&gt;</span></span>CSS Sticky Sidebar<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="3"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">package-1</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="4"></span>      <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">content-1</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="5"></span>        <span class="comment block html"><span class="punctuation definition comment begin html">&lt;!--</span> content goes here <span class="punctuation definition comment end html">--&gt;</span></span>
<span class="line-marker" data-line="6"></span>      <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span>      <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">sidebar-1</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="9"></span>        <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="10"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 1<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="11"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 2<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="12"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 3<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="13"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 4<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="14"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 5<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="15"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 6<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="16"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 7<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="17"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 8<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="18"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 9<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="19"></span>          <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>Item 10<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="20"></span>        <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="21"></span>      <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="22"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="23"></span>  <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">main</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
<p>The CSS Looks like this:</p>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source css"><span class="meta selector css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>root</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="2"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">sidebar-width</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">14<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="3"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>package-1</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="6"></span>  <span class="meta property-name css"><span class="support type property-name css">display</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">flex</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="7"></span>  <span class="meta property-name css"><span class="support type property-name css">align-items</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">flex-start</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="8"></span>  <span class="meta property-name css">gap</span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1.5<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="9"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="10"></span>
<span class="line-marker" data-line="11"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>content-1</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="12"></span>  <span class="meta property-name css"><span class="support type property-name css">flex</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="13"></span>  <span class="meta property-name css"><span class="support type property-name css">min-width</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">0</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="14"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="15"></span>
<span class="line-marker" data-line="16"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>sidebar-1</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="17"></span>  <span class="meta property-name css"><span class="support type property-name css">position</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">sticky</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="18"></span>  <span class="meta property-name css"><span class="support type property-name css">flex</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">0</span> <span class="constant numeric css">0</span> <span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">sidebar-width</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="19"></span>  <span class="meta property-name css"><span class="support type property-name css">width</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">sidebar-width</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="20"></span>  <span class="meta property-name css"><span class="support type property-name css">top</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1.5<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="21"></span>  <span class="meta property-name css"><span class="support type property-name css">max-height</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function calc css">calc</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="constant numeric css">100<span class="keyword other unit css">vh</span></span> <span class="keyword operator css">-</span> <span class="constant numeric css">3<span class="keyword other unit css">rem</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="22"></span>  <span class="meta property-name css"><span class="support type property-name css">overflow-y</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">auto</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="23"></span></span><span class="punctuation section property-list css">}</span></span></pre></div></div>
<h2>Details</h2>
<hr />
<p>Flexbox makes child elements the same height
by default. That would mean the sticky
sidebar would take up the same height as
the content which would end up with
a lot of empty space at the end and
prevent the sticky feather from kicking
in. Setting <code>align-items</code> to
<code>flex-start</code> adjusts the behavior of
child elements so they only
take up as much vertical space as
they need.</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="7"></span>  <span class="meta property-name css"><span class="support type property-name css">align-items</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">flex-start</span></span><span class="punctuation terminator rule css">;</span></pre></div></div>
<hr />
<p>The main content area is set up
with <code>flex: 1</code> so that it changes
size dynamically based on how
much space is available after
accounting for the sidebar.
The <code>min-width: 0;</code> line
prevents issues with content
that would otherwise overflow
the content area.</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="11"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>content-1</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="12"></span>  <span class="meta property-name css"><span class="support type property-name css">flex</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="13"></span>  <span class="meta property-name css"><span class="support type property-name css">min-width</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">0</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="14"></span></span><span class="punctuation section property-list css">}</span></pre></div></div>
<hr />
<p>The CSS for the sidebar breaks down like
this:</p>


<ul>
  <li>
    <p>Set the sidebar to be sticky in the viewport.</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="17"></span>  <span class="meta property-name css"><span class="support type property-name css">position</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">sticky</span></span><span class="punctuation terminator rule css">;</span></pre></div></div>  </li>


  <li>
    <p>
      Give it a fixed width.
    </p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="18"></span>  <span class="meta property-name css"><span class="support type property-name css">flex</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">0</span> <span class="constant numeric css">0</span> <span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">sidebar-width</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="19"></span>  <span class="meta property-name css"><span class="support type property-name css">width</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">sidebar-width</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span></pre></div></div>  </li>

  <li>
    <p>
      Use `top` to give it some padding when
      it hits the top of the page. 
    </p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="20"></span>  <span class="meta property-name css"><span class="support type property-name css">top</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1.5<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span></pre></div></div>  </li>
  <li>
    <p>
      Set the max hight of the sidebar to a little
      less than the viewport height and set
      the overflow so it scrolls internally
      if the content exceeds the height.
    </p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="21"></span>  <span class="meta property-name css"><span class="support type property-name css">max-height</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function calc css">calc</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="constant numeric css">100<span class="keyword other unit css">vh</span></span> <span class="keyword operator css">-</span> <span class="constant numeric css">3<span class="keyword other unit css">rem</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="22"></span>  <span class="meta property-name css"><span class="support type property-name css">overflow-y</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">auto</span></span><span class="punctuation terminator rule css">;</span></pre></div></div>  </li>

</ul>


<h2>Outro</h2>
<p>This isn't a responsive design. If you
squish it onto a phone it'll just
squish instead of reorienting itself.
I'm fine with that. It's purpose is
to use with tools designed for a
full size screen.</p>
<p>As with lots of things, this got
way easier to do as CSS continued
to improve. We live in the future,
and some parts of it are very nice.</p>
<p>-a</p>
<h2>Endnotes</h2>
<ul>
<li>
<p>The styles above provide the core layout.
There's a few ancillary styles that make
it look nicer. They also add a lot of
space to the sidebar items to give
it a better shot of needing to scroll.
The extra styles look like this:</p>
</li>
</ul>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="source css"><span class="meta selector css"><span class="entity name tag css">body</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="2"></span>  <span class="meta property-name css"><span class="support type property-name css">font-family</span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant font-name css">system-ui</span><span class="punctuation separator css">,</span> <span class="support constant font-name css">sans-serif</span></span><span class="punctuation terminator rule css">;</span></span>
<span class="line-marker" data-line="3"></span>  <span class="meta property-name css"><span class="support type property-name css">max-width</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css">min(<span class="constant numeric css">52<span class="keyword other unit css">rem</span></span>, <span class="meta function-call css"><span class="support function calc css">calc</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="constant numeric css">100<span class="keyword other unit css">vw</span></span> <span class="keyword operator css">-</span> <span class="constant numeric css">2<span class="keyword other unit css">rem</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span>);
<span class="line-marker" data-line="4"></span>  <span class="meta property-name css"><span class="support type property-name css">margin</span>-inline</span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">auto</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="5"></span>  <span class="meta property-name css"><span class="support type property-name css">background-color</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">default-background-color</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="6"></span>  <span class="meta property-name css"><span class="support type property-name css">color</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">default-base-color</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="7"></span>  <span class="meta property-name css"><span class="support type property-name css">font-size</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">default-font-size</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="8"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="9"></span>
<span class="line-marker" data-line="10"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>sidebar-1</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="11"></span>  <span class="meta property-name css"><span class="support type property-name css">background</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant other color rgb-value css"><span class="punctuation definition constant css">#</span>555</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="12"></span>  <span class="meta property-name css"><span class="support type property-name css">padding</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="13"></span>  <span class="meta property-name css"><span class="support type property-name css">border-radius</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">8<span class="keyword other unit css">px</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="14"></span>  <span class="meta property-name css"><span class="support type property-name css">margin-top</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1.2<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="15"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="16"></span>
<span class="line-marker" data-line="17"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>content-1</span> <span class="entity name tag css">p</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> 
<span class="line-marker" data-line="18"></span>  <span class="meta property-name css"><span class="support type property-name css">margin-bottom</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="19"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="20"></span>
<span class="line-marker" data-line="21"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>sidebar-1</span> <span class="entity name tag css">ul</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> 
<span class="line-marker" data-line="22"></span>  <span class="meta property-name css"><span class="support type property-name css">padding</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">0</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="23"></span>  <span class="meta property-name css"><span class="support type property-name css">list-style</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="24"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="25"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>sidebar-1</span> <span class="entity name tag css">li</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> 
<span class="line-marker" data-line="26"></span>  <span class="meta property-name css"><span class="support type property-name css">min-height</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">8<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="27"></span>  <span class="meta property-name css"><span class="support type property-name css">padding</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">0.5<span class="keyword other unit css">rem</span></span> <span class="constant numeric css">0</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="28"></span>  <span class="meta property-name css"><span class="support type property-name css">border-bottom</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">1<span class="keyword other unit css">px</span></span> <span class="support constant property-value css">solid</span> <span class="constant other color rgb-value css"><span class="punctuation definition constant css">#</span>d0d7d9</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="29"></span></span><span class="punctuation section property-list css">}</span></span></pre></div></div>
      </div>

      <div class="sidebar-1">
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 6</li>
          <li>Item 7</li>
          <li>Item 8</li>
          <li>Item 9</li>
          <li>Item 10</li>
        </ul>
      </div>
    </div>
  </main>
<footer class="default">
  <div>
    from <a href="https://bsky.app/profile/alanwsmith.com">alan w smith</a>
  </div>
  <div>
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  

      
</footer>


]]></summary>
  </entry>
  
  <entry>
    <title>A CSS Only Tabs Prototype (No JavaScript Required)</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n6&#x2f;a8&#x2f;6j/"/><id>urn:uuid:da7607ba-0815-5430-bf31-43f72931a57c</id>
    <updated>2026-07-25T16:47:14-04:00</updated>
    <summary><![CDATA[

<div class="warning-block">
  <p>
    Head's Up
  </p>
  <p>
    This is prototype testing code to see how
    this could work. According to <a href="https://adrianroselli.com/2023/03/css-only-widgets-are-inaccessible.html#Tabs">this post</a>
    it's not accessible. That's not really a surprise. 
    So, treat this as an interesting experiment instead
    of something to actually implement.
    I got pointed to 
    <a href="https://inclusive-components.design/tabbed-interfaces/">
      Tabbed Interfaces on inclusive-components.design</a>
    for an actual alternative.
  </p>
</div>
<h2>Component Kickoff</h2>
<p>I was listening to an episode of <a href="https://shoptalkshow.com/">Shop Talk Show</a>
that discussed putting native HTML elements inside
web components instead of having
the component insert them. For example,
a <em>fancy-checkbox</em> component could contain
a checkbox element:</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag custom html">fancy-checkbox</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">label</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">for</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>checkbox-x<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Show Example<span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">label</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="3"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">input</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">checkbox-x</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>checkbox<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html"> /&gt;</span></span>
<span class="line-marker" data-line="4"></span><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag custom html">fancy-checkbox</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
<p>Or, it could be empty, pushing the responsibility
for adding the checkbox element into
the component itself.</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag custom html">fancy-checkbox</span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag custom html">fancy-checkbox</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
With the first one, a checkbox shows up even if JavaScript
or the web component fails to load. Not so with the second.
<h2>Modal Pondering</h2>
<p>The conversation got me wondering what you can do
with a checkbox if there's no JavaScript running on the
page. Specifically, I was wondering if you could do something
like make a dark mode switcher using only
HTML and CSS. The answer is, yes, you can.</p>
<p>Check this out:</p>
<div class="mode-wrapper-x">
  <label for="mode-checkbox-x">
    Activate Dark Mode:
  </label>
  <input id="mode-checkbox-x" type="checkbox" />
</div>
<p>There's no JavaScript involved. Everything happens
thanks to this HTML:</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">mode-wrapper-x</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">label</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">for</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>mode-checkbox-x<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="3"></span>    Activate Dark Mode:
<span class="line-marker" data-line="4"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">label</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="5"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">input</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">mode-checkbox-x</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>checkbox<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html"> /&gt;</span></span>
<span class="line-marker" data-line="6"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
<p>and this CSS:</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="source css"><span class="meta selector css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>root</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="2"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">mode-wrapper-background-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant color w3c-standard-color-name css">white</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="3"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">mode-wrapper-color-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant color w3c-standard-color-name css">black</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="4"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta selector css"><span class="entity other attribute-name class css"><span class="punctuation definition entity css">.</span>mode-wrapper-x</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="7"></span>  <span class="meta property-name css"><span class="support type property-name css">background-color</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">mode-wrapper-background-x</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="8"></span>  <span class="meta property-name css"><span class="support type property-name css">color</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">mode-wrapper-color-x</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="9"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="10"></span>
<span class="line-marker" data-line="11"></span><span class="meta selector css"><span class="entity name tag css">body</span><span class="meta function-call css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>has</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>mode-checkbox-x</span><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>checked</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="12"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">mode-wrapper-background-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant color w3c-standard-color-name css">black</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="13"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">mode-wrapper-color-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant color w3c-standard-color-name css">white</span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="14"></span></span><span class="punctuation section property-list css">}</span></span></pre></div></div>
<p>The magic is the <code>:has()</code> pseudo-class on the
body element on line 11. It watches the <code>#mode-checkbox-x</code> element
to see if it's check. When it is, it overrides
the default property variables to do the switch.</p>
<h2>Tab Coded</h2>
<p>Of course, the dark mode switcher doesn't set
anything on the browser to maintain the mode
between pages. You would need JavaScript for that.</p>
<p>However, there are other things that
don't require keeping track of state
across pages. Tabs come to mind.
For example:</p>

<div class="tabs-wrapper-x">
<div>
  <input id="tab1" type="radio" name="tabSwtich" checked />
  <label for="tab1" >Tab 1</label>

  <input id="tab2" type="radio" name="tabSwtich" />
  <label for="tab2">Tab 2</label>

  <input id="tab3" type="radio" name="tabSwtich" />
  <label for="tab3">Tab 3</label>
</div>

<div id="content1">Content 1</div>
<div id="content2">Content 2</div>
<div id="content3">Content 3</div></div>

<p>Again, no JavaScript. Just this HTML:</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">input</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">tab1</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>radio<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">name</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>tabSwtich<span class="punctuation definition string end html">&quot;</span></span></span> <span class="entity other attribute-name html">checked</span><span class="punctuation definition tag end html"> /&gt;</span></span>
<span class="line-marker" data-line="3"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">label</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">for</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>tab1<span class="punctuation definition string end html">&quot;</span></span></span> <span class="punctuation definition tag end html">&gt;</span></span>Tab 1<span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">label</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">input</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">tab2</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>radio<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">name</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>tabSwtich<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html"> /&gt;</span></span>
<span class="line-marker" data-line="6"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">label</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">for</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>tab2<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Tab 2<span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">label</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">input</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">tab3</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>radio<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">name</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>tabSwtich<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html"> /&gt;</span></span>
<span class="line-marker" data-line="9"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">label</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">for</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>tab3<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Tab 3<span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">label</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="10"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="11"></span>
<span class="line-marker" data-line="12"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">content1</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Content 1<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="13"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">content2</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Content 2<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="14"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">content3</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Content 3<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
<p>and this CSS:</p>
<div class="highlight-wrapper"><div class="code-block no-copy numbers"><pre><span class="line-marker" data-line="1"></span><span class="source css"><span class="meta selector css"><span class="entity name tag css">body</span><span class="meta function-call css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>has</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>tab1</span><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>checked</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> 
<span class="line-marker" data-line="2"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-1-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">block</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="3"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-2-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="4"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-3-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="5"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="6"></span>
<span class="line-marker" data-line="7"></span><span class="meta selector css"><span class="entity name tag css">body</span><span class="meta function-call css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>has</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>tab2</span><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>checked</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> 
<span class="line-marker" data-line="8"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-1-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="9"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-2-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">block</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="10"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-3-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="11"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="12"></span>
<span class="line-marker" data-line="13"></span><span class="meta selector css"><span class="entity name tag css">body</span><span class="meta function-call css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>has</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>tab3</span><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>checked</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> 
<span class="line-marker" data-line="14"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-1-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="15"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-2-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">none</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="16"></span>  <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-3-display-x</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="support constant property-value css">block</span></span><span class="punctuation terminator rule css">;</span> 
<span class="line-marker" data-line="17"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="18"></span>
<span class="line-marker" data-line="19"></span>
<span class="line-marker" data-line="20"></span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>content1</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="21"></span>  <span class="meta property-name css"><span class="support type property-name css">display</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-1-display-x</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="22"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="23"></span>
<span class="line-marker" data-line="24"></span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>content2</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="25"></span>  <span class="meta property-name css"><span class="support type property-name css">display</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-2-display-x</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="26"></span></span><span class="punctuation section property-list css">}</span>
<span class="line-marker" data-line="27"></span>
<span class="line-marker" data-line="28"></span><span class="meta selector css"><span class="entity other attribute-name id css"><span class="punctuation definition entity css">#</span>content3</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span>
<span class="line-marker" data-line="29"></span>  <span class="meta property-name css"><span class="support type property-name css">display</span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="meta function-call css"><span class="support function var css">var</span><span class="meta group css"><span class="punctuation definition group begin css">(</span><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">content-3-display-x</span></span></span><span class="meta group css"><span class="punctuation definition group end css">)</span></span></span></span><span class="punctuation terminator rule css">;</span>
<span class="line-marker" data-line="30"></span></span><span class="punctuation section property-list css">}</span></span></pre></div></div>
<h2>First Try</h2>
<p>To be clear: this is a prototype. It's
purpose is a first test to see what's
possible. There's several things
to investigate, including:</p>
<ul>
<li>
<p>What's the accessibility of this like?
Is it dead on arrival? Are there
adjustments that can be made to bring
it in line?</p>
</li>
<li>
<p>The radio buttons themselves being visible
is pretty ugly. I'm pretty sure they
can be hidden. TBD on what that does
to accessibility.</p>
</li>
<li>
<p>The CSS is pretty verbose. It does an explicit
check for each radio button and updates all
the variables inside each check. I wouldn't
be surprised to learn there's a more
efficient way to do that.</p>
</li>
</ul>
<p>Overall, it's very exciting.
Even if there are reasons not to do
it now, the continuing march of
CSS makes me think it won't be long.</p>
<p>-a</p>

<h2>References</h2>
<ul>
<li>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:has">CSS :has() pseudo-class</a>
which provides the horsepower for the functionality. It hit <em>Baseline Widely Available</em>
in December 2023.</li>
</ul>
<h2>Endnotes</h2>
<ul>
<li>
<p>Thanks to <a href="https://alex.party/">Alex</a> for introducing
me to <code>:has()</code> and showing me how to use it.</p>
</li>
<li>
<p>If you've got feedback on the
accessibility aspects of this approach
please hit me up on <a href="https://bsky.app/profile/alanwsmith.com">Bluesky</a>
or <a href="https://hachyderm.io/deck/@TheIdOfAlan">Mastodon</a></p>
</li>
<li>
<p>Another thing I learned about
is <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button#command">command and commandfor</a>
for buttons. Feels like there's a lot of potential
there in future updates.</p>
</li>
<li>
<p>Another episode of Shop Talk Show was
<a href="https://shoptalkshow.com/724/">an interview</a> with
<a href="https://danabra.mov/">Dan Abramov</a> about
<a href="https://atproto.com/">AT Proto</a>. I'd been
toying with the idea of creating a
<a href="https://atproto.com/specs/lexicon">lexicon</a> for
<a href="neopolitan/">Neopolitan</a> (my markdown replacement
format). After the episode, I'm absolutely
gonna do it. The goal being to provide
a nice way to created pages and posts
using less than HTML but more than
Markdown.</p>
<p>One of the biggest considerations is if
JavaScript will be allowed. I love
the idea of providing for interaction.
I hate the idea of introducing the
security issues that come with the
language. Seeing this prototype seals
the deal. Current CSS can do so much
the reward of introducing the JavaScript risk
isn't worth it. And, I expect
CSS will get nothing but more powerful.</p>
</li>
</ul>
]]></summary>
  </entry>
  
  <entry>
    <title>Adding Copy Buttons with Bitty</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n6&#x2f;6r&#x2f;q5/"/><id>urn:uuid:b036d48b-70bb-5540-b49a-7c094701e075</id>
    <updated>2026-07-24T09:04:37-04:00</updated>
    <summary><![CDATA[

<h2>Hitting a Single</h2>
<p><a href="https://bittyjs.com">Bitty</a> has a <code>.copy()</code>
method. It does two things:</p>
<ol>
<li>
<p>Copies the content of the target element.</p>
</li>
<li>
<p>Updates the text of the Copy button
to say &quot;Copied&quot; for two seconds then reverts it.</p>
</li>
</ol>
<p>For example:</p>
<div class="example-container">
<div class="highlight-wrapper"><div class="title">content.html</div><div class="code-block numbers no-copy"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag custom html">bitty-9</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-connect</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>/blog/01/n6/6r/q5/examples/example-1/bit.js<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag custom html">bitty-9</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">button</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-s</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>basicCopy<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Copy<span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">button</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="4"></span><span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">span</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-r</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>basicCopy<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="5"></span>  The quick brown fox
<span class="line-marker" data-line="6"></span><span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">span</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div><div class="highlight-wrapper"><div class="title">bit.js</div><div class="code-block numbers no-copy"><pre><span class="line-marker" data-line="1"></span><span class="source js"><span class="meta export js"><span class="keyword control import-export js">export</span> <span class="storage type js">const</span> <span class="variable other readwrite js">b</span> <span class="keyword operator assignment js">=</span> <span class="meta object-literal js"><span class="punctuation section block js">{</span><span class="punctuation section block js">}</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta export js"><span class="keyword control import-export js">export</span> <span class="variable other readwrite js">function</span> </span><span class="meta function-call js"><span class="variable function js">basicCopy</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">_</span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">sender</span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">el</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="4"></span>  <span class="variable other object js">b</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">copy</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">el</span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">sender</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="5"></span><span class="punctuation section block js">}</span></span></span></pre></div></div><div class="example-wrapper"><div class="title">Output</div><div class="example-block"><bitty-9 data-connect="/blog/01/n6/6r/q5/examples/example-1/bit.js"></bitty-9>
<p><button data-s="basicCopy">Copy</button>
<span data-r="basicCopy">
The quick brown fox
</span></p>
</div></div></div>
<h2>Connecting Keys</h2>
<p>You can put multiple buttons on a
page that all use the same copy function
with the help of a <code>data-key</code> attribute:</p>
<div class="example-container">
<div class="highlight-wrapper"><div class="title">content.html</div><div class="code-block numbers no-copy"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag custom html">bitty-9</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-connect</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>/blog/01/n6/6r/q5/examples/example-2/bit.js<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag custom html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag custom html">bitty-9</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="4"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">button</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-s</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>copyWithKey<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-key</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>alfa<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="5"></span>    Copy
<span class="line-marker" data-line="6"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">button</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="7"></span>  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">span</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-r</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>copyWithKey<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-key</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>alfa<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="8"></span>    The quick brown fox
<span class="line-marker" data-line="9"></span>  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">span</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="10"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="11"></span>
<span class="line-marker" data-line="12"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="13"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline form html">button</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-s</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>copyWithKey<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-key</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>bravo<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="14"></span>    Copy
<span class="line-marker" data-line="15"></span>  <span class="meta tag inline form html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline form html">button</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="16"></span>  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">span</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-r</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>copyWithKey<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-key</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>bravo<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="17"></span>    The lazy dog
<span class="line-marker" data-line="18"></span>  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">span</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="19"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div><div class="highlight-wrapper"><div class="title">bit.js</div><div class="code-block numbers no-copy"><pre><span class="line-marker" data-line="1"></span><span class="source js"><span class="meta export js"><span class="keyword control import-export js">export</span> <span class="storage type js">const</span> <span class="variable other readwrite js">b</span> <span class="keyword operator assignment js">=</span> <span class="meta object-literal js"><span class="punctuation section block js">{</span><span class="punctuation section block js">}</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta export js"><span class="keyword control import-export js">export</span> <span class="variable other readwrite js">function</span> </span><span class="meta function-call js"><span class="variable function js">copyWithKey</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">_</span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">sender</span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">el</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="4"></span>  <span class="meta conditional js"><span class="keyword control conditional js">if</span> <span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other object js">sender</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">key</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>key<span class="punctuation definition string end js">&quot;</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span> <span class="keyword operator comparison js">===</span> <span class="variable other object js">el</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">key</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>key<span class="punctuation definition string end js">&quot;</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation section group js">)</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="5"></span>    <span class="variable other object js">b</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">copy</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">el</span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">sender</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="6"></span>  </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span>
<span class="line-marker" data-line="7"></span><span class="punctuation section block js">}</span></span></span></pre></div></div><div class="example-wrapper"><div class="title">Output</div><div class="example-block"><bitty-9 data-connect="/blog/01/n6/6r/q5/examples/example-2/bit.js"></bitty-9>
<div>
  <button data-s="copyWithKey" data-key="alfa">
    Copy
  </button>
  <span data-r="copyWithKey" data-key="alfa">
    The quick brown fox
  </span>
</div>
<div>
  <button data-s="copyWithKey" data-key="bravo">
    Copy
  </button>
  <span data-r="copyWithKey" data-key="bravo">
    The lazy dog
  </span>
</div></div></div></div>
<h2>How It Works</h2>
<ul>
<li>
<p>The <code>data-s</code> attributes on the buttons
sets them up to send a signal named <code>copyWithKey</code>.</p>
</li>
<li>
<p>When the signal comes in, bitty
loops through all the elements with a
<code>data-r</code> attribute whose value matches
the <code>copyWithKey</code> signal name.</p>
<p>Each element is passed to the <code>copyWithKey</code>
function as the <code>el</code> argument. The <code>sender</code>
argument is populated by the button
that sent the signal.</p>
</li>
<li>
<p>Since there are multiple elements
with the <code>data-r=&quot;copyWithKey&quot;</code> attribute
we need a way to filter them down to just the
one we want. The approach used here does the filtering
by comparing the <code>data-key</code> values of
the sending and receiving elements
via the <code>.key()</code> method that bitty
adds to the incoming elements.</p>
<p>When they match, the function calls
the <code>.copy()</code> method with the elements
to run the process.</p>
</li>
</ul>
<h2>Outro</h2>
<p>Most of bitty is about setting up functions to
add your own features. The <code>.copy()</code>
method is an exception. It's fully baked.
I found myself adding the functionality
so often it made since to include
it directly. Check it out if your
site has content you want to make it
easier for your visitors to grab.</p>
<p>-a</p>

<h2>References</h2>
<ul>
<li>
<p>Bitty is a signals based framework rolled
into a web component. You can find
out more about it at
<a href="https://bittyjs.com">bittyjs.com</a>.</p>
</li>
</ul>
<h2>Endnotes</h2>
<ul>
<li>
<p>This example is using <code>bitty-9</code>. At the
time of this writing, that version is
a private beta. The current production
version of bitty is <code>bitty-8</code>. It
provides the same functionality.</p>
</li>
</ul>
]]></summary>
  </entry>
  
  <entry>
    <title>Background Texture Maker - Give your site a little grit</title><link href="https://al9000.com&#x2f;texture-maker/"/><id>urn:uuid:b936489f-8c7a-5916-8683-845d3512447b</id>
    <updated>2026-01-03T10:36:00-05:00</updated>
    <summary><![CDATA[

<bitty-9 data-connect="/texture-maker/bit.js"></bitty-9>
<p>
  This page generates CSS for textured backgrounds. 
  Play with the sliders to preview it here.
  Copy/paste the code into your stylesheet 
  to apply it to your site.
</p>
<div data-r="example"></div>
<div class="controls">
  <div>
    <label>
      <div>Lightness</div>
      <input type="range" data-key="l" data-r="initValue" data-s="updateValue" min="0" max="1" step="0.001" autocomplete="off" />
    </label>
    <label><div>Chroma</div>
      <input type="range" data-key="c" data-r="initValue" data-s="updateValue" min="0" max="0.3" step="0.0001" autocomplete="off" />
    </label>
  </div>
  <div>
    <label>
      <div>Hue</div>
      <input type="range" data-key="h" data-r="initValue" data-s="updateValue" min="0" max="360" step="0.01" autocomplete="off" />
    </label>
    <label>
      <div>Texture</div>
      <input type="range" data-key="o" data-r="initValue" data-s="updateValue" min="0" max="100" step="0.01" autocomplete="off" />
    </label>
  </div>
</div>

<div class="code-block numbers copy-button">
  <pre data-r="updateCSS"></pre>
</div>

<h2>Details</h2>
<ul>
<li>
<p>The texture comes from an SVG that's encoded
for use as a CSS <strong>background-image</strong>.</p>
</li>
<li>
<p>The SVG and the CSS <strong>background-size</strong> are both
set to 150px x 150px. This prevents the texture
from changing at different page sizes.</p>
</li>
<li>
<p>The Lightness, Chroma, and Hue sliders set the base background variables for an oklch
color.</p>
</li>
<li>
<p>The Texture slider controls how strong
the textured effect is.</p>
</li>
<li>
<p>The original version of this tool used base64 encoding.
<a href="https://tylersticka.com/">Tyler Sticka</a> reminded me
that that's not necessary for SVGs.
The output is escaped plain-text now
as a result.</p>
</li>
</ul>
<h2>Outro</h2>
<p>The textured effect can go from barely
perceptible to in your face.
I'm leaning toward the subtler
site. That's not to dismiss the more
overt. I expect to change things
up from time to time. I hope you enjoy
experimenting with it too.</p>
<p>-a</p>






<p>P.S. At press time, I have a little
<strong>text-shadow</strong> on the page to
add some separation to the prose.
It's set to compliment a darker
palette. It's not dynamic. That
can make it look weird with different
background colors. Especially as they
get lighter.</p>
<p>The shadow isn't part of the CSS
payload from the tool. Playing
with it is left as an exercise
for the reader.</p>
<p><button data-s="restoreDefaults" style="opacity: 0.05;">Restore Defaults</button></p>
]]></summary>
  </entry>
  
  <entry>
    <title>Blog Post base32 ID Cleanup</title><link href="https://al9000.com&#x2f;rust&#x2f;apps&#x2f;base32_timestamp_cleanup/"/><id>urn:uuid:877fdc9f-6054-5489-baa4-31c24d2410ca</id>
    <updated>2026-07-20T13:27:00-04:00</updated>
    <summary><![CDATA[

<p>The IDs for posts on this site
are generated by using
base32<sup class="footnote-link"><a id="fn-b32-body" href="#fn-b32">b32</a></sup> encoding
to convert timestamps into strings of text.
The idea being to get shorter
IDs that still sort in chronological
order. For example, this timestamp:</p>
<section class="output-wrapper"><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">2026-07-20T13:27:00-04:00</span></pre></section>
<p>Turns into this snippet:</p>
<section class="output-wrapper"><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">01n5wpk4</span></pre></section>
<p>It works great, as long
as you do the encoding properly.
It turns out, Dear Reader, that
I did not do it properly.</p>
<p>This is the process I wrote to
fix them. It does two things:</p>
<ul>
<li>
<p>update the ids in the files
based of the <code>created</code> timestamp.</p>
</li>
<li>
<p>generates blog folders for
the new IDs.</p>
</li>
</ul>
<h3>Rust</h3>
<div class="highlight-wrapper"><div class="file-name">./Cargo.toml</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text plain">[package]
<span class="line-marker" data-line="2"></span>name = &quot;base32_timestamp_cleanup&quot;
<span class="line-marker" data-line="3"></span>version = &quot;0.1.0&quot;
<span class="line-marker" data-line="4"></span>edition = &quot;2024&quot;
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>[dependencies]
<span class="line-marker" data-line="7"></span>anyhow = &quot;1.0.104&quot;
<span class="line-marker" data-line="8"></span>base32 = &quot;0.5.1&quot;
<span class="line-marker" data-line="9"></span>chrono = &quot;0.4.45&quot;
<span class="line-marker" data-line="10"></span>regex = &quot;1.13.1&quot;
<span class="line-marker" data-line="11"></span>walkdir = &quot;2.5.0&quot;</span></pre></div></div>
<div class="highlight-wrapper"><div class="file-name">./src/main.rs</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="meta path rust">anyhow<span class="punctuation accessor rust">::</span></span>Result<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span><span class="keyword other rust">use</span> <span class="meta path rust">base32<span class="punctuation accessor rust">::</span></span>Alphabet<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">chrono<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>DateTime<span class="punctuation separator rust">,</span> FixedOffset</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">regex<span class="punctuation accessor rust">::</span></span>Regex<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>fs<span class="punctuation separator rust">,</span> <span class="meta path rust">path<span class="punctuation accessor rust">::</span></span>PathBuf</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="6"></span><span class="keyword other rust">use</span> <span class="meta path rust">walkdir<span class="punctuation accessor rust">::</span></span>WalkDir<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="9"></span>  <span class="support function rust">update_file_ids</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="10"></span>  <span class="support function rust">make_blog_folders</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="11"></span>  <span class="support macro rust">println!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>done.<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="13"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="14"></span>
<span class="line-marker" data-line="15"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">make_blog_folders</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="16"></span>  <span class="storage type rust">let</span> base_dir <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>../../../blog<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="17"></span>  <span class="storage type rust">let</span> id_matcher <span class="keyword operator rust">=</span> <span class="meta path rust">Regex<span class="punctuation accessor rust">::</span></span>new<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double raw rust"><span class="storage type string rust">r</span><span class="punctuation definition string begin rust">#</span>&quot;id\s+=\s+&quot;(..)/(..)/(..)/(..)&quot;<span class="punctuation definition string end rust">&quot;#</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="18"></span>  <span class="storage type rust">let</span> files <span class="keyword operator rust">=</span> <span class="support function rust">get_files_with_extensions</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>
<span class="line-marker" data-line="19"></span>    <span class="keyword operator rust">&amp;</span><span class="meta path rust">PathBuf<span class="punctuation accessor rust">::</span></span>from<span class="meta group rust"><span class="punctuation section group begin rust">(</span>base_dir</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="20"></span>    <span class="keyword operator rust">&amp;</span><span class="support macro rust">vec!</span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>html<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="21"></span>  </span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="22"></span>  <span class="keyword control rust">for</span> f <span class="keyword operator rust">in</span> files <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="23"></span>    <span class="storage type rust">let</span> content <span class="keyword operator rust">=</span> <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>read_to_string<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>f</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="24"></span>    <span class="keyword control rust">if</span> <span class="storage type rust">let</span> <span class="support type rust">Some</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">_</span><span class="punctuation separator rust">,</span> <span class="meta group rust"><span class="punctuation section group begin rust">[</span>f1<span class="punctuation separator rust">,</span> f2<span class="punctuation separator rust">,</span> f3<span class="punctuation separator rust">,</span> f4<span class="punctuation section group end rust">]</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> id_matcher
<span class="line-marker" data-line="25"></span>      .<span class="support function rust">captures_iter</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="26"></span>      .<span class="support function rust">next</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="27"></span>      .<span class="support function rust">map</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">|</span></span></span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="variable parameter rust">c</span><span class="punctuation section parameters end rust">|</span></span> </span><span class="meta function closure rust">c.<span class="support function rust">extract</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="28"></span>    <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="29"></span>      <span class="storage type rust">let</span> new_folder <span class="keyword operator rust">=</span>
<span class="line-marker" data-line="30"></span>        <span class="meta path rust">PathBuf<span class="punctuation accessor rust">::</span></span>from<span class="meta group rust"><span class="punctuation section group begin rust">(</span>base_dir</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>f1</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>f2</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>f3</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>f4</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="31"></span>      <span class="support macro rust">dbg!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>new_folder</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="32"></span>      <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> NOTE: Uncomment this line to make the
<span class="line-marker" data-line="33"></span></span>      <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> dirs. It should be idempotent, but
<span class="line-marker" data-line="34"></span></span>      <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> there&#39;s no need to test that.
<span class="line-marker" data-line="35"></span></span>      <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> std::fs::create_dir_all(new_folder)?;
<span class="line-marker" data-line="36"></span></span>    </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="37"></span>  </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="38"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="39"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="40"></span>
<span class="line-marker" data-line="41"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">update_file_ids</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="42"></span>  <span class="storage type rust">let</span> files <span class="keyword operator rust">=</span> <span class="support function rust">get_files_with_extensions</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>
<span class="line-marker" data-line="43"></span>    <span class="keyword operator rust">&amp;</span><span class="meta path rust">PathBuf<span class="punctuation accessor rust">::</span></span>from<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>../../..<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="44"></span>    <span class="keyword operator rust">&amp;</span><span class="support macro rust">vec!</span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>html<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="45"></span>  </span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="46"></span>  <span class="storage type rust">let</span> date_matcher <span class="keyword operator rust">=</span> <span class="meta path rust">Regex<span class="punctuation accessor rust">::</span></span>new<span class="meta group rust"><span class="punctuation section group begin rust">(</span>
<span class="line-marker" data-line="47"></span>    <span class="string quoted double raw rust"><span class="storage type string rust">r</span>&quot;created\s+=\s+(\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d-\d\d:\d\d)<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="48"></span>  </span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="49"></span>  <span class="storage type rust">let</span> id_matcher <span class="keyword operator rust">=</span> <span class="meta path rust">Regex<span class="punctuation accessor rust">::</span></span>new<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double raw rust"><span class="storage type string rust">r</span><span class="punctuation definition string begin rust">#</span>&quot;id\s+=\s+&quot;(../../../..)&quot;<span class="punctuation definition string end rust">&quot;#</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="50"></span>  <span class="keyword control rust">for</span> f <span class="keyword operator rust">in</span> files <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="51"></span>    <span class="storage type rust">let</span> content <span class="keyword operator rust">=</span> <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>read_to_string<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>f</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="52"></span>    <span class="keyword control rust">if</span> <span class="storage type rust">let</span> <span class="support type rust">Some</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">_</span><span class="punctuation separator rust">,</span> <span class="meta group rust"><span class="punctuation section group begin rust">[</span>date<span class="punctuation section group end rust">]</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> date_matcher
<span class="line-marker" data-line="53"></span>      .<span class="support function rust">captures_iter</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="54"></span>      .<span class="support function rust">next</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="55"></span>      .<span class="support function rust">map</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">|</span></span></span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="variable parameter rust">c</span><span class="punctuation section parameters end rust">|</span></span> </span><span class="meta function closure rust">c.<span class="support function rust">extract</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="56"></span>    <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="57"></span>      <span class="storage type rust">let</span> dt <span class="keyword operator rust">=</span> <span class="meta path rust">DateTime<span class="punctuation accessor rust">::</span></span>parse_from_rfc3339<span class="meta group rust"><span class="punctuation section group begin rust">(</span>date</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="58"></span>      <span class="storage type rust">let</span> encoded <span class="keyword operator rust">=</span> <span class="support function rust">encode_base32_datetime</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>dt</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="59"></span>      <span class="storage type rust">let</span> new_id <span class="keyword operator rust">=</span> <span class="support macro rust">format!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust">
<span class="line-marker" data-line="60"></span>        <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{}</span>/<span class="constant other placeholder rust">{}</span>/<span class="constant other placeholder rust">{}</span>/<span class="constant other placeholder rust">{}</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="61"></span>        <span class="keyword operator rust">&amp;</span>encoded<span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="constant numeric integer decimal rust">0</span><span class="keyword operator rust">..</span><span class="keyword operator rust">=</span><span class="constant numeric integer decimal rust">1</span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="62"></span>        <span class="keyword operator rust">&amp;</span>encoded<span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="constant numeric integer decimal rust">2</span><span class="keyword operator rust">..</span><span class="keyword operator rust">=</span><span class="constant numeric integer decimal rust">3</span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="63"></span>        <span class="keyword operator rust">&amp;</span>encoded<span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="constant numeric integer decimal rust">4</span><span class="keyword operator rust">..</span><span class="keyword operator rust">=</span><span class="constant numeric integer decimal rust">5</span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="64"></span>        <span class="keyword operator rust">&amp;</span>encoded<span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="constant numeric integer decimal rust">6</span><span class="keyword operator rust">..</span><span class="keyword operator rust">=</span><span class="constant numeric integer decimal rust">7</span><span class="punctuation section group end rust">]</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="65"></span>      <span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="66"></span>      <span class="support macro rust">dbg!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>new_id</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="67"></span>      <span class="keyword control rust">if</span> <span class="storage type rust">let</span> <span class="support type rust">Some</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">_</span><span class="punctuation separator rust">,</span> <span class="meta group rust"><span class="punctuation section group begin rust">[</span>old_id<span class="punctuation section group end rust">]</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> id_matcher
<span class="line-marker" data-line="68"></span>        .<span class="support function rust">captures_iter</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>content</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="69"></span>        .<span class="support function rust">next</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="70"></span>        .<span class="support function rust">map</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">|</span></span></span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="variable parameter rust">c</span><span class="punctuation section parameters end rust">|</span></span> </span><span class="meta function closure rust">c.<span class="support function rust">extract</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="71"></span>      <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="72"></span>        <span class="support macro rust">dbg!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>old_id</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="73"></span>        <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> NOTE: Uncomment these lines to do the replacement.
<span class="line-marker" data-line="74"></span></span>        <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> It should be safe to do multiple times, but
<span class="line-marker" data-line="75"></span></span>        <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> there&#39;s no reason to test that.
<span class="line-marker" data-line="76"></span></span>        <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> let new_content = content.replace(old_id, &amp;new_id);
<span class="line-marker" data-line="77"></span></span>        <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> fs::write(&amp;f, new_content)?;
<span class="line-marker" data-line="78"></span></span>      </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="79"></span>    </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="80"></span>  </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="81"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="82"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="83"></span>
<span class="line-marker" data-line="84"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">encode_base32_datetime</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="85"></span>  <span class="variable parameter rust">datetime</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span><span class="meta generic rust">DateTime<span class="punctuation definition generic begin rust">&lt;</span>FixedOffset<span class="punctuation definition generic end rust">&gt;</span></span>
<span class="line-marker" data-line="86"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> String</span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="87"></span>  <span class="storage type rust">let</span> bytes <span class="keyword operator rust">=</span> <span class="keyword operator rust">&amp;</span>datetime.<span class="support function rust">timestamp</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">to_be_bytes</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="constant numeric integer decimal rust">3</span><span class="keyword operator rust">..</span><span class="constant numeric integer decimal rust">8</span><span class="punctuation section group end rust">]</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="88"></span>  <span class="meta path rust">base32<span class="punctuation accessor rust">::</span></span>encode<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta path rust">Alphabet<span class="punctuation accessor rust">::</span></span>Crockford<span class="punctuation separator rust">,</span> bytes</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">to_lowercase</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="89"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="90"></span>
<span class="line-marker" data-line="91"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">get_files_with_extensions</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="92"></span>  <span class="variable parameter rust">dir</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span>PathBuf,
<span class="line-marker" data-line="93"></span>  <span class="variable parameter rust">extensions</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span><span class="meta generic rust">Vec<span class="punctuation definition generic begin rust">&lt;</span><span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span><span class="punctuation definition generic end rust">&gt;</span></span>,
<span class="line-marker" data-line="94"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Vec<span class="punctuation definition generic begin rust">&lt;</span>PathBuf<span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="95"></span>  <span class="meta path rust">WalkDir<span class="punctuation accessor rust">::</span></span>new<span class="meta group rust"><span class="punctuation section group begin rust">(</span>dir</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="96"></span>    .<span class="support function rust">into_iter</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="97"></span>    .<span class="support function rust">filter_map</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">|</span></span></span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="variable parameter rust">e</span><span class="punctuation section parameters end rust">|</span></span> </span><span class="meta function closure rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="98"></span>      <span class="storage type rust">let</span> path <span class="keyword operator rust">=</span> e.<span class="support function rust">as_ref</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">path</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="99"></span>      <span class="keyword control rust">match</span> path.<span class="support function rust">extension</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="100"></span>        <span class="support type rust">Some</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>ext</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=&gt;</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="101"></span>          <span class="keyword control rust">if</span> extensions.<span class="support function rust">contains</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>ext.<span class="support function rust">to_str</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="102"></span>            <span class="support type rust">Some</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>path.<span class="support function rust">to_path_buf</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="103"></span>          </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span> <span class="keyword control rust">else</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="104"></span>            <span class="support type rust">None</span>
<span class="line-marker" data-line="105"></span>          </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="106"></span>        </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="107"></span>        <span class="support type rust">None</span> <span class="keyword operator rust">=&gt;</span> <span class="support type rust">None</span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="108"></span>      </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="109"></span>    </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="110"></span>    .<span class="support function rust">collect</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="111"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<h2>Measure Twice</h2>
<p>I checked the original method I was using
to make sure things were sorting properly.
Unfortunately, I didn't check all the cases
I needed to. The issue only shows up when
there are numbers in the output string.
The encoding should have put numbers before
letters. It didn't. They were reversed.</p>
<p>I considered not bothering with the update.
It doesn't matter for the site itself.
The only place it makes a difference
is when I'm editing files. It's easier
to find them when they are sorted by
date. The goal of the site builder I'm
working on is to use it for the next
20 years. Spending the time on the
correction is an easy investment
given that perspective.</p>
<p>-a</p>

<h2>Endnotes</h2>
<ul>
<li>I moved the pages to new locations
that match their updated IDs. I
didn't bother setting up redirects.
Incoming links that point to the
old locations will get a Page
Not Found error. I don't expect
that to be enough of a problem
that it's worth setting up redirects
for.</li>
</ul>
<h2>Footnotes</h2>
<ul>
<li><a id="fn-b32" href="#fn-b32-body" class="footnote-ref">b32</a> <a href="https://en.wikipedia.org/wiki/Base32">base32</a>
is a process that takes an input
and coverts it into a string
of characters that can be shorter
than the original. For example,
the timestamps I use look like this:</li>
</ul>
]]></summary>
  </entry>
  
  <entry>
    <title>Three Dates in a Trench Coat</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n5&#x2f;st&#x2f;wc/"/><id>urn:uuid:49caaea3-78c2-53d3-a115-1ff56e26e45e</id>
    <updated>2026-07-19T11:21:48-04:00</updated>
    <summary><![CDATA[<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="/styles/main.css" />

    <script src="&#x2f;scripts.raw&#x2f;bitty&#x2f;bitty-9.0.0-beta1.source.js" type="module"></script>

<link rel="shortcut icon" href="/favicon.ico" />
<title>Three Dates in a Trench Coat</title>
<meta property="og:title" content="Three Dates in a Trench Coat" />
<meta name="description" content="from alan w smith" />
<meta property="og:description" content="from alan w smith" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://al9000.com/rss/feed.xml" />
<meta property="og:image" content="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n5&#x2f;st&#x2f;wc/og-image.jpg" />
<link rel="apple-touch-icon" sizes="180x180" href="&#x2f;favicons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="16x16" href="&#x2f;favicons/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="&#x2f;favicons/favicon-32x32.png" />
<link rel="manifest" href="&#x2f;favicons/site.webmanifest" />
<link rel="mask-icon" href="&#x2f;favicons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="alternate" type="application/atom+xml" title="al9000.com" href="/rss/feed.xml" />
<link
  rel="site.standard.publication"
  href="at://did:plc:hehia4csii5iipebsgolxxal/site.standard.publication&#x2f;3mp5l453r552a"
/>




    
    
    
    

    


    <style>
    </style>
    
  </head>
  <body class="page">
<noscript>
  <p>
    NOTE: Some pages on this site rely on JavaScript. 
    It's not currently available in your
    browser/reader. Depending on the page,
    some or all of the content may not
    work correctly without it. 
  </p>

</noscript>

    <div class="payload">
      

<header class="default-wrapper xlarge-bottom-margin xlarge-bottom-padding small-font-size">
<noscript>
  <p>
    NOTE: This site use JavaScript which appears to be turned off. 
    Some content will be fine, but some things won't work.
  </p>

</noscript>
  <div class="top-nav">
    <a href="/">home</a>
    <a href="/tools">tools</a>
    <a href="/rss/">rss</a> |
    <a href="https://bittyjs.com/">bitty</a>
  </div>


</header>


<main class="default default-wrapper default-flow">

  <hgroup class="default">
      <div class="title-wrapper">
        <h1>Three Dates in a Trench Coat</h1>
      </div>
        <div class="date">July 2026</div>
  </hgroup>


<h2>An Initial Pair</h2>
<p>Two dates isn't enough.</p>
<p>At least, when it comes to blog posts. For years, I've used <strong>created</strong>
and <strong>updated</strong> as the only dates for my
writing. It makes sense for pages that are
written and deployed in one shot.
Not so much when a draft sticks around for a few days,
weeks, or years before seeing the light of day.</p>
<p>Neither <strong>created</strong> or <strong>updated</strong> feels right
for a post started last October but didn't
go out until today. I want to keep the
<strong>created</strong> date locked in to when I first
started the piece. But, using <strong>updated</strong>
doesn't make sense for the first time
the status of a page goes from
<strong>draft</strong> to <strong>done</strong>.</p>
<h2>Introducing: completed</h2>
<p>The solution: a third date. Our new
friend <strong>completed</strong>.</p>
<p>Posts start out with metadata that
looks like this:</p>
<div class="highlight-wrapper"><div class="output-block"><pre><span class="line-marker" data-line="1"></span><span class="text plain">created = 2026-06-02T12:21:48-04:00
<span class="line-marker" data-line="2"></span>status  = &quot;draft&quot;</span></pre></div></div>
<p>They get worked on for however
long then need. When they're
ready, the metadata gets updated
with the completed timestamp
and the status is set to &quot;done&quot;.</p>
<div class="highlight-wrapper"><div class="output-block"><pre><span class="line-marker" data-line="1"></span><span class="text plain">created   = 2025-10-02T12:21:48-04:00
<span class="line-marker" data-line="2"></span>completed = 2026-03-11T12:21:48-04:00
<span class="line-marker" data-line="3"></span>status    = &quot;done&quot;</span></pre></div></div>
<p>The &quot;done&quot; status is what makes the page
show up on the home page and the
RSS feed. It's sorted in based
on the <strong>completed</strong> date, but
I don't lose the metadata for
when the scribbling started.</p>
<p>If the piece has major changes
an <strong>updated</strong> datetime is added:</p>
<div class="highlight-wrapper"><div class="output-block"><pre><span class="line-marker" data-line="1"></span><span class="text plain">created   = 2025-10-02T12:21:48-04:00
<span class="line-marker" data-line="2"></span>completed = 2026-03-11T12:21:48-04:00
<span class="line-marker" data-line="3"></span>updated   = 2026-07-19T12:21:48-04:00
<span class="line-marker" data-line="4"></span>status    = &quot;done&quot;</span></pre></div></div>
<p>The status stays as <strong>done</strong>. That
keeps the page in the list of links
and RSS feed. The <strong>updated</strong> value
is used to re-slot it into a
corresponding position on the timeline.</p>
<h2>Words Mean Things</h2>
<p>I just put this feature in place
today. I already love it. It removes
that little bit of friction that
came from trying to decided which
of the two original dates to use
when an old draft got polished
enough to be release into the wild.</p>
<p>-a</p>

<div class="end-of-line"></div>


<div class="backmatter default-flow">
    <h2>Endnotes</h2>

<ul class="endnotes">

  <li>Adding the <strong>completed</strong> timestamp isn't required. 
    A page with <strong>status = "done"</strong> and nothing
    more than a <strong>created</strong> datetime will show up
    on the site. The <strong>completed</strong> (and <strong>updated</strong>)
values simply shift the position in the chronology 
    of the lists. </li>

<li>I'm still updating dates manually. It's not much 
more work with the third option in play. The 
date for when the piece goes lives has to be
added/edited either way. It's a little friction
though. I've got an item on the todo list
for a tool that'll let me update the values
    with a button press.</li>

  <li><p>I briefly debated making the <strong>updated</strong>
metadata an array that could store the dates
  for multiple changes. Something like this:</p>

<div class="highlight-wrapper"><div class="output-block"><pre><span class="line-marker" data-line="1"></span><span class="text plain">created   = 2025-10-02T12:21:48-04:00
<span class="line-marker" data-line="2"></span>completed = 2026-03-11T12:21:48-04:00
<span class="line-marker" data-line="3"></span>updated   = [2026-04-19T12:21:48-04:00, 2026-07-07T12:21:48-04:00]
<span class="line-marker" data-line="4"></span>status    = &quot;done&quot;</span></pre></div></div>

<p>
That's more work than I want to do. Especially
because I'm unlikely to ever show anything
other than the latest change. The source
content for my site is stored in a 
version control system that lets me
see when changes occur if I ever really
want to check it out. 
</p>
  </li>
</ul>



</div>

</main>

<footer class="default">
  <div>
    from <a href="https://bsky.app/profile/alanwsmith.com">alan w smith</a>
  </div>
  <div>
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  

      
</footer>


    </div>


    <div class="templates" hidden>
      <bitty-9 data-connect="/bits/default.js"></bitty-9>
      <script type="module" src="/bits/components.js"></script>



    </div>
  </body>
</html>
]]></summary>
  </entry>
  
  <entry>
    <title>Full Site Links</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n5&#x2f;n7&#x2f;gg/"/><id>urn:uuid:f5fac119-f789-5fb4-ad7f-4ef2ac1f8b2f</id>
    <updated>2026-07-17T17:26:40-04:00</updated>
    <summary><![CDATA[

<p>I'm doing something new with the structure of my
site. Or, something old, really. While
I've got a <code>blog</code> folder to hold general
posts, the r
est of the site is
made up of arbitrary folders and files
scattered to the four winds. I can
throw stuff anywhere. It's liberating.</p>
<p>The approach did cause a complication.
Aggregating content from across the
site into a single list is more complicated
than processing a single directory of
files. I fixed that today during
a few hours of live streaming.
I was going to post it until I realized
I jacked up settings at some point
and haven't been recording audio.</p>
<p>Alas, such is life. And, the more
important thing is that the
work is done. I can drop pages
anywhere and they'll show
up in the chronological timeline.</p>
<p>-a</p>

]]></summary>
  </entry>
  
  <entry>
    <title>Week Notes 2026-28</title><link href="https://al9000.com&#x2f;weeknotes&#x2f;2026&#x2f;28/"/><id>urn:uuid:a8de8881-6dd0-5c0e-a832-7b81832ae62e</id>
    <updated>2026-07-15T16:44:19-04:00</updated>
    <summary><![CDATA[

<h2>Intro</h2>
<p>As of this post, I've moved Week Notes
to a new location on the site <code>/weeknotes/</code>
where the format is <code>/weeknotes/YEAR/WEEK/</code>.</p>
<p>I'll eventually move prior week notes
into the same structure. For now,
it only applies to notes moving
forward. The idea is to make it
easier to define starts and stops
and keep track because I'm using
automatic output from the
date function (via rust's chronos
crate) to generate the week numbers.
That way, I don't have to think
about it.</p>
<p>(I actually moved things in
week 30, this is just pulling
the content from a prior
not on al9000 here. All the
rest of the notes that will
be moved are still sitting on
alanwsmith.com)</p>
<h2>Sunday - June 19</h2>
<ul>
<li>
<p>Added a feature to my site
builder so that <a href="/blog/01/n5/st/wc/">posts and
page can have three dates</a>:
created, completed, and updated.
Did that because I'll often
have posts that take me a long
time to write. I want to
keep track of when I start them
and when I publish them.
It felt weird to use &quot;update&quot;
for the publication date. Hence
the new &quot;completed&quot; date.</p>
</li>
</ul>

]]></summary>
  </entry>
  
  <entry>
    <title>NeoDoc - Notes with Superpowers</title><link href="https://al9000.com&#x2f;neodoc/"/><id>urn:uuid:dd27b276-bd2f-526c-bb49-474af7001d30</id>
    <updated>2026-07-13T08:41:29-04:00</updated>
    <summary><![CDATA[

<div class="warning">
  <p>
    Head's up
  </p>
  <p>
    NeoDoc is currently embedded 
    in the app I use to build my
    websites. I'm in the process of splitting it
    out to its own project. 
    It won't be available for general use 
    until that work is finished. 
    I'll update this page when it's ready.
  </p>
</div>

<h2>Introduction</h2>
<p>NeoDoc is a way to take notes. It's easy to
learn, quick to customize, and super powerful.</p>
<h2>Sections</h2>
<h3>Section Names</h3>
<p>NeoDoc note are made of sections. Sections
are defined by lines that start with
two dashes followed by a name. Content
for the section comes after an empty
line.</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- title
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span>A NeoDoc Overview</span></pre></div></div>
The section names can be pretty much anything
as long as they don't contain spaces.
<h3>Section Flags and Attributes</h3>
<p>Sections can have metadata attached to them
in the form of <strong>flags</strong> and <strong>attributes</strong>.</p>
<p>Flags are pieces of text that start
with two dashes on the lines below a
section name. For example, this is
an <strong>image</strong> section with a flag for the
image's filename. The content portion of the section
is used for the image's alt text:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- image 
<span class="line-marker" data-line="2"></span>-- example-image.jpg
<span class="line-marker" data-line="3"></span>
<span class="line-marker" data-line="4"></span>This is where the alt text for the image goes.</span></pre></div></div>
Attributes work the same way as flags but
start with a keyword followed by a colon. 
For example, here's a "aside" section
with a "class" attribute of "warning":
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- aside 
<span class="line-marker" data-line="2"></span>-- class: warning
<span class="line-marker" data-line="3"></span>
<span class="line-marker" data-line="4"></span>There is where you can put something 
<span class="line-marker" data-line="5"></span>that needs extra attention.</span></pre></div></div>
<h2>Section Types</h2>
<p>Section content is treated as paragraphs by default.
Adding a section type after a section name
changes the handling. Two section types
are &quot;list&quot; and &quot;checklist&quot;. Changing the
type of a section is done by the name of the type
after the name of the section:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- notes list
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span>- A note about something. 
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span>- Another note about something.</span></pre></div></div>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- todo checklist 
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span>[] Something that needs to be done
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span>[x] Something that has been done.</span></pre></div></div>
The section types can also be used generically 
as their own section names:
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- list
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span>- Item for a list without a more
<span class="line-marker" data-line="4"></span>specific section name. 
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>- And another item for the list.</span></pre></div></div>
<details><summary>List of Section Types</summary>
<p>The full list of section types is:</p>
<ul>
<li>
<p>checklist - a collection of items
with a status associated with them.</p>
</li>
<li>
<p>csv - a collection of CSV data.</p>
</li>
<li>
<p>json - a JSON object.</p>
</li>
<li>
<p>list - a list that uses bullets for
each item.</p>
</li>
<li>
<p>numbered - a list that uses numbers
for each item.</p>
</li>
<li>
<p>raw - a raw block of text with
no addition processing.</p>
</li>
<li>
<p>toml - a block of TOML data.</p>
</li>
<li>
<p>yaml - a block of YAML data.</p>
</li>
</ul>
</details>
<h3>Special Sections</h3>
<p>There are a few section sections that
aren't parsed as paragraphs by
default. They are:</p>
<ul>
<li>
<p>css - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>html - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>script - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>math - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>pre - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>svg - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>template - processed as a <strong>raw</strong> block
by default.</p>
</li>
<li>
<p>textarea - processed as a <strong>raw</strong> block
by default.</p>
</li>
</ul>
<p>The defaults for these sections map to
how they'll be used the majority of the time.
They ensure that different implementations
of NeoDoc will have a consistent baseline.</p>
<h2>Spans</h2>
<p>Section content can contain spans.
They're snippets that wrap
text to alter it in some way.</p>
<h3>Example Span</h3>
<p>A basic span looks like this:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">&lt;&lt;code|console.log()&gt;&gt;</span></pre></div></div>
The parts are:
<ul>
<li>
<p>A pair of less than signs (<code>&lt;&lt;</code>)
that mark the start of the span.</p>
</li>
<li>
<p>The type of span (e.g. <code>code</code> in the
example above).</p>
</li>
<li>
<p>A pipe (<code>|</code>) character that separates
the span type from the span's content.</p>
</li>
<li>
<p>The span's content itself.</p>
</li>
<li>
<p>A pair of greter than signs (<code>&gt;&gt;</code>)
that mark the end of the span.</p>
</li>
</ul>
<p>Here's what a span looks like surrounded
by more content:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">The JavaScript function &lt;&lt;code|console.log()&gt;&gt;
<span class="line-marker" data-line="2"></span>prints information to the developer console.</span></pre></div></div>
When that content is turned into a web page
the span turns into an HTML `&lt;code&gt;` tag
like this:
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text html basic">The JavaScript function <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">code</span><span class="punctuation definition tag end html">&gt;</span></span>console.log()<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">code</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>prints information to the developer console.</span></pre></div></div>
<h3>Span Attributes</h3>
<p>Spans can have attributes that further
enhance their content. They're added
by using additional pipes to separate
them from the content. For example,
a class attribute can be added to
the span like this:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">&lt;&lt;code|console.log()|class: featured&gt;&gt;</span></pre></div></div>
which outputs this HTML:
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">code</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">featured</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>console.log()<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">code</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
Multiple attributes can be added by using
more pipes. For example, this span (which
also shows how spans can be split across lines)
adds a `data-language` attribute that can be
used to apply syntax highlighting to the
code:
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">&lt;&lt;code
<span class="line-marker" data-line="2"></span>  |console.log()
<span class="line-marker" data-line="3"></span>  |class: featured
<span class="line-marker" data-line="4"></span>  |data-language: javascript&gt;&gt;</span></pre></div></div>
The output HTML looks like this:
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">code</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">featured</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">data-language</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>javascript<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>console.log()<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">code</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
<h3>Span Shorthands</h3>
<p>There are shorthands for frequenly used
spans. For example, backtics denote code
spans. The orignal example above:</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">&lt;&lt;code|console.log()|class: featured|language: javascript&gt;&gt;</span></pre></div></div>
can be written as:
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">``console.log()|class: featured|language: javascript``</span></pre></div></div>
<details><summary>Full List of Span Shorthands</summary>
<ul>
<li>
<p>``TEXT`` - code span</p>
</li>
<li>
<p>**TEXT** - bold span</p>
</li>
<li>
<p>__TEXT__ - emphasis span</p>
</li>
<li>
<p>~~TEXT~~ - strikethrough span</p>
</li>
<li>
<p>^^TEXT^^ - footnote</p>
</li>
<li>
<p>&gt;&gt;TEXT|URL&gt;&gt; - link</p>
</li>
<li>
<p>[[FILEPATH|alt: ALT_TEXT]] - image span</p>
</li>
</ul>
</details>
<h2>Content Generation</h2>
<p>NeoDoc notes are designed to be turned
into or other forms of content (e.g. web pages).
Apps apply templates to the notes to generate
the final content. Since each app is
responsible for its own templates, the
same note can be laid out in any number
of ways. Updating templates redesigns
pages without having to change the notes.</p>
<details><summary>Technical Overview</summary>
<p>NeoDoc is a specification for turning
a plain-text document into an Abstract
Syntax Tree (AST). Parsers are responsible
for converting notes into ASTs. Those
ASTs are handed off to other processes
that are responsible for generating the
final output.</p>
<p>The AST identifies the names, types, flags
and attributes of sections and spans. Content
generators match those details with
corresponding templates to render
the final output. The specifics of
how that happens are the responsibility
of the generator.</p>
</details>
<h2>Why Not Markdown?</h2>
<p>NeoDoc is similar to another format
called Markdown. Both rely on text files
to store their content and formatting
details. The first question
anyone who knows about Markdown
asks when I tell them about NeoDoc
is why I don't use it instead.</p>
<p>The short answer comes down the
the core design features of NeoDoc:</p>
<ul>
<li>
<p>The ability to create custom sections
and spans.</p>
</li>
<li>
<p>The ability to add flags and
attributes to content.</p>
</li>
</ul>
<h3>Layout Flexibility</h3>
<p>Here's an example to help demonstrate
what NeoDoc is capable of. It's
a <strong>book-review</strong> section that includes
attributes for the title, author, and
cover image along with the review itself.</p>
<div class="highlight-wrapper"><div class=""><pre><span class="line-marker" data-line="1"></span><span class="text plain">-- book-review
<span class="line-marker" data-line="2"></span>-- title: Dungeon Crawler Carl
<span class="line-marker" data-line="3"></span>-- author: Matt Dinniman
<span class="line-marker" data-line="4"></span>-- cover: dungeon-crawler-carl-cover.jpg
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>First off, I did the audio book instead
<span class="line-marker" data-line="7"></span>of the paper copy. I don&#39;t know how much
<span class="line-marker" data-line="8"></span>I would have liked the physical version
<span class="line-marker" data-line="9"></span>but the narrator for the audio book
<span class="line-marker" data-line="10"></span>is absolute gold. 
<span class="line-marker" data-line="11"></span>
<span class="line-marker" data-line="12"></span>etc.</span></pre></div></div>
Apps that use NeoDoc can access
the content and attributes as independent
pieces of data. They can be placed 
wherever they need to be in the output. 
The HTML for a web page might looks like
this:
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">book-review</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>  <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="3"></span>    <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">img</span> 
<span class="line-marker" data-line="4"></span>      <span class="meta attribute-with-value html"><span class="entity other attribute-name html">src</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>dungeon-crawler-carl-cover.jpg<span class="punctuation definition string end html">&quot;</span></span></span>
<span class="line-marker" data-line="5"></span>      <span class="meta attribute-with-value html"><span class="entity other attribute-name html">alt</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>The book cover for Dungeon Crawler Carl<span class="punctuation definition string end html">&quot;</span></span></span>
<span class="line-marker" data-line="6"></span>   <span class="punctuation definition tag end html"> /&gt;</span></span>
<span class="line-marker" data-line="7"></span>  <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="8"></span>  <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="9"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">title</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Dungeon Crawler Carl<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="10"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">by</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>by Matt Dinniman<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="11"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="12"></span>      First off, I did the audio book instead
<span class="line-marker" data-line="13"></span>      of the paper copy. I don&#39;t know how much
<span class="line-marker" data-line="14"></span>      I would have liked the physical version
<span class="line-marker" data-line="15"></span>      but the narrator for the audio book
<span class="line-marker" data-line="16"></span>      is absolute gold. 
<span class="line-marker" data-line="17"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="18"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="19"></span>      etc.
<span class="line-marker" data-line="20"></span>    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="21"></span>  <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="22"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>
When, in turn, gets rendered like this:
<div class="book-review">
  <div>
    <img 
      src="dungeon-crawler-carl-cover.jpg"
      alt="The book cover for Dungeon Crawler Carl"
    />
  </div>
  <div>
    <div class="title">Dungeon Crawler Carl</div>
    <div class="by">by Matt Dinniman</div>
    <p>
      First off, I did the audio book instead
      of the paper copy. I don't know how much
      I would have liked the physical version
      but the narrator for the audio book
      is absolute gold. 
    </p>
    <p>
      etc.
    </p>
  </div>
</div>
<p>Achieving that layout in Markdown
would require writing the HTML
directly in the file. That's
entirely possible but removes
the ability to change the layout
without editing every document
that has a book review in it.
It also means you can't
use the same content in
multiple ways without duplicating it.</p>
<h3>Data Access</h3>
<p>NeoDoc allows section
content, flags, and attributes to
be treated as data that's available
beyond the individual notes
that contain them. Consider
a collection of notes that
have book reviews scattered
among them. You can generate
a page that lists all their
titles and authors in one
place with links pointing
to the full review. Another
page could be created for
each author listing all the
books by them that you've
reviewed.</p>
<p>Your content effectively
becomes a database you can
query to output content
in any number of ways.
All without having to maintain
different copies of the
same content in multiple places.</p>
<h2>Wrap-Up</h2>
<p>NeoDoc is designed to be as simple as
possible while providing flexibility
for your content. Defining your own
sections, spans, attributes, and
flags let you create notes for just
about anything. The ability to treat
everything as data means you can
lay out, link and, index
your content out in any number of ways.</p>
<p>I've been using NeoDoc for a few
years and couldn't be happier with it.<br />
Once the parser is available, I
hope you'll enjoy it too.</p>
<p>-a</p>

<h2>Endnotes</h2>
<ul>
<li>
<p>NeoDoc was born out of frustration
with Markdown. As great as that format is,
I kept wanting to do more than it could handle.
I'd have to either inject HTML directly in
my files or switch to using database or
data files to accomplish what I wanted.
NeoDoc is designed to bridge the
gap. Full featured content can
be stored in plain-text and rendered without
the need for databases or data
formats designed more for computers
than humans.</p>
</li>
<li>
<p>The page provides the high level overview
of NeoDoc. It covers the fundamentals
without digging into specifics. For example,
it doesn't cover how sections can be nested
inside each other. Those details are covered
in the documentation that will be released when
the parser has been extracted from my website builder.</p>
</li>
<li>
<p>I've been using NeoDoc for a few years
for my web sites and personal grimoire of notes.
The later of which is currently 11,629
NeoDoc files. I've yet to run into
something it can't handle.</p>
</li>
</ul>
]]></summary>
  </entry>
  
  <entry>
    <title>Stream Tools</title><link href="https://al9000.com&#x2f;stream-tools/"/><id>urn:uuid:d2f3e1bf-0d2d-5c6b-aeb1-3cd4b0a30f70</id>
    <updated>2026-06-27T09:35:33-04:00</updated>
    <summary><![CDATA[
<h2>Overlays</h2>
<ul>
<li><a href="/stream-tools/overlays/ascii-bear-left/">ASCIIBear Left</a></li>
<li><a href="/stream-tools/overlays/facecam-right/">FaceCam Right</a></li>
</ul>


]]></summary>
  </entry>
  
  <entry>
    <title>Pondering Standard.site and the Social Web</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n3&#x2f;t9&#x2f;nx/"/><id>urn:uuid:5e50e155-e974-5250-bb20-c57af43c82d6</id>
    <updated>2026-06-25T09:01:49-04:00</updated>
    <summary><![CDATA[

<p>I've seen a bunch of references to Standard.site<sup class="footnoteLink" id="body-standard"><a href="#footnote-standard">standard</a></sup>.
It's an approach to publishing long-form content
with/in AT Protocol<sup class="footnoteLink" id="body-at"><a href="#footnote-at">at</a></sup>. The same protocol that powers bluesky<sup class="footnoteLink" id="body-bs"><a href="#footnote-bs">bs</a></sup>.
My first reaction was &quot;why would I do that when I have a website?&quot;
I didn't give it much thought<sup class="footnoteLink" id="body-posse"><a href="#footnote-posse">posse</a></sup>.</p>
<p>A post called &quot;Integrating your Atmosphere account content
in your web projects<sup class="footnoteLink" id="body-post"><a href="#footnote-post">post</a></sup>&quot; came across today.
Instead of publishing, it's about storing your content in
AT Protocol to use it as a CMS for your site.
I'm not interested in that<sup class="footnoteLink" id="body-cms"><a href="#footnote-cms">cms</a></sup>.
What caught my eye was the comments at the bottom
of the page. Some of were direct
responses. Some were attached via reference
to the posts.</p>
<p>My eyebrow went up. Spock style.</p>
<h2>Manifesto Made Real</h2>
<p>Thinking about how to make the web a better
place is my favorite pastime. To the point
where I've begun my manifesto<sup class="footnoteLink" id="body-manifesto"><a href="#footnote-manifesto">manifesto</a></sup>.
A key focus is making it easier
to share and connect web content.
The link I hit for &quot;Integrating your Atmosphere account...&quot;
is on a site called Standard Reader<sup class="footnoteLink" id="body-sr"><a href="#footnote-sr">sr</a></sup>.
It aggregates Standard.site long-form
content from across the AT Protocol
network. If you squint your eyes, it's an
RSS reader with two way communication<sup class="footnoteLink" id="body-rss"><a href="#footnote-rss">rss</a></sup>.
Damn close to what I've been thinking about.</p>
<p>If that's really what it provides,
we have a chance to vastly improve the
web. Using it to break away from
corporate controlled social media
networks<sup class="footnoteLink" id="body-break"><a href="#footnote-break">break</a></sup>.
Doing that would make the
world a better place<sup class="footnoteLink" id="body-better"><a href="#footnote-better">better</a></sup>.</p>
<p>-a</p>
<p>[aka <a href="https://bsky.app/profile/alanwsmith.com">@alanwsmith.com</a> on bluesky]</p>

<h3>Endnotes</h3>
<ul>
<li>
<p>Standard.site includes some
basic theming (in site.standard.theme.basic).
It's only four colors at the moment: foreground, background,
accent, and accentForeground.
That they have it at all is what's encouraging.
It points to the possibility for more advanced
CSS. The idea being that folks should be able to
send a CSS payload that consumers can choose
to use fully, partially, or completely ignore
at their own discretion.</p>
</li>
<li>
<p><a href="https://en.wikipedia.org/wiki/ActivityPub">ActivityPub</a> is a sibling of AT Protocol.
It's what behind <a href="https://joinmastodon.org/">Mastodon</a>.
I <a href="https://hachyderm.io/deck/@TheIdOfAlan">use it too</a>.
Nothing like Standard.site has come across my
feed from there. Would love to know if there's
something like it. (The way I look at it,
the more swings we take at breaking down corporate
social media networks the better.)</p>
</li>
<li>
<p>This post does not get into moderation.
There's an entire category of work to be
done there. Bluesky has some tools in place.
Possibly some of those can be repurposed.
Either way, there's a lot to tackle.</p>
</li>
</ul>
<h3>References</h3>
<ul>
<li>
<p><a href="https://chriscoyier.net/2026/06/01/social-rss-2/">Social RSS(?)</a> from Chris Coyier.
Just one example of other folks who are thinking about and
after the same idea.</p>
</li>
<li>
<p><a href="https://leaflet.pub/">Leaflet</a>, <a href="https://pckt.blog/">pckt</a>, and
<a href="https://offprint.app/">offprint</a> - Three services that
that provide ways to publish that use Standard.site.
I'm more interested in integrating this into my site,
but not everyone will want to do that.</p>
<p>I've only scanned the home pages of each, but the feeling
is absolutely the idea of a social web.</p>
<p>All three are paid services. I like that because
I it when I'm interacting with a business where
I'm the customer and not the commodity that's
being sold. Notes like this on the offprint home page
are great:
&quot;Funded by writers, not investors - We’re paid by
the writers who use Offprint, not advertisers or
investors. The writers remain our priority.&quot;</p>
<p>I'm coming at this from the perspective
of someone with a website looking to use
the protocol to enhance what I have. Doing
everything entirely on AT Protocol (which is
the approach these services take) is equally
valid. I wouldn't be surprise to see
it being the majority use case.</p>
</li>
<li>
<p><a href="https://sequoia.pub/blog/introducing-sequoia">Sequoia</a> -
An app that's designed to publish static sites to
ATProto. Details in <a href="https://sequoia.pub/quickstart/">the quickstart</a>.</p>
<p>This is the thing that I'm most interested in looking
at since I want to have the source of truth be
my website instead of one of the other services.
I wrote my own site builder. I expect I'll mimic
what sequoia does internally. Especially since
I use a <a href="https://neopolitan.alanwsmith.com/">custom text format</a> I designed instead
of markdown for my content. The good news
is <a href="https://docs.rs/atproto-client/0.14.5/atproto_client/index.html">there's a rust create</a>
to get me started.</p>
</li>
</ul>
<h3>Footnotes</h3>
<div class="footnote-wrapper">
<ul>
<li>
<p><a class="footnoteId" id="footnote-standard" href="#body-standard">standard</a></p>
<p><a href="https://standard.site/">Standard.site</a> - A standardized
approach to publishing long form content on AT Protocol
designed to to make it easier to discover and share.
Here's <a href="https://standard.site/docs/introduction/">the introduction page</a>.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-at" href="#body-at">at</a></p>
<p><a href="https://atproto.com/">AT Protocol</a> - The tag line on the home page is literally: Building the Social Internet.
I'm into that.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-bs" href="#body-bs">bs</a></p>
<p><a href="https://bsky.app/">Bluesky</a> - The social media platform built
on the AT Protocol.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-posse" href="#body-posse">posse</a></p>
<p>I didn't give it enough though to consider it from an
<a href="https://indieweb.org/">IndieWeb</a> <a href="https://indieweb.org/POSSE">POSSE</a>
perspective: Publish on your Own Site. Syndicate Everywhere.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-post" href="#body-post">post</a></p>
<p><a href="https://standard-reader.app/a/did:plc:s2rczyxit2v5vzedxqs326ri/3m56tzfj5pc2a">Integrating your Atmosphere account content in your web projects</a> - the
post that got me thinking about standard.site again.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-cms" href="#body-cms">cms</a></p>
<p>I'm one of those hacker types who ignores the general advice against
writing your web site builders. (<a href="/blog/1e/nr/w0/">This post</a> is a
draft at press time, but it'll give you an idea.)</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-manifesto" href="#body-manifesto">manifesto</a></p>
<p><a href="https://www.alanwsmith.com/en/2v/xa/cn/vj/">A Vision for the Web</a> (originally
titled &quot;A Website Manifesto&quot;. Despite still being a draft made up mainly
of scratch notes the ideas are all there.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-sr" href="#body-sr">sr</a></p>
<p><a href="https://standard-reader.app/">standard-reader.app</a> A site
that aggregates long-form content from the AT Protocol network.
Very much in line with what I'm thinking about for
make the web a better place.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-rss" href="#body-rss">rss</a></p>
<p>Of course, this isn't RSS. It's AT Protocol. I'm
referring only to the user experience of
an RSS reader.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-break" href="#body-break">break</a></p>
<p>Engaging with readers and customers is tough on traditional
websites. Setting up account management (and its customer
support), interaction, and moderation are a lot of work.
Social media sites handle all that. It's easy to
see why individuals and companies follow that
path of least resistance. Something like
Standard.site offers removing the burden of
account management and interaction. Moderation
won't come out of the box. I expect services
will pop-up to assist with that as well.</p>
</li>
<li>
<p><a class="footnoteId" id="footnote-better" href="#body-better">better</a></p>
<p>Corporate social networks aren't made
for us. They're made to make money.
They turn our time, attention, and
content into chum to feed their algorithms
designed to maximize shareholder value.
Standard.site and the services using
it offer a way to regain control
of our content and, by extension,
our time and attention.</p>
<p>Corporations will still participate
in social media. They just won't
own it.</p>
</li>
</ul>
</div>
]]></summary>
  </entry>
  
  <entry>
    <title>Konami</title><link href="https://al9000.com&#x2f;konami/"/><id>urn:uuid:0a1bbe0f-c170-523c-83a5-f17055a6dea6</id>
    <updated>2026-06-23T19:29:25-04:00</updated>
    <summary><![CDATA[

<bitty-9 data-connect="/konami/bit.js"></bitty-9>

<div class="wrapper">
  <div class="center">
    <div>konami</div>
    <div class="small">[enter code]</div>
  </div>
  <div id="screen">
    <div>
      <div class="letters" data-r="output fail"></div>
      <div data-r="accepted"></div>
    </div>
  </div>
  <div class="faded">
<footer class="default-wrapper xxlarge-block-padding accent-top-border xxxlarge-top-margin">
  <div class="small-font-size text-align-center">
    <a href="/">home</a>
  </div>
  <div class="small-font-size text-align-center">
    from <a href="/">alan w smith</a>
  </div>
  <div class="small-font-size text-align-center">
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  <div class="small-font-size text-align-center">
    <a href="/rss/">rss feed</a>
  </div>
</footer>  </div>
</div>



<script type="text/html" data-template="letter">
  <span class="letter" data-r="key__NUM__">_</span>
</script>


]]></summary>
  </entry>
  
  <entry>
    <title>Type Different: Changing the Keys on Your Keyboard</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n3&#x2f;g3&#x2f;x8/"/><id>urn:uuid:93677c41-e871-5424-8602-1fa52f3f4809</id>
    <updated>2026-06-21T12:22:00-04:00</updated>
    <summary><![CDATA[
<h2>Keyboard Basics</h2>
<p>There's a few things to know about
keyboards you plug into your computer:</p>
<ol>
<li>
<p>They have little computers
in them.</p>
</li>
<li>
<p>When you press a key, the little
computer in the keyboard sends a
signal to your actual computer telling
it what key you pressed.</p>
</li>
<li>
<p>The little computer in your keyboard
is programmed with a map that defines
which keys send what signals to your computer
(i.e. when you press the &quot;a&quot; it sends
and &quot;a&quot; signal).</p>
</li>
<li>
<p>Some keyboards let you reprogram
the map to change the signals
each key sends (e.g. you can set it
up so the &quot;a&quot; key sends the &quot;z&quot; signal).</p>
</li>
</ol>
<p>(Keyboards built into laptops work
the same way. It's just a little easier
to think about them as separate things
for this post.)</p>
<h2>Good Defaults</h2>
<p>Each keyboard come with a default map
that defines the signal each
physical key sends to your computer.
That map is what lets different keyboards
lay out keys in different ways. For example, the
&quot;Alt&quot; key on this keyboard is the
third one from the left.</p>
<p><img src="keyboard-1-37044873_cac84b17f7_o.jpg"
alt="A close up of the lower left corner of black keyboard with white lettering. The first three keys on the bottom row are 'Ctrl', 'Fn', and 'Alt'."
/></p>
<p>On this one, (where it's labeled both &quot;alt&quot; and &quot;option&quot;)
it's the second from the left.</p>
<p><img src="keyboard-2-4389417539_ec4be54c14_k.jpg"
alt="A view of the lower left corder of a white keyboard with black lettering. The first three keys on the bottom row are 'control', 'alt / option', and 'command'."
/></p>
<p>Thanks to the maps, the computer
receives the same &quot;Alt&quot; signal regardless
of where the key sits on the keyboard.</p>
<h2>Change-Up</h2>
<p>You can change things around if you're
keyboard has a way to reprogram the mapping.
For example, you could reverse the letters of the alphabet.
So, pressing an &quot;a&quot; sends the signal for a &quot;z&quot;, &quot;b&quot; does &quot;y&quot;, etc...
Probably a bad idea, but totally possible.</p>
<p>A more practical example is moving frequently used keys
so they are easier to reach. As an example,
I use parenthesis all the time when I'm programming.
By default, the &quot;(&quot; and &quot;)&quot; keys are mapped so you
have to reach up to the number row and
hold shift to type them.</p>
<p>I updated the map on my keyboard so it sends
the signal for &quot;(&quot; when I hit the &quot;j&quot; key
while holding down the &quot;control&quot; (aka &quot;Ctrl&quot;) key.
The &quot;l&quot; key does the &quot;)&quot;.</p>
<h2>Landing Changes</h2>
<p>I use a keyboard called a Moonlander. It looks
like this:</p>
<p><img src="moonlander-white.png"
alt="A white moonlander keyboard. It's a split keyboard with a wire that connects the left and right pieces."
/></p>
<p>Here's how the keys are mapped for the right half:</p>
<p><img src="moonlander-right-1.jpg"
alt="A graphic showing the right half of a moonlander keyboard with letters in their stander positions."
/></p>
<p>When I press the &quot;control&quot; key, they switch to this:</p>
<p><img src="moonlander-right-2.jpg"
alt="A graphic showing the right half of a moonlander keyboard. It shows various symbols like '(' and '{' that are on or closer to the home row than a standard keyboard layout."
/></p>
<p>That's how I get the parenthesis under &quot;j&quot; and &quot;l&quot;.</p>
<p>The keys are mapped specifically to reduce
how far I have to reach when programming.
The goal is to reduce the risk of repetitive
strain injury (RSI) issues.</p>
<h2>The Rabbit Hole</h2>
<p>In theory, you can update the mapping
layout on any keyboard. In practice,
that's not the case. You can only
do it if the manufacturer provides
an app that let you do it<sup>1</sup>.</p>
<p>Lots of &quot;mechanical keyboards&quot; provide
that software. Start looking into those
if you want to change things up.
Fair warning though, there are a billion
options and even more opinions.</p>
<p>Totally worth it, though.</p>
<p>-a</p>
<div class="xxlarge-top-margin xxlarge-bottom-margin xsmall-font-size faded-reverse-color text-align-right faded-reverse-block-border">end of line</div>
<h3>Endnotes</h3>
<ul>
<li>
<p>I glossed over some of the complexities
of how keyboards work. For example,
the signal that's sent when you press a
specific key is a code instead of
an actual character.</p>
</li>
<li>
<p>It's also possible to update some
computers so they do different things
when they receive given signals. For example,
you press the &quot;a&quot; key and your keyboard
sends the &quot;a&quot; signal, but the computer
acts like it received a &quot;z&quot; signal
and types that. It's been a while
since I've looked into that. Last
time I did, the options weren't great.</p>
</li>
<li>
<p>The full keyboard layout mapping
for my moonlander is
<a href="https://configure.zsa.io/moonlander/layouts/APODe/latest/0">on this page</a>.</p>
</li>
</ul>
<h3>Footnotes</h3>
<ul>
<li>
<p><sup>1</sup> you can also get into hardware hacking, but
that's a different thing entirely.</p>
</li>
</ul>
<h3>Image Sources</h3>
<ul>
<li>
<p><a href="https://www.flickr.com/photos/ozzzie/37044873/in/photolist-4gS9H-37iJVd-3w9mE-26jA6Jk-6bitL-uE7wS-MLHsd-gsxYB-569niC-oqisgw-9VfpC-b1qMG-bGGgo-4WrmRD-Lrcg5R-4myiwF-9BVHmk-xAMYw-6sHJFL-5tSaJe-5tWxV3-cRGCnh-7dcFo-kZo7LT-cRGCD1-cRJxT1-8jqLdc-kZpw1q-b1qNV-c55zTU-7bNZYS-bFxRCV-b1qEA-7FSUUK-b1qXQ-7edja8-J3igiF-8jbB6-d8auR5-obNw2V-JY2ip-b1qYP-8oZRpA-L9DJUs-avL4Y-BYwmWW-7FWR7U-a7yGeX-jKTfVv-4nMqXb">keyboard 1</a></p>
</li>
<li>
<p><a href="https://www.flickr.com/photos/njtechteacher/4389417539/in/photolist-b1qNV-c55zTU-7bNZYS-bFxRCV-b1qEA-7FSUUK-b1qXQ-7edja8-J3igiF-8jbB6-d8auR5-obNw2V-JY2ip-b1qYP-8oZRpA-L9DJUs-avL4Y-BYwmWW-7FWR7U-a7yGeX-jKTfVv-4nMqXb-e9Kru-vezru-7vqNu2-3eYMc3-HdeRa-knMJ6Z-4GBua3-KysRnh-8j4dT1-9kUmhm-9JfDUW-4QvoK8-6QXd7-7r56jn-aNXewX-cyoJC-c55ztQ-5Ba1U-qC8NDY-9U4Zua-SpyDDs-6YJ7Mv-7DMSG1-66ygcE-4tXpkE-9a378S-TVfw-8TuUUz">keyboard 2</a></p>
</li>
<li>
<p><a href="https://www.zsa.io/moonlander">moonlander</a></p>
</li>
</ul>


]]></summary>
  </entry>
  
  <entry>
    <title>RSS Powers: Activated</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n3&#x2f;fm&#x2f;ag/"/><id>urn:uuid:2785568a-7ada-54a0-8cd1-a5f3596f3b7a</id>
    <updated>2026-06-21T07:56:00-04:00</updated>
    <summary><![CDATA[

<p>I started moving my site from <a href="https://www.alanwsmith.com/">alanwsmith.com</a>
over here to <a href="https://al9000.com/">al9000.com</a> earlier this year.
I started with basic pages. The first blog post came in April.
That post is called <em>I'm Not Ready to Start This Blog</em><sup>1</sup>.
One of the reasons I wasn't ready was I hadn't built
an RSS feed for the site yet<sup>2</sup>.</p>
<p>As of yesterday, the RSS feed is operational. There's
still work to do. Things like adding
a little header to posts that feature JavaScript
based features that won't work in most feed readers.
All that stuff will come in time. The important
part is the basics are in place and ingestible now.</p>
<p>You can pick it up <a href="/rss/">on this page</a>.</p>
<p>-a</p>

<h2>Endnotes</h2>
<ul>
<li>
<p>Right now, the feed only contains blog posts.
One feature on the TODO list is to provide a way
to include other pages into it as well. For example,
I don't want to have to make a separate blog post
for projects (e.g. my <a href="/qr-clock/">QR Code Clock</a>).
I just want them to show up in feed.</p>
</li>
<li>
<p>Careful observers will note: the feed isn't
actually RSS. It's Atom. I'm using that format
because it <a href="https://datatracker.ietf.org/doc/html/rfc4287">has an RFC</a>.
As far as I can tell, RSS does not. With the vastness
of technology, I'm sure there are cases where
the difference matters. I'm not aware of them.
Nor am I worried about them.</p>
<p>Past me worried about the fact that I called it
an RSS feed even though it's Atom. I've grown
less pedantic. Folks are more familiar with
the term RSS. Atom works in readers.
That's all I need.</p>
</li>
</ul>
<h2>Footnotes</h2>
<ul>
<li>
<p><sup>1</sup> <a href="/blog/1e/bk/0i/">I'm Not Ready To Start This Blog</a> - in
which I make the first post on this site just to get started.
The only thing I really had set up for it was the folder and
the naming convention I'm using for the page addresses/urls.</p>
<p>I could have waited until I was &quot;more ready&quot;. That way
lies dragons. The big one of paralysis by perfection,
in particular.</p>
</li>
<li>
<p><sup>2</sup> this site is built from
a custom site builder I'm building specifically
for it. The builder is very much an early
work in progress. The general advice is not
to make your on site builders. After a decade
and a half working on the web I disagree
with that for those with the skill set
to make their own.</p>
<p>It's slower to start, but the time you spend
on it is like compounding interest over time.
Especially compared to the never ending treadmill of
jumping to new frameworks.</p>
</li>
</ul>
]]></summary>
  </entry>
  
  <entry>
    <title>Unoffice Hours</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n3&#x2f;fk&#x2f;am/"/><id>urn:uuid:162046c8-1547-59e0-bcb6-4edf32841cee</id>
    <updated>2026-06-21T07:39:00-04:00</updated>
    <summary><![CDATA[
<p>This is a fun concept. Folks who set aside a little time
each week to take calls with whoever about whatever.</p>
<p><a href="https://unofficehours.com/">unoficehours.com</a></p>
<p>I've got a bunch of traveling to do. Setting
up calls with some folks is on the list
for when I get back.</p>
<p>-a</p>
<h3>Endnotes</h3>
<ul>
<li>
<p>I'll totally be using this to talk with
techy folks about bitty to get feedback from
them.</p>
</li>
<li>
<p>For the non-techy folks, we'll play the
conversations by ear and see where they go.</p>
</li>
</ul>


]]></summary>
  </entry>
  
  <entry>
    <title>Project Ideas</title><link href="https://al9000.com&#x2f;ideas/"/><id>urn:uuid:4e0342ef-1f09-5d77-a346-d2314750e31a</id>
    <updated>2026-06-20T19:42:00-04:00</updated>
    <summary><![CDATA[

<p><bitty-9 data-connect="/ideas/bit.js"></bitty-9></p>
<div class="dynamic-wrapper">
  <div class="idea-wrapper">
    <div data-r="newIdea"></div>
  </div>
  <!--
  <div class="selection-wrapper">
    <div>
    <input id="general" type="radio" name="selector" checked autocomplete="off"/>
    <label for="general">General Ideas</label>
    </div>
    <div>
    <input id="personal" type="radio" name="selector" autocomplete="off" />
    <label for="personal">My Personal Ideas</label>
    </div>
  </div>
-->
  <div class="button-wrapper">
    <button data-s="newIdea">Get a New Idea</button>
  </div>
</div>
<div class="html-wrapper">
  <div class="general-ideas">
<ul>
<li>
<p>Gather the lyrics from your 25 favorite songs and do a word <a href="https://en.wikipedia.org/wiki/Frequency_analysis">frequency analysis</a></p>
</li>
<li>
<p>Make an extension to pull your notes out of the Amazon Kindle Notebook page</p>
</li>
<li>
<p>Make a web page that lets you sort a JavaScript class alphabetically</p>
</li>
<li>
<p>Make Hungry Hungry Hippos, but with cats</p>
</li>
<li>
<p>Make a website that displays the number of tabs you have open</p>
</li>
<li>
<p>Make a <a href="https://bongo.cat/">Bongo Cat</a> clone</p>
</li>
<li>
<p>Make a page of <a href="https://en.wikipedia.org/wiki/List_of_common_misconceptions">common misconceptions</a></p>
</li>
<li>
<p>Make a GitHub Stars web component</p>
</li>
<li>
<p>Make a HypnoToad site</p>
</li>
<li>
<p>Make a site to design winamp skins</p>
</li>
<li>
<p>A site where you design your own '80s style cassette tape</p>
</li>
<li>
<p>Make a waveform generator for making visualization when doing recordings</p>
</li>
<li>
<p>A browser extension that shows that Open Graph/Preivew image for a web page so you can check it easily</p>
</li>
<li>
<p>Make a web version of Pipe Dreams</p>
</li>
<li>
<p>Make a configurable countdown timer</p>
</li>
<li>
<p>Build a site that displays a random photo of a corgis pulled automatically from <a href="https://unsplash.com/">Unsplash</a> every time you refresh the page</p>
</li>
<li>
<p>A bot that lets you know how many of the <a href="https://womenofjamstack.com/">womenofjamstack.com</a> folks you follow</p>
</li>
<li>
<p>An app that you feed a bunch of words that it uses to make bingo cards</p>
</li>
<li>
<p>Programmatically make a googly eyes gif</p>
</li>
<li>
<p>Make a fibonacci clock</p>
</li>
<li>
<p>Change a web page pointer to googly eyes and place them automatically on photos (like <a href="https://pointerpointer.com/">pointerpointer.com</a>)</p>
</li>
<li>
<p>Build a site that displays a random photo of a corgis pulled automatically from <a href="https://unsplash.com/">Unsplash</a> every time you refresh the page</p>
</li>
<li>
<p>Create some type of lorem ipsum generator (e.g. with music terms)</p>
</li>
<li>
<p>Generate automatic playlists using the <a href="https://musicbrainz.org/doc/MusicBrainz_API">MusicBrainz API</a></p>
</li>
<li>
<p>Create generative art like the stuff from <a href="https://georgefrancis.dev/">George Francis</a></p>
</li>
<li>
<p>Make a collection of animated gifs/webps that do something cool together</p>
</li>
<li>
<p>Use a word you have trouble remembering how to spell and make a site like <a href="https://d-e-f-i-n-i-t-e-l-y.com/">d-e-f-i-n-i-t-e-l-y.com</a></p>
</li>
<li>
<p>Extract and display color samples from movies showing the average color of each frame</p>
</li>
<li>
<p>Pull all frames from a movie and make them small thumbnails and output them linerally</p>
</li>
<li>
<p>Pull thumbnails from frames of a movie and display them individually at random points of the page instead of showing them as a video.</p>
</li>
<li>
<p>Use the thumbnails of frames from a movie to create a timeline that shows only the first frame from each scene change</p>
</li>
<li>
<p>Do one of those photo mosaic images where you make a picture out of smaller images using movie thumbnails (like <a href="https://www.pinterest.com/pin/692358142710574224/">this one</a>) but have the thumbnails transition between movies (e.g. Matrix 1, 2, 3, and 4)</p>
</li>
<li>
<p>Setup a random color generator that shows complimentary colors as well</p>
</li>
<li>
<p>Generate random color pallets based off color theory</p>
</li>
<li>
<p>Spin multiple versions of a photo at different rates on one page (like rotate it with some type of css or js)</p>
</li>
<li>
<p>Create a page that shows three copies of a character image that jumps to thirty if you enter the <a href="https://en.wikipedia.org/wiki/Konami_Code">konami code</a></p>
</li>
<li>
<p>Whack-A-Mole</p>
</li>
<li>
<p>Make a site with a sound board of clips from <a href="https://www.youtube.com/watch?v=GBmg7WTyfYw">Speak and Spell/Math</a></p>
</li>
<li>
<p>Make your own synth voice like <a href="https://www.youtube.com/watch?v=GBmg7WTyfYw">Speak and Math</a></p>
</li>
<li>
<p>Make a web version of <a href="https://en.wikipedia.org/wiki/Speak_%26_Spell_(toy)">Speak and Spell</a></p>
</li>
<li>
<p>Make one of those games with the paper thing with four pyramids that you put your fingers in and write letters and numbers on them and then close and open them and then lift a flap to see whatever's written there</p>
</li>
<li>
<p>Pick a random character and fill the window with it in a random order (this is one of the first things I did on my grandfather's TI-99/4A)</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Space_Invaders">Space Invaders</a> clone</p>
</li>
<li>
<p>Build a Tic-tac-toe game where you play against the computer</p>
</li>
<li>
<p>A &quot;this page intentionally left blank&quot; site with random fonts, colors, etc...</p>
</li>
<li>
<p>Make a clock but use <a href="https://github.com/segmentio/ksuid">KSUIDs</a> to display the time</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Seven-segment_display">seven-segment display</a> clock</p>
</li>
<li>
<p>Setup an &quot;Is it Friday?&quot; page with just a Yes/No answer on it</p>
</li>
<li>
<p>Write a little tool to alphabetize lists of text</p>
</li>
<li>
<p>Make a font book that shows font examples from google fonts but with a selection of colors and effects</p>
</li>
<li>
<p>Make a font display page that lets you see multiple google fonts at the same time (e.g. as a heading and as body text)</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Binary_clock">binary clock</a></p>
</li>
<li>
<p>Display color pallet examples for a CSS framework like <a href="https://tailwindcss.com/">tailwind</a></p>
</li>
<li>
<p>Plot default terminal colors in a 3D space with <a href="https://threejs.org/">three.js</a></p>
</li>
<li>
<p>Create a current weather conditions site</p>
</li>
<li>
<p>Make a weather forecast page</p>
</li>
<li>
<p>Setup a service that reads the weather forcast and lets you know if you should bring a coat or not</p>
</li>
<li>
<p>Build a bot to cross post your content from one platform to another</p>
</li>
<li>
<p>Make a page that displays a random quote from a collection you setup</p>
</li>
<li>
<p>Run stats on your social media followers to see the distribution of the number of followers the folks who follow you have</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Pong">pong</a> clone</p>
</li>
<li>
<p>Make a jenga clone</p>
</li>
<li>
<p>Make a tetris clone</p>
</li>
<li>
<p>Make a battleship clone</p>
</li>
<li>
<p>Make a minesweeper clone</p>
</li>
<li>
<p>Make a space invaders clone</p>
</li>
<li>
<p>Make a shoots/snakes and ladders clone</p>
</li>
<li>
<p>Plot word frequencies for podcasts based on their transcripts</p>
</li>
<li>
<p>Build a website with only a single html file (i.e. no framework) with the words &quot;Hello, World&quot;</p>
</li>
<li>
<p>Get word stats from pages/sites that have RSS feeds (to make it easier to get the data)</p>
</li>
<li>
<p>Build your own podcast feed with a collection of podcasts you like (e.g. <a href="https://www.alanwsmith.com/the-pod-of-alan">this one ;-)</a>) sorted in the order you like</p>
</li>
<li>
<p>Run stats on the metadata for your photos to see what day of the week you take the most photos</p>
</li>
<li>
<p>Make a bubble pop site like <a href="https://bubblespop.netlify.app/">this one</a></p>
</li>
<li>
<p>Setup a coin flip page</p>
</li>
<li>
<p>Make an all work and no play makes jack a dull boy site (like <a href="https://jacktorrance.blog/">this</a>) but set to music</p>
</li>
<li>
<p>Create a page with matrix style green text animated page but you can change the color and the direction the glyphs move</p>
</li>
<li>
<p>Make one of those pair matching games where there's a grid of tiles that you turn over two at a time to find matches, but use animated gifs</p>
</li>
<li>
<p>Setup a count-down timer showing how long until the next time your team plays</p>
</li>
<li>
<p>Make an &quot;Is YOUR TEAM playing today?&quot; page with simple yes/no on it</p>
</li>
<li>
<p>Pick a topic and make a site like <a href="http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/">hasthelargehadroncolliderdestroyedtheworldyet</a> that never changes</p>
</li>
<li>
<p>Create a data visualization in <a href="https://d3js.org/">D3</a> using census data to show the average age in each state</p>
</li>
<li>
<p>Graph of the number of national championships across different football teams and coaches</p>
</li>
<li>
<p>Build an &quot;Is it Friday yet&quot; single page site with yes/no.</p>
</li>
<li>
<p>Setup a site that shows what percentage of the planet is in today/tomorrow/yesterday</p>
</li>
<li>
<p>Make a count down page with the days left in the year</p>
</li>
<li>
<p>Show a count down until all the various holidays you get off</p>
</li>
<li>
<p>Do something with <a href="https://www.remotion.dev/">remotion</a></p>
</li>
<li>
<p>Make a sound board with random bird sounds sounds</p>
</li>
<li>
<p>Create a single page site with your favorite gif on it</p>
</li>
<li>
<p>Create something like <a href="corndog.io/">corndog.io</a> but with corgis</p>
</li>
<li>
<p>Make a random name generator (pulled from list of most popular names from different name lists)</p>
</li>
<li>
<p>Setup a display page to show the schedule and scores for your favorite team</p>
</li>
<li>
<p>Build a Helmet/Hat schedule like <a href="https://fbschedules.com/2021-sec-football-helmet-schedule/">this one</a> that also shows scores and post-season play</p>
</li>
<li>
<p>Make page the embeds a youtube video multiple times but offsets their start by a little and only plays the audio from one</p>
</li>
<li>
<p>Build a <a href="https://en.wikipedia.org/wiki/Markov_chain">markov chain generator</a> with terms from programming</p>
</li>
<li>
<p>Build a <a href="https://en.wikipedia.org/wiki/Markov_chain">markov chain generator</a> with terms from football</p>
</li>
<li>
<p>Make a page where you type in a sentence and it replaces words with their related emoji</p>
</li>
<li>
<p>Build an <a href="https://familyguy.fandom.com/wiki/Evil_Monkey">evil monkey</a> page where it points to your cursor when you move it around</p>
</li>
<li>
<p>Setup cheatsheets for things you constantly have to look up</p>
</li>
<li>
<p>Make a stock market it &quot;is it up or is it down&quot; app</p>
</li>
<li>
<p>Build a display showing the sun's position in the sky throughout the day</p>
</li>
<li>
<p>Setup a display sun rise and sunset times for the day</p>
</li>
<li>
<p>Make a display showing the phase of the moon</p>
</li>
<li>
<p>Build a place holder image site like <a href="https://placekitten.com/">Place Kitten</a> but with corgis</p>
</li>
<li>
<p>Plot the weekly position over time of every song that hits the top ten</p>
</li>
<li>
<p>Make a site that takes a list of twitch streamers and just auto plays one of the ones who's live randomly</p>
</li>
<li>
<p>Display graphs of math formulas</p>
</li>
<li>
<p>Make a <a href="https://play.battlesnake.com/">Battlesnake</a></p>
</li>
<li>
<p>Recreate <a href="https://www.youtube.com/watch?v=6WpMlwVwydo">Hamster Dance</a> but with corgis</p>
</li>
<li>
<p>Make a &quot;Guess the number&quot; game with a random number that says &quot;You Win&quot; if you get it and &quot;You Lose&quot; if you don't</p>
</li>
<li>
<p>Setup a personal resume site</p>
</li>
<li>
<p>Create a virtual <a href="https://en.wikipedia.org/wiki/Spirograph">spirograph</a></p>
</li>
<li>
<p>Setup a site that list people who's birthday is the current day with data from wikipedia</p>
</li>
<li>
<p>Make a digital fireplace using svgs for the flames</p>
</li>
<li>
<p>Make a digital fishtank</p>
</li>
<li>
<p>Pull your person github stats and display them on a calendar</p>
</li>
<li>
<p>Make a calendar that puts an X over the days that have occurred</p>
</li>
<li>
<p>Build a personal RSS feed reader</p>
</li>
<li>
<p>Setup a <a href="https://tenor.com/view/cylon-battlestar-galactica-looking-around-scan-gif-9153290">Cylon</a> image with the red eye sweep</p>
</li>
<li>
<p>Make a game where you assemble robots from different drawings of arms, legs, heads, and bodies.</p>
</li>
<li>
<p>Setup a personal movie review site with up/down ratings and stats of things like your favorite genre from <a href="https://www.themoviedb.org">The Movie DB API</a></p>
</li>
<li>
<p>Generate a personal movie recommendation engine</p>
</li>
<li>
<p>Create a data visualization which shows which heroes were in which marvel movies</p>
</li>
<li>
<p>Make a personal &quot;Books I Have Read&quot; and &quot;Books I What To Read&quot; site</p>
</li>
<li>
<p>Setup a personal calendar showing holidays you get off</p>
</li>
<li>
<p>Make a social media bot that watches for the word &quot;pirate&quot; then responds with &quot;Arrrgh!&quot;</p>
</li>
<li>
<p>Do something like <a href="https://www.fugitivesheets.com/">Fugitive Sheets</a></p>
</li>
<li>
<p>Build a page to display a personal set of bookmarks and links</p>
</li>
<li>
<p>Pull forms you use from other sites and put them on your own page</p>
</li>
<li>
<p>Make a web page that sorts lists alphabetically</p>
</li>
<li>
<p>Create math forms for things like figuring out what percentage one number is of another</p>
</li>
<li>
<p>Make color pallets from your favorite games like <a href="https://www.monumentpalettes.style/">Monument Pallets</a></p>
</li>
<li>
<p>Setup an automatic, random favicon generator that makes the different sizes of favicons for a site</p>
</li>
<li>
<p>Create a clock page with clocks from different times zones</p>
</li>
<li>
<p>Make baseball cards with live stats</p>
</li>
<li>
<p>Make a golf putting game</p>
</li>
<li>
<p>Make a golf driving game</p>
</li>
<li>
<p>Make a darts game</p>
</li>
<li>
<p>Make a darts game, but with gravity reversed</p>
</li>
<li>
<p>Make a pool/billiards game</p>
</li>
<li>
<p>Create a virtual model train project where you assemble graphics to make the track</p>
</li>
<li>
<p>Make your own <a href="https://en.wikipedia.org/wiki/Magic_8-Ball">Magic 8-ball</a></p>
</li>
<li>
<p>Turn photos into 8-bit images</p>
</li>
<li>
<p>Turn photos into 2-bit images</p>
</li>
<li>
<p>Make a bot to find pages on StackOverflow with code samples that don't include proper &quot;import&quot;, etc... calls (and then fix them)</p>
</li>
<li>
<p>Build a site the displays random programming snippets and explications on each refresh</p>
</li>
<li>
<p>Create a chat app using web sockets</p>
</li>
<li>
<p>Create transcripts and closed caption automatically with the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API">Web Speech API</a></p>
</li>
<li>
<p>Build a click/tap game where a target shows up randomly on the page that you have to cick and then another shows up and you're timed to see how quickly you can hit 20 of them</p>
</li>
<li>
<p>Sudoku, but with emoji</p>
</li>
<li>
<p>Make a sudoku game</p>
</li>
<li>
<p>Create a red light, green light game where you have to click to make progress, but if you click when it's a red light you lose</p>
</li>
<li>
<p>Build an automated screenshot re-namer that changes mac screenshot file names to something that actually sorts</p>
</li>
<li>
<p>Make your own digital <a href="https://en.wikipedia.org/wiki/Grimoire">grimoire</a></p>
</li>
<li>
<p>Build characters in CSS <a href="https://codepen.io/Niloofar_araz/pen/zYEpbKw">like these</a></p>
</li>
<li>
<p>Make your own programming challenge game like <a href="https://adventofcode.com/">Advent Of Code</a></p>
</li>
<li>
<p>Write a blog post where you solve every day of <a href="https://adventofcode.com/">Advent Of Code</a></p>
</li>
<li>
<p>Build a single page website as a subdomain of your main site every day for 30 days (don't worry about quality, just get something posted)</p>
</li>
<li>
<p>Use image recognition to count the number of chocolate chips in cookie photos</p>
</li>
<li>
<p>Auto-generate <a href="https://en.wikipedia.org/wiki/Where%27s_Wally%3F">Where's Waldo</a> images</p>
</li>
<li>
<p>Do a data visualization showing the differences between ingredients of different types of coke/soda/pop</p>
</li>
<li>
<p>Track your commute and run stats about which day averages the longest/shortest time</p>
</li>
<li>
<p>Make a data viz with the <a href="https://citymapper.com/powers">City Mapper API</a></p>
</li>
<li>
<p>Build a social media bot that posts a photo of a random corgi photo from <a href="https://unsplash.com/">Unsplash</a> every day</p>
</li>
<li>
<p>Build your own version of <a href="https://apod.nasa.gov/apod/astropix.html">Astronomy Picture Of the Day</a> from the <a href="https://data.nasa.gov/Space-Science/Astronomy-Picture-of-the-Day-API/ez2w-t8ua">NASA API</a></p>
</li>
<li>
<p>Build a <a href="https://en.wikipedia.org/wiki/Compound_interest">compound interest</a> calculator</p>
</li>
<li>
<p>Make a space weather conditions site with data from the <a href="https://ccmc.gsfc.nasa.gov/donki/">Space Weather Database Of Notifications, Knowledge, Information (DONKI)</a> from <a href="https://ccmc.gsfc.nasa.gov/support/DONKI-webservices.php">NASA's API</a></p>
</li>
<li>
<p>Make a lorem ipsum generator with pirate talk</p>
</li>
<li>
<p>Make a white noise generator with different choices for the audio track</p>
</li>
<li>
<p>Visualize the sounds waveform of your favorite song</p>
</li>
<li>
<p>Make Beat Saber as a typing game</p>
</li>
<li>
<p>Plot the average beats per minute of top ten songs for the past fifty years</p>
</li>
<li>
<p>Make word clouds for the number one songs of each year</p>
</li>
<li>
<p>Make a D3 graph showing the number of times an artist made it to the top ten in the charts</p>
</li>
<li>
<p>Plot the most frequent weekly downloads from npm</p>
</li>
<li>
<p>Make a progress bar for the number of days in the year</p>
</li>
<li>
<p>Make a video player page that plays a random video from a curated playlist</p>
</li>
<li>
<p>Show standard programming techniques (e.g. looping over a list/array) in seven different programming languages</p>
</li>
<li>
<p>Build a personal version of a bookmark site like <a href="https://pinboard.in/">Pinboard</a></p>
</li>
<li>
<p>Setup a process to collect all the web pages you visit each day</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Mastermind_(board_game)">Mastermind</a> clone</p>
</li>
<li>
<p>Make Pokemon stat cards with the <a href="https://pokeapi.co/">PokeAPI</a></p>
</li>
<li>
<p>Make a text to brail tool</p>
</li>
<li>
<p>Convert text to <a href="https://en.wikipedia.org/wiki/Morse_code">Morse code</a></p>
</li>
<li>
<p>Setup a graphic that shows the binary representations of letters you type</p>
</li>
<li>
<p>Make word clouds from <a href="http://shakespeare.mit.edu/">Shakespeare</a></p>
</li>
<li>
<p>Make a <a href="https://www.youtube.com/watch?v=iJLbAntU118">warp speed</a> effect with <a href="https://motion.dev/">motion</a></p>
</li>
<li>
<p>Create your own meme generator that lets you put text on images</p>
</li>
<li>
<p>Build emoji in <a href="https://www.blender.org/">Blender</a></p>
</li>
<li>
<p>Make your own election map</p>
</li>
<li>
<p>Create an info graphic showing governmental spending (e.g. <a href="https://www.visualcapitalist.com/death-taxes-2015-visual-guide-tax-dollars-go/">this one</a>)</p>
</li>
<li>
<p>Setup a process to remind you of people's birthdays</p>
</li>
<li>
<p>Build a process that solves <a href="https://en.wikipedia.org/wiki/Six_Degrees_of_Kevin_Bacon">six-degrees of Kevin Bacon</a> for movie actors</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Pictionary">Pictionary</a> clone</p>
</li>
<li>
<p>Make a game where you fill the scree with a character like &quot;/&quot; and then randomly place a &quot;|&quot; that you have to find</p>
</li>
<li>
<p>Make an audio equalizer display but using letters</p>
</li>
<li>
<p>Build an app that beeps at you if you type &quot;teh&quot; instead of &quot;the&quot;</p>
</li>
<li>
<p>Setup a process that ping you to remind you to hydrate</p>
</li>
<li>
<p>Make a site where you type in a word and it give you a corresponding <a href="https://xkcd.com/">XKCD</a></p>
</li>
<li>
<p>Run OCR on <a herf="https://xkcd.com/">XKCD</a> so you can search them</p>
</li>
<li>
<p>Build a live transcription service for streamers with <a href="https://deepgram.com/">Deepgram</a></p>
</li>
<li>
<p>Make a data visualization showing how long characters were alive in each episode of Game Of Thrones</p>
</li>
<li>
<p>Make a live data visualization connecting directors and actors with data from <a href="https://developers.themoviedb.org/3/getting-started/introduction">The Movie Database API</a></p>
</li>
<li>
<p>Build an spaced repetition flashcard system like <a href="https://apps.ankiweb.net/">Anki</a></p>
</li>
<li>
<p>Make your own <a href="https://miro.com/">miro</a> style board</p>
</li>
<li>
<p>Make a jokes page where it shows you a random joke and then click a button to see the answer</p>
</li>
<li>
<p>Use a data visualization tool to visualize the same data set three different ways</p>
</li>
<li>
<p>Replay the git history of a project showing the changes for files without moving them around</p>
</li>
<li>
<p>Make an &quot;<a href="https://jacktorrance.blog/">All work and no play makes Jack a dull boy</a>&quot; site</p>
</li>
<li>
<p>Make a spot the differences game that displays two photos where one has minor modifications that you have to find</p>
</li>
<li>
<p>Build a site where users login via their GitHub accounts and save a favorite color</p>
</li>
<li>
<p>Make a game with letters swapped out randomly where you have to swap them back in to decode the original text</p>
</li>
<li>
<p>Make a Caesar encryption page</p>
</li>
<li>
<p>Make a personal photo sharing site for you and your family and friends</p>
</li>
<li>
<p>Build your own chat client for you and your friends</p>
</li>
<li>
<p>Make your own color theme for your text editor</p>
</li>
<li>
<p>Create a new color theme for your syntax highlighter of choice</p>
</li>
<li>
<p>Make SVG emoji faces by hand</p>
</li>
<li>
<p>Write code to create emoji faces in SVG</p>
</li>
<li>
<p>Make an animated &quot;This Is Fine&quot; page where the flames are moving SVGs</p>
</li>
<li>
<p>Build your own comment system for a JamStack site</p>
</li>
<li>
<p>Automated Open Graph images with the titles of your posts</p>
</li>
<li>
<p>Do word analysis on your posts and automatically pull a related image from <a href="https://unsplash.com/">Unsplash</a> to generate an Open Graph image</p>
</li>
<li>
<p>Make a page of dad jokes that shows you the joke with a link to hit to see the punch line</p>
</li>
<li>
<p>Code a social media bot that randomly posts <a href="https://www.cs.columbia.edu/~hgs/audio/harvard.html">Harvard Sentences</a></p>
</li>
<li>
<p>Make a color mixer where you give it three numeric values for red, green, and blue and it shows the color</p>
</li>
<li>
<p>Make a hex code based color mixer with separate in puts for red, green, and blue</p>
</li>
<li>
<p>Build a personal movie review site</p>
</li>
<li>
<p>Build a Show And Movies To Watch app to keep track of stuff you want to see</p>
</li>
<li>
<p>Make a subdomain for every day of the week with a random image and saying for the day</p>
</li>
<li>
<p>Make a Random XKCD Of The Day site</p>
</li>
<li>
<p>Build a site that collects all the stats (e.g. followers, likes, posts) from all the site you have an account on and combine them into one display</p>
</li>
<li>
<p>Code your own video embed player</p>
</li>
<li>
<p>Make a Ludicrous Speed site that goes plaid</p>
</li>
<li>
<p>Make <a href="https://http.cat/">http.cat</a> but with corgis</p>
</li>
<li>
<p>Create a bot the receives <a href="https://dev.twitch.tv/docs/eventsub">Twitch EventSub notifications</a> when someone goes live and sends you a text via <a href="https://www.twilio.com/">Twilio</a></p>
</li>
<li>
<p>Create a public bridge app that receives <a href="https://dev.twitch.tv/docs/eventsub">Twitch EventSub notifications</a> that you can connect to with web sockets to see the notifications on a private network</p>
</li>
<li>
<p>Find the API for your favorite game and make a personal stats page</p>
</li>
<li>
<p>Code your own video page with the <a href="https://docs.medal.tv/">medal API</a></p>
</li>
<li>
<p>Make your own YouTube recommendation engine</p>
</li>
<li>
<p>Setup a <a href="https://docs.google.com/spreadsheets/u/0/?tgif=d">Google Sheets</a> spreadsheet as an &quot;Episodes I've Watched&quot; tracker and use it as the data source for a web page</p>
</li>
<li>
<p>Make a recipe site</p>
</li>
<li>
<p>Make a recipe site that uses the <a href="https://docs.instacart.com/">Instacart API</a> to determine prices</p>
</li>
<li>
<p>Make your own app to control LED lights</p>
</li>
<li>
<p>Build an WiFi controlled LED candle out of a raspberry pi</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Blinkenlights">Blinkenlights</a> page</p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/Blinkenlights">Blinkenlights</a> display with a raspberry pi</p>
</li>
<li>
<p>Make a list of the movies you've watched and plot the most watched actors and directors</p>
</li>
<li>
<p>Use facial recognition to determine screen time for each actor in a movie</p>
</li>
<li>
<p>Pipe a movie through different speech recognition engines and do a diff of the output</p>
</li>
<li>
<p>Write a generative art tool to create random header images for</p>
</li>
<li>
<p>Write a program to automatically generate the solutions to &lt;&lt;link|monocrack|https://monocrack.alanwsmith.com/&gt;&gt; puzzles</p>
</li>
<li>
<p>Make a clock, but with QR codes for the display</p>
</li>
<li>
<p>Design your own QR code</p>
</li>
<li>
<p>Make a form to fill in that automatically generates meta tags for your site</p>
</li>
<li>
<p>Make your own sticky notes app</p>
</li>
<li>
<p>Turn photos into ASCII art</p>
</li>
<li>
<p>Make a <a href="https://www.powerlanguage.co.uk/wordle/">Wordle</a> clone</p>
</li>
<li>
<p>Build a bot to solve <a href="https://www.powerlanguage.co.uk/wordle/">Wordle</a></p>
</li>
<li>
<p>Make a movie out of a set of images like screen grabs from <a href="https://configure.zsa.io/moonlander/layouts/APODe/latest/0">keyboard layout changes</a></p>
</li>
<li>
<p>Make interesting looking dashboards in <a href="https://d3js.org/">D3</a></p>
</li>
<li>
<p>Build a dedicated Read Later tablet app that uses <a href="https://pinboard.in/">Pinboard</a> as a back end and maintains your position in multi page texts</p>
</li>
<li>
<p>Make your own create-next-app template for making new sites</p>
</li>
<li>
<p>Make a site with samples from <a href="https://supercollider.github.io/">SuperCollider</a></p>
</li>
<li>
<p>Make a site that's a front end to <a href="https://supercollider.github.io/">SuperCollider</a></p>
</li>
<li>
<p>Build your own dynamic image transformation service (like <a href="https://cloudinary.com/">Cloudinary</a>)</p>
</li>
<li>
<p>Make a bot that automatically updates your profile picture based on the time of day</p>
</li>
<li>
<p>Create your own version of the <a href="https://css-tricks.com/almanac/">CSS-Tricks Almanac</a></p>
</li>
<li>
<p>Make and send out your own e-cards</p>
</li>
<li>
<p>Build a CI/CD pipeline from scratch to deploy a one page site</p>
</li>
<li>
<p>Use <a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/">Beautiful Soup</a> to gather sub-headers from the <a href="https://en.wikipedia.org/wiki/Web_scraping">Wikipedia We Scraping page</a></p>
</li>
<li>
<p>Write a process to turn each word on the <a href="https://en.wikipedia.org/wiki/CSS">Wikipedia CSS page</a> a random color</p>
</li>
<li>
<p>Build your own browser start tag with personalized links and form inputs stored in a database</p>
</li>
<li>
<p>Write a program to find the fastet <a href="https://en.wikipedia.org/wiki/Wikipedia:Wikirace">Wikipedia Race</a> path between <a href="https://en.wikipedia.org/wiki/Quain_Professor">Quain Professor</a> and <a href="https://en.wikipedia.org/wiki/Alan_R._Moon">Alan R. Moon</a></p>
</li>
<li>
<p>Build your own version of <a href="https://en.wikipedia.org/wiki/Catan">The Settlers of Catan</a></p>
</li>
<li>
<p>Write your own <a href="https://en.wikipedia.org/wiki/Solitaire">Solitare</a> game</p>
</li>
<li>
<p>Build a calculator and D3 data visualization that shows compound interest working of saving vs debt</p>
</li>
<li>
<p>Write a program to solve the daily <a href="https://monocrack.alanwsmith.com/">monocrack</a> puzzle</p>
</li>
<li>
<p>Mkae a bsowrer eitnxeosn taht smrcalbes the isinde lteters of wdors lkie tihs</p>
</li>
<li>
<p>Write a browser extension that logs all the sites you visit each day</p>
</li>
<li>
<p>Track the domains you visit for a month and create a D3 graph showing the frequency</p>
</li>
<li>
<p>Plot the basic <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">ANSI Colors</a> in a <a href="https://threejs.org/">three.js</a> visualization</p>
</li>
<li>
<p>Generate the waveform of a song in <a href="https://threejs.org/">three.js</a></p>
</li>
<li>
<p>Make a rotating cube in <a href="https://threejs.org/">three.js</a></p>
</li>
<li>
<p>Make a <a href="https://en.wikipedia.org/wiki/SMPTE_color_bars">bars and tone</a> web page</p>
</li>
<li>
<p>Make a three dimensional <a href="https://en.wikipedia.org/wiki/SMPTE_color_bars">bars and tone</a> in <a href="https://threejs.org/">three.js</a></p>
</li>
<li>
<p>Build a movie review site</p>
</li>
<li>
<p>Roll your own web server</p>
</li>
<li>
<p>Write a program to decrypt this <a href="https://en.wikipedia.org/wiki/Caesar_cipher">Caesar Cipher</a>:<br /> aol xbpjr iyvdu mve qbtwz vcly aol shgf kvn</p>
</li>
<li>
<p>Make a web page connected to the &lt;a href=&quot;https://developer.spotify.com/documentation/web-api/&gt;Spotify API</a> to start your playlists</p>
</li>
<li>
<p>Turn a Google Sheets document into a web page</p>
</li>
<li>
<p>Make an overhead room design and furniture layout tool</p>
</li>
<li>
<p>Make a virtual jig saw puzzle</p>
</li>
<li>
<p>Use ffmpeg to turn a movie into thumbnails</p>
</li>
<li>
<p>Use <a href="https://threejs.org/">three.js</a> to mage a 3D Hello, World page</p>
</li>
<li>
<p>Make a drawing tool that uses arrow keys for controls</p>
</li>
<li>
<p>Make a drawing tool that uses a simple on screen programming language for controls</p>
</li>
<li>
<p>Create a virtual synthesizer</p>
</li>
<li>
<p>Create a virtual drum machine</p>
</li>
<li>
<p>Use <a href="https://www.openstreetmap.org/">Open Street Maps</a> to determine the driving distance between New Orleans, LA and Springfield, MO</p>
</li>
<li>
<p>Build your own, personal read-later service</p>
</li>
<li>
<p>Build a random number generator where you can set the low and high numbers</p>
</li>
<li>
<p>Write a browser plugin that hides parts of a social media site you don't want to see</p>
</li>
<li>
<p>Make your own version of scrabble</p>
</li>
<li>
<p>Make a personal wikipedia</p>
</li>
<li>
<p>Make a personal web journal with raw html, css, and no javascript</p>
</li>
<li>
<p>Make a random name generator</p>
</li>
<li>
<p>Make a page that takes a list of names and then orders them randomly to determine who goes first</p>
</li>
<li>
<p>Make a stock ticker web page</p>
</li>
<li>
<p>Make a visualization that puts all your Wordle results on one page</p>
</li>
<li>
<p>Build a browser extension that interacts with your bookmarks to make a custom launch page</p>
</li>
<li>
<p>Make your own photo gallery site</p>
</li>
<li>
<p>Make a font comparison site with fonts from nerd fonts and the others from https://www.programmingfonts.org/</p>
</li>
<li>
<p>Make a javascript bookmarklet that counts the number of times the word <em>the</em> appears on the page</p>
</li>
<li>
<p>Make an app that lets you mute your music without muting your browser</p>
</li>
<li>
<p>Make a bookmarklet that opens a new google doc for you without having to visit the page first</p>
</li>
<li>
<p>Make a page that turns text into a ransom letter format</p>
</li>
<li>
<p>Write a program that does 99 bottles of beer</p>
</li>
<li>
<p>Make an app that shows weather information on your desktop</p>
</li>
<li>
<p>Automatically generate desktop backgrounds with the current weather so they can be rotated through 0</p>
</li>
<li>
<p>Build an chess game that people can play over social media</p>
</li>
<li>
<p>Build a chess game that people can play over twitch chat</p>
</li>
<li>
<p>Build an extension that lets you change favicons in your browser’s bookmarks</p>
</li>
<li>
<p>Write an app or extension that goes through all your bookmarks and makes them open in new tabs instead of overwriting the currently open page</p>
</li>
<li>
<p>Write a program that does The Twelve Days of Christmas</p>
</li>
<li>
<p>Create a browser extension that automatically opens links to other sites in new tabs</p>
</li>
<li>
<p>Create a browser extension that opens links in new tabs by default</p>
</li>
<li>
<p>Make your own custom window manager</p>
</li>
<li>
<p>Make a devtok site that’s a collection of developer tic toks</p>
</li>
<li>
<p>Build a Tetris game you can play with a bot</p>
</li>
<li>
<p>Build a bot to play Tetris</p>
</li>
<li>
<p>Make a random image viewer frame out of <a href="https://www.adafruit.com/category/150">E-Ink</a> and a <a href="https://www.raspberrypi.org/">Raspberry Pi</a></p>
</li>
<li>
<p>Put several <a href="https://www.adafruit.com/category/150">E-Ink</a> displays together to make a single image display with a <a href="https://www.raspberrypi.org/">Raspberry Pi</a></p>
</li>
<li>
<p>Make your own LED light strip control out of a <a href="https://www.raspberrypi.org/">Raspberry Pi</a></p>
</li>
<li>
<p>Make a RegEx tester</p>
</li>
<li>
<p>Print out regex as diagrams</p>
</li>
<li>
<p>Build a imperial to metric conversion calculator</p>
</li>
<li>
<p>Build a process to automatically clip online videos into gifs/webps</p>
</li>
<li>
<p>Build your own analytics system</p>
</li>
<li>
<p>Make an epoch time calculator</p>
</li>
<li>
<p>Automatically generate open-graph preview images from a text feed</p>
</li>
<li>
<p>A tool the generates music videos from random gifs</p>
</li>
<li>
<p>Make your own version of <a href="https://carbon.now.sh/">Carbon</a> for sharing images of source code</p>
</li>
<li>
<p>Make a screen saver for your website that shows up when folks are idle for a while</p>
</li>
<li>
<p>A Yak Count website that helps keep track of how many yaks deep you are</p>
</li>
<li>
<p>Create a site that shows color pallets, but instead of showing swatches, it shows full page layouts</p>
</li>
<li>
<p>Make a roulette game</p>
</li>
<li>
<p>Create a custom WASM function to send to cloudinary that generates random patterns to use for the background of images</p>
</li>
<li>
<p>Create a browser plugin that shows the top voted stack overflow answer above the question</p>
</li>
<li>
<p>Implement a <a href="https://en.wikipedia.org/wiki/Maze_generation_algorithm#Iterative_implementation">maze generator algorithm</a></p>
</li>
<li>
<p>Make a version of the Atari game Tempest</p>
</li>
<li>
<p>Create designs for all the bands on <a href="https://band-names.alanwsmith.com/">band-names.alanwsmith.com</a></p>
</li>
<li>
<p>Hamster Dance, but with Corgis</p>
</li>
<li>
<p>Build a version of the <a href="https://www.thinkfun.com/products/rush-hour/">Rush Hour</a> game but as a web page</p>
</li>
<li>
<p>Build a bot to solve <a href="https://www.thinkfun.com/products/rush-hour/">Rush Hour</a> game puzzles</p>
</li>
<li>
<p>Build an app that generates playlists by completely ignoring artist, genre, and release date and focuses only on lyrics</p>
</li>
<li>
<p>Build an app that watches your screen for passwords and access keys and switches obs to a blackout screen if it sees them (with obs working on a delay to allow that to happen)</p>
</li>
<li>
<p>Make a jigsaw puzzle</p>
</li>
<li>
<p>Make an count down calendar (e.g. an advent calendar)</p>
</li>
<li>
<p>Make a single serving site that plays a Strong Bad Email playlist on repeat</p>
</li>
<li>
<p>Make a Space Invaders game</p>
</li>
<li>
<p>Make a tool that turns ascii sentences into similar looking unicode characters</p>
</li>
<li>
<p>A button to push that automatically posts the song your listening to to all your social media sites</p>
</li>
<li>
<p>A Trading Fours website. Small groups where one person at a time posts four songs. Key rule is no one can post twice in a row</p>
</li>
<li>
<p>A personal movie rating page</p>
</li>
<li>
<p>Make a single page filled with randome spinners: https://icon-sets.iconify.design/svg-spinners/</p>
</li>
<li>
<p>Setup a Chrome Extension the moves tabs to a Read Later window</p>
</li>
<li>
<p>Build your own Ideas site</p>
</li>
<li>
<p>Setup a process to automatically move windows to different layouts</p>
</li>
<li>
<p>Create a tool that let's you past in HTML and generates a graphical tree view of the code</p>
</li>
<li>
<p>Use the Amazon API to build a page with cool $10 items that people can use to get to the free shipping threshold</p>
</li>
<li>
<p>Make a site that's more like a map (e.g. <a href="https://luckysoap.com/andbyislands/">luckysoap.com/andbyislands/</a>)</p>
</li>
<li>
<p>Make a site full of pages with different iterations of open graph tags and create snapshots of what they look like when used on various social networks</p>
</li>
<li>
<p>Figure out a way to use <a href="https://publicdomainreview.org/">Public Domain Review</a></p>
</li>
<li>
<p>Create a web based tool for making GIFs</p>
</div>
<div class="personal-ideas"></div>
</li>
</ul>
</div>
<noscript>
  <style>
  .dynamic-wrapper {
    display: none;
  }
  .html-wrapper {
    display: block;
  }
  </style>
</noscript>





]]></summary>
  </entry>
  
  <entry>
    <title>The Name(s) of My New Band</title><link href="https://al9000.com&#x2f;band-names/"/><id>urn:uuid:4a6eb3d2-040d-5245-ba1f-28d310471349</id>
    <updated>2026-06-20T19:42:00-04:00</updated>
    <summary><![CDATA[
  <div class="text-align-center xxxlarge-block-margin xxxlarge-block-padding">
    <div data-r="latest random" class="xxlarge-font-size xxlarge-font-weight"></div>
    <div data-r="isLatest"></div>
  </div>
  <div class="text-align-center">
    <button data-s="random">get a another name</button>
  </div>


]]></summary>
  </entry>
  
  <entry>
    <title>DAE - Digital to Analog Enlarger</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;n3&#x2f;dd&#x2f;tw/"/><id>urn:uuid:bbdbb3e3-c932-5b3f-979b-c6a3ffd39fc6</id>
    <updated>2026-06-20T11:53:00-04:00</updated>
    <summary><![CDATA[

<p>The sonic foundation of computers is the DAC,
or Digital-to-Audio Converter. It's the hardware
that turns digital files into the signal that goes
down the wires of your speakers to make them make sound.</p>
<p>What if we made a Digital to Analog Enlarger
for photographs? I mean, this already exists in some
ways. Any time you get a digital photo
printed there's a process that does it that
can output to various sizes. That's not what I'm
talking about.</p>
<p>I'm talking about one that looks like this:</p>
<figure class="default"><img src="/blog/01/n3/dd/tw/enlarger-4856357201.jpg" alt="Two photography film enlargers side by side on a worktop desk. There&#x27;s a collection of trays for processing beside them" /></figure>
<p>Ones that project light onto a piece of paper covered with
a light sensitive emulsion. The next step
being to run the paper through a series of
chemicals to produce the image.</p>
<p>It's a bit of a ridiculous way to
go about it, but it would give you
the chemical experience from
your digital images.</p>
<h3>Endnotes</h3>
<ul>
<li>
<p>The source of the enlarger photo
<a href="https://www.flickr.com/photos/ccdoh1/4856357201/in/photolist-8p96Nz-2nMeAaJ-2mQwA1E-2pnhQEK-2mYAL47-2n4AieV-2gf6FGd-dwMELp-2oDmvPL-2n2bBmS-2mVuvsY-2kTC6w2-2ocEgtt-ecUrw-f7Dqe-2hhKuw8-2m6CpsK-2nQ94vf-DxToxa-2gwA5Ai-2kTHMfC-2g6NeZz-2oBNNbT-2krKtfC-4ukokA-4RRb62-2hfRYPQ-2fan8hz-2iRxZGR-4ugkBP-2gcydSB-2nrctwb-GRQR7G-2mJULsD-VF4ay7-PAv2Uq-2gZyDLJ-2oBD7F5-2iVhpwb-2hfRYx7-6xrrGU-6xru2C-4c8MHp-2kinsnR-2nRcpPC-2oifdep-oC2vr4-2o7U4Ci-QKGmwB-2qdBpxH">here</a>.</p>
</li>
<li>
<p>Probably someone has already built one of these.</p>
</li>
<li>
<p>It's unlikely I'll ever try, but the idea is fun.</p>
</li>
</ul>


]]></summary>
  </entry>
  
  <entry>
    <title>Manic Scroll</title><link href="https://al9000.com&#x2f;manic-scroll/"/><id>urn:uuid:5ca74181-a524-5145-aa83-fa3340469a32</id>
    <updated>2026-06-19T22:16:00-04:00</updated>
    <summary><![CDATA[


<style>
* {
  margin: 0;
}

*, 
*::before, 
*::after {
  box-sizing: border-box;
}

body {
  background-color: black;
  color: #999;
}

img {
  width: min(48rem, 92vw);
  display: block;
  border-left: 1px solid #333;
  border-right: 1px solid #333;
}

.wrapper {
  width: min(48rem, 92vw);
  margin: auto;
  padding-bottom: 3rem;
}

.first {
  border-top: 1px solid #333;
}

.last{
  border-bottom: 1px solid #333;
}

.flow > :where(:not(:first-child)) {
  margin-top: var(--flow-space, 1em);
}

p {
  width: min(32rem, 80vw);
}

.imageWrapper {
  padding-top: 2rem;
}

</style>


<div class="wrapper flow">

<noscript>
  <p>
    NOTE: This site use JavaScript which appears to be turned off. 
    Some content will be fine, but some things won't work.
  </p>

</noscript>
  <div class="top-nav">
    <a href="/">home</a>
    <!--
    <a href="/tools">tools</a>
-->
  </div>





  <h1>Manic Scroll</h1>

<div class="flow">
  <p>
    In Nov. 2017, I had a full-blown manic bipolar episode. For two weeks,
    I ran around my house naked recording audio and video and taking notes
    about my plans to fix the world. These notes are part of that. They
    were also an attempt to stop talking and fight back against the
    &quot;pressure to talk&quot; that comes with mania.
  </p>
  <p>
    This is not a cohesive, edited piece. It&apos;s not something crafted
    for a movie sequence with dramatic music and a profound epiphany at
    the end. It the raw scribbling of someone in the throws of mania. If
    you&apos;re interested in seeing what that actually looks like, this
    is it.
  </p>
</div>

  <div class="imageWrapper">

<div 
   class="first" 
  
  >
  <img src="/manic-scroll/images/scroll-1-01.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-02.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-03.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-04.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-05.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-06.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-07.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-08.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-09.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-10.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-11.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-12.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-13.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-1-14.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-01.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-02.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-03.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-04.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-05.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-06.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-07.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-08.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-09.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-10.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-11.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-12.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-13.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-14.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-15.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-16.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-17.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-2-18.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-3-01.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-4-01.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-4-02.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-4-03.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-5-01.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-6-01.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-6-02.png" />
</div>

<div 
  
  
  >
  <img src="/manic-scroll/images/scroll-7-01.png" />
</div>

<div 
  
   class="last" 
  >
  <img src="/manic-scroll/images/scroll-8-01.png" />
</div>
  </div>

</div>


<footer class="default-wrapper xxlarge-block-padding accent-top-border xxxlarge-top-margin">
  <div class="small-font-size text-align-center">
    <a href="/">home</a>
  </div>
  <div class="small-font-size text-align-center">
    from <a href="/">alan w smith</a>
  </div>
  <div class="small-font-size text-align-center">
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  <div class="small-font-size text-align-center">
    <a href="/rss/">rss feed</a>
  </div>
</footer>

]]></summary>
  </entry>
  
  <entry>
    <title>QR Alice</title><link href="https://al9000.com&#x2f;qr-alice/"/><id>urn:uuid:846d81d0-adb5-5682-b02d-db83541797f2</id>
    <updated>2026-06-19T10:22:00-04:00</updated>
    <summary><![CDATA[

<style>
body {
  background-color: black;
  color: #999;
}

a {
  color: #9d1fc1;
}

h1 {
  border-bottom: 1px solid #666;
}

.clock-wrapper {
  align-items: center;
  display: flex;
  justify-content: center;
}
.center {
  display: flex;
  justify-content: center;
}

.contentWrapper {
  min-height: 96vh;
  min-height: 96dvh;
  display: grid;
  grid-template-rows: 1fr auto;
  width: min(500px, 96%);
  margin: auto;
}

</style>

<bitty-9 data-connect="/qr-alice/bit.js"></bitty-9>

<div class="contentWrapper">
<div class="text-wrapper">
  <div>
    <h1>Alice's Adventures in Wonderland</h1>
    <div data-r="init start">
        <noscript>
          This page requires JavaScript to run. 
          It's not currently available in your
          browser.
        </noscript>
      </div>
  </div>
</div>

<footer class="default-wrapper xxlarge-block-padding accent-top-border xxxlarge-top-margin">
  <div class="small-font-size text-align-center">
    <a href="/">home</a>
  </div>
  <div class="small-font-size text-align-center">
    from <a href="/">alan w smith</a>
  </div>
  <div class="small-font-size text-align-center">
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  <div class="small-font-size text-align-center">
    <a href="/rss/">rss feed</a>
  </div>
</footer></div>

<script type="text/html" data-template="runningState">
  <div class="center" id="qrcode"></div>
  <div class="center">
    <button data-s="pause" data-r="pause">pause</button>
  </div>
</script>

<script type="text/html" data-template="initState">
  <p>
    This piece presents the text
    of <a href="https://www.gutenberg.org/cache/epub/19033/pg19033.txt">Alice's Adventures in Wonderland</a>
    as a series of QR codes for each word. 
    They flash rapidly. 
    Be careful if you're sensitive to that kind of thing.
  </p>
  <button data-s="start">start</button>
</script>


]]></summary>
  </entry>
  
  <entry>
    <title>QR Clock</title><link href="https://al9000.com&#x2f;qr-clock/"/><id>urn:uuid:5d7c9261-a3dc-5090-9610-fdd1d5d2c2c8</id>
    <updated>2026-06-18T18:22:00-04:00</updated>
    <summary><![CDATA[

<style>
body {
  background-color: black;
  color: #999;
}

a {
  color: #9d1fc1;
}

.clock-wrapper {
  align-items: center;
  display: flex;
  justify-content: center;
}
.center {
  display: flex;
  justify-content: center;
}

.contentWrapper {
  min-height: 96vh;
  min-height: 96dvh;
  display: grid;
  grid-template-rows: 1fr auto;
}
</style>

<bitty-9 data-connect="/qr-clock/bit.js"></bitty-9>

<div class="contentWrapper">
<div class="clock-wrapper">
  <div>
    <h1 class="center">The Current Time Is</h1>
    <div class="center" id="qrcode"></div>
  </div>
</div>
<footer class="default-wrapper xxlarge-block-padding accent-top-border xxxlarge-top-margin">
  <div class="small-font-size text-align-center">
    <a href="/">home</a>
  </div>
  <div class="small-font-size text-align-center">
    from <a href="/">alan w smith</a>
  </div>
  <div class="small-font-size text-align-center">
    who also makes <a href="https://bittyjs.com">bitty</a>
  </div>
  <div class="small-font-size text-align-center">
    <a href="/rss/">rss feed</a>
  </div>
</footer></div>



]]></summary>
  </entry>
  
  <entry>
    <title>Tabletop Simulator Art</title><link href="https://al9000.com&#x2f;tts/"/><id>urn:uuid:6e835f9a-cdc1-5f00-b38d-0d99f68cdd4c</id>
    <updated>2026-06-16T12:22:00-04:00</updated>
    <summary><![CDATA[

<bitty-9 data-connect="/tts/bit.js"></bitty-9>

<p>These images are for play mats and card backs to use
in Magic: The Gathering on <a href="https://www.tabletopsimulator.com/">Tabletop Simulator</a>.
The play mats are actually upside down so
they face folks across the table from me.
Clicking the <code>Copy</code> button copies
the text to put into Tabletop Simulator
to use the image.</p>
<p>Here's an example of what the images look like
in place:</p>
<p><img src="/tts/images/tabletop-example.jpg" 
alt="A view of Tabletop Simulator showing an angel playmat and a custom card back for the Magic cards" /></p>
<p>(this is for my angels deck. hence the image)</p>
<h2>Card Backs</h2>
<div class="card-backs">
  <div>
    <img src=".DS_Store" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card1" 
      value="https://al9000.com.DS_Store" />
    <button data-s="copy" data-key="card1">Copy</button>
  </div>
  <div>
    <img src="001.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card2" 
      value="https://al9000.com001.jpg" />
    <button data-s="copy" data-key="card2">Copy</button>
  </div>
  <div>
    <img src="002.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card3" 
      value="https://al9000.com002.jpg" />
    <button data-s="copy" data-key="card3">Copy</button>
  </div>
  <div>
    <img src="003.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card4" 
      value="https://al9000.com003.jpg" />
    <button data-s="copy" data-key="card4">Copy</button>
  </div>
  <div>
    <img src="004.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card5" 
      value="https://al9000.com004.jpg" />
    <button data-s="copy" data-key="card5">Copy</button>
  </div>
  <div>
    <img src="005.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card6" 
      value="https://al9000.com005.jpg" />
    <button data-s="copy" data-key="card6">Copy</button>
  </div>
  <div>
    <img src="006.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card7" 
      value="https://al9000.com006.jpg" />
    <button data-s="copy" data-key="card7">Copy</button>
  </div>
  <div>
    <img src="007.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card8" 
      value="https://al9000.com007.jpg" />
    <button data-s="copy" data-key="card8">Copy</button>
  </div>
  <div>
    <img src="008.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card9" 
      value="https://al9000.com008.jpg" />
    <button data-s="copy" data-key="card9">Copy</button>
  </div>
  <div>
    <img src="009.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card10" 
      value="https://al9000.com009.jpg" />
    <button data-s="copy" data-key="card10">Copy</button>
  </div>
  <div>
    <img src="010.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card11" 
      value="https://al9000.com010.jpg" />
    <button data-s="copy" data-key="card11">Copy</button>
  </div>
  <div>
    <img src="011.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card12" 
      value="https://al9000.com011.jpg" />
    <button data-s="copy" data-key="card12">Copy</button>
  </div>
  <div>
    <img src="012.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card13" 
      value="https://al9000.com012.jpg" />
    <button data-s="copy" data-key="card13">Copy</button>
  </div>
  <div>
    <img src="013.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card14" 
      value="https://al9000.com013.jpg" />
    <button data-s="copy" data-key="card14">Copy</button>
  </div>
  <div>
    <img src="014.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card15" 
      value="https://al9000.com014.jpg" />
    <button data-s="copy" data-key="card15">Copy</button>
  </div>
  <div>
    <img src="015.jpg" alt="A card back for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="card16" 
      value="https://al9000.com015.jpg" />
    <button data-s="copy" data-key="card16">Copy</button>
  </div>
</div>
<p>Reminder: You have to set the card back URL before
importing the deck. Click the gear icon in the importer
and set the Card Back URL field. Then, add
the Deck Site URL under the &quot;Deck&quot; tab.
Images will squish in so the aspect ratio
of the source images doesn't matter.</p>
<h2>Play Mats</h2>
<div class="play-mats">
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/american-ninja-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="american-ninja-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/american-ninja-2/image.jpg" />
    <button data-s="copy" data-key="american-ninja-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel/image.jpg" />
    <button data-s="copy" data-key="angel">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-10/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-10" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-10/image.jpg" />
    <button data-s="copy" data-key="angel-10">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-11/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-11" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-11/image.jpg" />
    <button data-s="copy" data-key="angel-11">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-12/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-12" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-12/image.jpg" />
    <button data-s="copy" data-key="angel-12">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-2/image.jpg" />
    <button data-s="copy" data-key="angel-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-3/image.jpg" />
    <button data-s="copy" data-key="angel-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-4/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-4" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-4/image.jpg" />
    <button data-s="copy" data-key="angel-4">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-5/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-5" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-5/image.jpg" />
    <button data-s="copy" data-key="angel-5">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-6/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-6" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-6/image.jpg" />
    <button data-s="copy" data-key="angel-6">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-7/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-7" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-7/image.jpg" />
    <button data-s="copy" data-key="angel-7">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-8/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-8" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-8/image.jpg" />
    <button data-s="copy" data-key="angel-8">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angel-9/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angel-9" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angel-9/image.jpg" />
    <button data-s="copy" data-key="angel-9">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angry-bender/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angry-bender" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angry-bender/image.jpg" />
    <button data-s="copy" data-key="angry-bender">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/angry-owl/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="angry-owl" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/angry-owl/image.jpg" />
    <button data-s="copy" data-key="angry-owl">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/animal/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="animal" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/animal/image.jpg" />
    <button data-s="copy" data-key="animal">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/arrow/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="arrow" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/arrow/image.jpg" />
    <button data-s="copy" data-key="arrow">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-1/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-1" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-1/image.jpg" />
    <button data-s="copy" data-key="bear-1">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-2/image.jpg" />
    <button data-s="copy" data-key="bear-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-3/image.jpg" />
    <button data-s="copy" data-key="bear-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-4/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-4" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-4/image.jpg" />
    <button data-s="copy" data-key="bear-4">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-5/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-5" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-5/image.jpg" />
    <button data-s="copy" data-key="bear-5">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-6/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-6" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-6/image.jpg" />
    <button data-s="copy" data-key="bear-6">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-7/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-7" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-7/image.jpg" />
    <button data-s="copy" data-key="bear-7">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-8/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-8" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-8/image.jpg" />
    <button data-s="copy" data-key="bear-8">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/bear-9/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="bear-9" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/bear-9/image.jpg" />
    <button data-s="copy" data-key="bear-9">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/beeker/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="beeker" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/beeker/image.jpg" />
    <button data-s="copy" data-key="beeker">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/crying/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="crying" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/crying/image.jpg" />
    <button data-s="copy" data-key="crying">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/disaster-girl/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="disaster-girl" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/disaster-girl/image.jpg" />
    <button data-s="copy" data-key="disaster-girl">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/elmo-on-fire/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="elmo-on-fire" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/elmo-on-fire/image.jpg" />
    <button data-s="copy" data-key="elmo-on-fire">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/firebending/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="firebending" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/firebending/image.jpg" />
    <button data-s="copy" data-key="firebending">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/fishing-pole/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="fishing-pole" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/fishing-pole/image.jpg" />
    <button data-s="copy" data-key="fishing-pole">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/fozzy/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="fozzy" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/fozzy/image.jpg" />
    <button data-s="copy" data-key="fozzy">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/fozzy-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="fozzy-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/fozzy-2/image.jpg" />
    <button data-s="copy" data-key="fozzy-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/fry/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="fry" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/fry/image.jpg" />
    <button data-s="copy" data-key="fry">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/hamburglar/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="hamburglar" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/hamburglar/image.jpg" />
    <button data-s="copy" data-key="hamburglar">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/horn/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="horn" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/horn/image.jpg" />
    <button data-s="copy" data-key="horn">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/jeff-goldblum/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="jeff-goldblum" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/jeff-goldblum/image.jpg" />
    <button data-s="copy" data-key="jeff-goldblum">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/jeff-goldblum-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="jeff-goldblum-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/jeff-goldblum-2/image.jpg" />
    <button data-s="copy" data-key="jeff-goldblum-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/jurassic-park/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="jurassic-park" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/jurassic-park/image.jpg" />
    <button data-s="copy" data-key="jurassic-park">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/jurassic-park-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="jurassic-park-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/jurassic-park-2/image.jpg" />
    <button data-s="copy" data-key="jurassic-park-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/jurassic-park-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="jurassic-park-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/jurassic-park-3/image.jpg" />
    <button data-s="copy" data-key="jurassic-park-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/jurassic-park-4/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="jurassic-park-4" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/jurassic-park-4/image.jpg" />
    <button data-s="copy" data-key="jurassic-park-4">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/kermit/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="kermit" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/kermit/image.jpg" />
    <button data-s="copy" data-key="kermit">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/kotis/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="kotis" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/kotis/image.jpg" />
    <button data-s="copy" data-key="kotis">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/kotis-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="kotis-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/kotis-2/image.jpg" />
    <button data-s="copy" data-key="kotis-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/kotis-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="kotis-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/kotis-3/image.jpg" />
    <button data-s="copy" data-key="kotis-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/mask/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="mask" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/mask/image.jpg" />
    <button data-s="copy" data-key="mask">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/muppet-bomb/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="muppet-bomb" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/muppet-bomb/image.jpg" />
    <button data-s="copy" data-key="muppet-bomb">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/muppet-doc/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="muppet-doc" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/muppet-doc/image.jpg" />
    <button data-s="copy" data-key="muppet-doc">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/muppets/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="muppets" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/muppets/image.jpg" />
    <button data-s="copy" data-key="muppets">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja/image.jpg" />
    <button data-s="copy" data-key="ninja">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-bike/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-bike" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-bike/image.jpg" />
    <button data-s="copy" data-key="ninja-bike">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-blender/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-blender" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-blender/image.jpg" />
    <button data-s="copy" data-key="ninja-blender">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-scroll/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-scroll" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-scroll/image.jpg" />
    <button data-s="copy" data-key="ninja-scroll">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-scroll-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-scroll-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-scroll-2/image.jpg" />
    <button data-s="copy" data-key="ninja-scroll-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-scroll-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-scroll-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-scroll-3/image.jpg" />
    <button data-s="copy" data-key="ninja-scroll-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-scroll-fire/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-scroll-fire" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-scroll-fire/image.jpg" />
    <button data-s="copy" data-key="ninja-scroll-fire">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/ninja-with-sword/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="ninja-with-sword" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/ninja-with-sword/image.jpg" />
    <button data-s="copy" data-key="ninja-with-sword">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/sam-the-eagle/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="sam-the-eagle" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/sam-the-eagle/image.jpg" />
    <button data-s="copy" data-key="sam-the-eagle">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/smokey/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="smokey" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/smokey/image.jpg" />
    <button data-s="copy" data-key="smokey">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/terminator/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="terminator" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/terminator/image.jpg" />
    <button data-s="copy" data-key="terminator">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/thief/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="thief" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/thief/image.jpg" />
    <button data-s="copy" data-key="thief">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/thief-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="thief-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/thief-2/image.jpg" />
    <button data-s="copy" data-key="thief-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/this-is-fine/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="this-is-fine" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/this-is-fine/image.jpg" />
    <button data-s="copy" data-key="this-is-fine">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/tifa-1/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="tifa-1" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/tifa-1/image.jpg" />
    <button data-s="copy" data-key="tifa-1">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/tifa-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="tifa-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/tifa-2/image.jpg" />
    <button data-s="copy" data-key="tifa-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/tifa-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="tifa-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/tifa-3/image.jpg" />
    <button data-s="copy" data-key="tifa-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/vampire-hunter/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="vampire-hunter" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/vampire-hunter/image.jpg" />
    <button data-s="copy" data-key="vampire-hunter">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/winona/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="winona" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/winona/image.jpg" />
    <button data-s="copy" data-key="winona">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/winona-2/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="winona-2" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/winona-2/image.jpg" />
    <button data-s="copy" data-key="winona-2">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/winona-3/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="winona-3" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/winona-3/image.jpg" />
    <button data-s="copy" data-key="winona-3">Copy</button>
  </div>
  <div class="play-mat-image">
    <img src="&#x2f;tts&#x2f;play-mats/yoink/image.jpg" alt="A playmat for Magic: The Gathering in Tabletop Simulator" />
    <input 
      type="hidden" 
      id="yoink" 
      value="playmat https://al9000.com&#x2f;tts&#x2f;play-mats/yoink/image.jpg" />
    <button data-s="copy" data-key="yoink">Copy</button>
  </div>
</div>
<aside>
  NOTE: The alt text for the images isn't descriptive.
  The process that builds the page isn't set up for that. 
</aside>




]]></summary>
  </entry>
  
  <entry>
    <title>Fingers to Keys</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;my&#x2f;zm&#x2f;1g/"/><id>urn:uuid:e8d8efbc-f956-5f21-b4ed-dc6d5d047adf</id>
    <updated>2026-04-27T17:08:00-04:00</updated>
    <summary><![CDATA[

<p>I need to write something.</p>
<p>Notice I did not say, I <em>want</em> to write something.
I need to.</p>
<p>My brain has been offline for a couple weeks.
Not too bad. Not full on depressions. I expect
it might have been if it weren't for the meds.
Or, if I had to go to a day job.</p>
<p>That's maybe the most interesting thing for me.
How much less do I get impacted by the swings
of bipolar disorder without having the pressure
of a gig.</p>
<p>I don't think there would be a difference on the
mania side. The depressions side? It feels like I
would have spiralled down if I'd had to deal
with a 9 to 5 over the past few weeks.</p>
<p>Struggling with one during my big depression
was the major reasons I ended up in the hospital
A measure that was necessary because I'd
become a danger to myself.</p>
<p>I got stuck in this cycle of thinking that I
couldn't get my brain moving which meant that
I couldn't do my job which meant that I'd get
fired which meant I'd lose everything which
led the rest of the way down the dark
path.</p>
<h2>TODO List</h2>
<p>I've got stuff I want to work on right now.
That's better than the past few days
where I didn't want to do anything beyond
watching youtube.</p>
<p>I don't have any momentum though. I'm at
a stand still.</p>
<p>The purpose of this post is to get a little.
It's not much more than leaning forward a
bit. Not much. Just enough to take
a first step.</p>
<p>Hopefully, that'll be enough. It always
has been so far. Even as ever time it
feels like the fire might not re-ignite.</p>
<h2>Support Notes</h2>
<p>Ok.</p>
<p>Things are better now.</p>
<p>Looking at the time stamps, it took me 16
minutes to write down to this point.</p>
<p>It's fucking magic.</p>
<p>It gave me enough to clear the fog. Like
turning on a kitchen fan to clear the
smoke after you burned something in the
frying pan.</p>
<p>It also let me put music back in my ears.
I haven't really been listening to anything.
It's tough to hear tunes over
react videos of folks watching Doctor Who.</p>
<p>But, I need music as much as I do writing.</p>
<p>Input from one. Output of the other.
Balance between.</p>
<p>It's cranked now.</p>
<p>Goose's &quot;Give It Time&quot; on repeat.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/DF2QKZ823HY?si=-wPDXd_C5lvvCMla" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
<h2>Outro</h2>
<p>I don't have the energy to do
an edit pass on this post. It would
be nice. It would also be pushing
it.</p>
<p>This time is fragile. Nothing more
than an ember.</p>
<p>I'm not exactly sure how to land
this post either. This wasn't
an exercise in prose. It was
a stretch. A warm up.</p>
<p>It's done now.</p>
<p>I'm not sure what's next.
But, I know it'll be something.
A vast improvement over an hour
ago when the part of my
brain that does things wasn't
with me.</p>
<p>-a</p>

<h2>Endnotes</h2>
<ul>
<li>
<p>I've written variations of this
post a few different times. I've
written it even more in my journal.
Back when I did that.</p>
<p>The most concise iteration was
<a href="/the-clicky-sound">The Clicky Sound</a>.
The one where I finally dug out of
two years of major bipolar depression.</p>
</li>
</ul>
]]></summary>
  </entry>
  
  <entry>
    <title>The Good Place</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;my&#x2f;72&#x2f;tm/"/><id>urn:uuid:fbb02aad-94c7-554f-bc4b-f80701cd4d15</id>
    <updated>2026-04-18T09:47:00-04:00</updated>
    <summary><![CDATA[
<p>I binged The Good Place over the past few days.
All four seasons. It was all I did. I enjoyed it.
I also think there's been some depression over
the past week or so. Though, it might have just
been ennui. It's tough for me to tell. I still
don't have baselines for what's what.</p>
<p>It's been nine years since I had my manic episode
and started taking meds for bipolar disorder. The
first two or three of those years were going
though the depression along with my brain healing
from the episodes. The thing I'm wondering now is
how much of the way I was feeling was depression
and how much was healing.</p>
<p>Like, maybe I don't know what depression actually
feels like because a bunch of what I was feeling beat
up by was the physical impact on my brain and the
recovery from that. It would be nice if most of it
was the healing. That would mean the depression
wasn't as bad. I doubt that's the case based on
the clinical descriptions of depression.</p>
<p>It would be nice though.</p>
<p>Whatever, that was what it was and will be what it will be.</p>
<p>Anyway, The Good Place was a nice way to spend
the past few days. Kristen Bell is a delight.
It was a lot of fun to see Ted Danson. Those are the
two I was familiar with. William Jackson Harper
and D'Arcy Carden were great. Manny Jacinto was
good in his own way, though I wasn't a fan of his
character. He was the most Networky one. Too far on
the caricature side of a character.</p>
<p>-- h2</p>
<p>Kant and Crew</p>
<p>I give credit to the writers for the amount
of philosophy they threw in. I'd heard of half
the philosophers before thanks to J. The recurring
joke about everyone hating moral philosophers
landed for me more than most because J has told
me before that she didn't trust them. I can't
imagine most folks have either known a moral
philosopher either first or second hand. The
riff felt like an inside joke that I knew just
enough about to appreciate.</p>
<p>-- h2</p>
<p>The Exit</p>
<p>When I saw there were four seasons and the
last one ended six years ago I wondered how
they were going to wrap it up. This was in the
middle of the second season where it was clear
how much effort the writers put into the
philosophy. I was really hoping the series
would have an explicit end instead of just
ending because the show didn't get renewed.
I'm glad they got to complete it. They landed
it wonderfully. The humans walking through walk
into the universe and ceasing to be was... powerful.</p>
<p>I don't have the words to describe it. It was
very affecting. I'm crying right now thinking
about it. Not because it was bad, or sad. And, not
because it was beautiful. It was that, and it wasn't.</p>
<p>I don't know. I really don't know how to
describe it. Something like catharsis.</p>
<p>The word sublime comes to mind too. Not in the
way most folks use it. Not an ecstasy. An impact.
An intensity.</p>
<p>The thing that got me the most was the way they
described knowing it was time to move on. The
characters each recognized when they'd done
what they needed to do.</p>
<p>I get that.</p>
<p>I'm at a time when I feel like I've done enough.
What I've needed to do. If there were a door,
I could see myself walking through it. I expect
that feeling will pass. Possibly it's some
depressions. It doesn't feel like it though.
It really does feel more like I've done what
I've needed to do. That I've had enough
experiences that I've covered the enough
of them that I'm content. There will always
be more to see, but I've seen enough that
I'd be happy if it's all I got.</p>
<p>-a</p>
<p>-- endnote/</p>
<p>I'm not suicidal right now. I've been there.
This isn't that. It's weird to think I might
be again. Doubly so now that I've got the
analogy from the end of the show in my head.
The idea of the wave and the water. The wave
is a thing, but when it crashes on the shore
it ceases to be. It's just water again.
Part of the ocean.</p>
<p>-- youtube
-- l1IchzbtNj0</p>
<p>-- /endnote</p>
<p>-- endnote</p>
<p>With The Good Place and Everything Everywhere
All at Once I'm super impressed with the stories
in film and television. They are new high marks
for putting big thought narratives in play for
wider audiences. Love the evolution.</p>
<p>-- endnote</p>
<p>As always happens after a period of being kinda
offline, writing this has helped start me up.
I'll have to link up &quot;The Clicky Sound&quot;.</p>


]]></summary>
  </entry>
  
  <entry>
    <title>Get the Stem of a File Name in bash</title><link href="https://al9000.com&#x2f;cli&#x2f;get-file-name-stem/"/><id>urn:uuid:1d7d2df4-9df0-59f5-9dcb-64fcae06a832</id>
    <updated>2026-04-13T20:25:00-04:00</updated>
    <summary><![CDATA[

<div class="highlight-wrapper"><div class="title">bash</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell">!/bin/bash</span><span class="comment line number-sign shell">
<span class="line-marker" data-line="2"></span></span>
<span class="line-marker" data-line="3"></span><span class="variable other readwrite assignment shell">EXAMPLE_PATH</span><span class="keyword operator assignment shell">=</span><span class="string unquoted shell"><span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span>path/to/example-file.txt<span class="punctuation definition string end shell">&quot;</span></span></span>
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span><span class="variable other readwrite assignment shell">BASENAME</span><span class="keyword operator assignment shell">=</span><span class="string unquoted shell"><span class="meta group expansion command parens shell"><span class="punctuation definition variable shell">$</span><span class="punctuation section parens begin shell">(</span><span class="meta function-call shell"><span class="variable function shell">basename</span></span><span class="meta function-call arguments shell"> <span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span><span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="variable other readwrite shell">EXAMPLE_PATH</span></span><span class="punctuation definition string end shell">&quot;</span></span></span><span class="punctuation section parens end shell">)</span></span></span>
<span class="line-marker" data-line="6"></span><span class="variable other readwrite assignment shell">STEM</span><span class="keyword operator assignment shell">=</span><span class="string unquoted shell"><span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span><span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="punctuation section expansion parameter begin shell">{</span></span><span class="meta group expansion parameter shell"><span class="variable other readwrite shell">BASENAME<span class="keyword operator expansion shell">%</span></span></span><span class="meta group expansion parameter shell">.<span class="keyword operator regexp quantifier shell">*</span></span><span class="meta group expansion parameter shell"><span class="punctuation section expansion parameter end shell">}</span></span><span class="punctuation definition string end shell">&quot;</span></span></span>
<span class="line-marker" data-line="7"></span>
<span class="line-marker" data-line="8"></span><span class="meta function-call shell"><span class="support function echo shell">echo</span></span><span class="meta function-call arguments shell"> <span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="variable other readwrite shell">STEM</span></span></span></span></pre></div></div>
<section class="output-wrapper"><div class="title">output</div><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">example-file</span></pre></section>


]]></summary>
  </entry>
  
  <entry>
    <title>Get the Name of the Current Directory in bash</title><link href="https://al9000.com&#x2f;cli&#x2f;get-current-directory-name/"/><id>urn:uuid:7550d3d0-ec1c-5a95-b6dd-0b8470099d7f</id>
    <updated>2026-04-13T18:47:00-04:00</updated>
    <summary><![CDATA[

<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell">!/bin/bash</span><span class="comment line number-sign shell">
<span class="line-marker" data-line="2"></span></span>
<span class="line-marker" data-line="3"></span><span class="variable other readwrite assignment shell">CURRENT_DIR_NAME</span><span class="keyword operator assignment shell">=</span><span class="string unquoted shell"><span class="meta group expansion command parens shell"><span class="punctuation definition variable shell">$</span><span class="punctuation section parens begin shell">(</span><span class="meta function-call shell"><span class="variable function shell">basename</span></span><span class="meta function-call arguments shell"> <span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span><span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="variable other readwrite shell">PWD</span></span><span class="punctuation definition string end shell">&quot;</span></span></span><span class="punctuation section parens end shell">)</span></span></span>
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span><span class="meta function-call shell"><span class="support function echo shell">echo</span></span><span class="meta function-call arguments shell"> <span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="variable other readwrite shell">CURRENT_DIR_NAME</span></span></span></span></pre></div></div>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text plain">get-current-directory-name</span></pre></div></div>


]]></summary>
  </entry>
  
  <entry>
    <title>Doors</title><link href="https://al9000.com&#x2f;doors/"/><id>urn:uuid:a90d2ef7-7fd4-538d-a72e-c0adc7ae7056</id>
    <updated>2026-04-12T14:33:00-04:00</updated>
    <summary><![CDATA[


<div class="wrapper">
  <div class="inner-wrapper">
    <video muted src="doors.mp4" autoplay loop playsinline></video>
    <div class="links"><a href="/">home</a> - <a href="https://siliconpr0n.org/archive/doku.php?id=infosecdj:start">source</a></div>
  </div>
</div>


]]></summary>
  </entry>
  
  <entry>
    <title>I&#x27;m Not Ready to Start This Blog</title><link href="https://al9000.com&#x2f;blog&#x2f;01&#x2f;mx&#x2f;qf&#x2f;ng/"/><id>urn:uuid:1d75ebeb-8282-5d79-9d04-609157bd169b</id>
    <updated>2026-04-12T11:48:00-04:00</updated>
    <summary><![CDATA[

<p>Fuck it. We'll do it live.</p>
<p>Welcome to the al9000.com blog!</p>
<p>Things to know:</p>
<ul>
<li>
<p>I've used <a href="https://www.alanwsmith.com/">alanwsmith.com</a>
as my website since the 1900's. It's always
been formal sounding and more syllables than
I'd like. It finally bugged me enough that
I bought this one and am moving everything
here.</p>
</li>
<li>
<p>There's a few thousand pages on alanwsmith.com.
Migration is gonna take a while.</p>
</li>
<li>
<p>If I keep blogging there, I'll keep putting
off the work to migrate here. It's similar to
&quot;broken gets fixed, shoddy is forever&quot;. Not
that the old site is shoddy or broken.
It's just that considering it no longer viable
pushes me to work here.</p>
</li>
</ul>
<p>So, I'm making the leap. I've got to hand code
a lot. Things are barely styled. Links
and pages break all the time as I
figure out where to put things.
But, the basic framework is in place.
Enough that I can start putting down words.</p>
<p>As bumpy as it's going to be, I'm
looking forward to the ride.
Even if it doesn't feel like I'm ready
to start.</p>
<p>-a</p>

<p>P.S. I've been posting other content.
You can get to it from the <a href="/">home page</a>.
It's just not what I consider blog content.
Though, the more I'm thinking about what
I want to do with the site the less that
distinction is going to matter.</p>
<p>P.P.S. I haven't built the RSS feed yet. It's
coming soon.</p>
]]></summary>
  </entry>
  
  <entry>
    <title>Use Keyword Args in a Function</title><link href="https://al9000.com&#x2f;rust&#x2f;minijinja&#x2f;use_keyword_args/"/><id>urn:uuid:cb735269-6df7-5b17-89c4-fd22d59f6b76</id>
    <updated>2026-04-11T12:52:12-04:00</updated>
    <summary><![CDATA[

<h3>Rust</h3>

<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="meta group rust"><span class="punctuation section group begin rust">[</span>package<span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="2"></span>name <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>optional_function_argument<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="3"></span>version <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>0.1.0<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="4"></span>edition <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>2024<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta group rust"><span class="punctuation section group begin rust">[</span>dependencies<span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="7"></span>anyhow <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>1.0.102<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="8"></span>minijinja <span class="keyword operator rust">=</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span> version <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>2.21.0<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> features <span class="keyword operator rust">=</span> <span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>custom_syntax<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation section group end rust">]</span></span> </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></pre></div></div>

<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> 
<span class="line-marker" data-line="2"></span></span><span class="keyword other rust">use</span> <span class="meta path rust">anyhow<span class="punctuation accessor rust">::</span></span>Result<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">minijinja<span class="punctuation accessor rust">::</span></span><span class="meta path rust">syntax<span class="punctuation accessor rust">::</span></span>SyntaxConfig<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">minijinja<span class="punctuation accessor rust">::</span></span><span class="meta path rust">value<span class="punctuation accessor rust">::</span></span>Kwargs<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span><span class="keyword other rust">use</span> <span class="meta path rust">minijinja<span class="punctuation accessor rust">::</span></span><span class="meta block rust"><span class="punctuation section block begin rust">{</span>Environment<span class="punctuation separator rust">,</span> Error<span class="punctuation separator rust">,</span> Value<span class="punctuation separator rust">,</span> context</span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="6"></span>
<span class="line-marker" data-line="7"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="8"></span>  <span class="storage type rust">let</span> <span class="storage modifier rust">mut</span> env <span class="keyword operator rust">=</span> <span class="support function rust">get_env</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="9"></span>  <span class="storage type rust">let</span> template_string <span class="keyword operator rust">=</span> <span class="support function rust">get_template_string</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="10"></span>  env.<span class="support function rust">add_template</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>template<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> <span class="keyword operator rust">&amp;</span>template_string</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="11"></span>  <span class="storage type rust">let</span> template <span class="keyword operator rust">=</span> env.<span class="support function rust">get_template</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>template<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>  <span class="storage type rust">let</span> output <span class="keyword operator rust">=</span> template.<span class="support function rust">render</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="support macro rust">context!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>title <span class="keyword operator rust">=&gt;</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>Alfa Bravo<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="13"></span>  <span class="support macro rust">println!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{}</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span> output<span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="14"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="15"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="16"></span>
<span class="line-marker" data-line="17"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">get_env</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="meta generic rust">Environment<span class="punctuation definition generic begin rust">&lt;</span><span class="storage modifier lifetime rust">&#39;static</span><span class="punctuation definition generic end rust">&gt;</span></span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="18"></span>  <span class="storage type rust">let</span> <span class="storage modifier rust">mut</span> env <span class="keyword operator rust">=</span> <span class="meta path rust">Environment<span class="punctuation accessor rust">::</span></span>new<span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="19"></span>  env.<span class="support function rust">set_syntax</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>
<span class="line-marker" data-line="20"></span>    <span class="meta path rust">SyntaxConfig<span class="punctuation accessor rust">::</span></span>builder<span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="21"></span>      .<span class="support function rust">block_delimiters</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>[!<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>!]<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="22"></span>      .<span class="support function rust">variable_delimiters</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>[@<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>@]<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="23"></span>      .<span class="support function rust">comment_delimiters</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>[#<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>#]<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="24"></span>      .<span class="support function rust">build</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="25"></span>      .<span class="support function rust">unwrap</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation separator rust">,</span>
<span class="line-marker" data-line="26"></span>  </span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="27"></span>  env.<span class="support function rust">add_function</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>test_function<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation separator rust">,</span> test_function</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="28"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>env</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="29"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="30"></span>
<span class="line-marker" data-line="31"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">get_template_string</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span>String<span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="32"></span>  <span class="storage type rust">let</span> template <span class="keyword operator rust">=</span> <span class="string quoted double raw rust"><span class="storage type string rust">r</span><span class="punctuation definition string begin rust">#</span>&quot;
<span class="line-marker" data-line="33"></span>No Extra Args: [@ test_function(&quot;alfa&quot;, &quot;bravo&quot;) @]
<span class="line-marker" data-line="34"></span>With Extra Args: [@ test_function(&quot;delta&quot;, &quot;echo&quot;, extra = &quot;foxtrot&quot;) @]
<span class="line-marker" data-line="35"></span>  <span class="punctuation definition string end rust">&quot;#</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="36"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>template.<span class="support function rust">to_string</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="37"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="38"></span>
<span class="line-marker" data-line="39"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">test_function</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="40"></span>  <span class="variable parameter rust">value1</span><span class="punctuation separator rust">:</span> Value,
<span class="line-marker" data-line="41"></span>  <span class="variable parameter rust">value2</span><span class="punctuation separator rust">:</span> Value,
<span class="line-marker" data-line="42"></span>  <span class="variable parameter rust">options</span><span class="punctuation separator rust">:</span> Kwargs,
<span class="line-marker" data-line="43"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span>Value, Error<span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="44"></span>  <span class="storage type rust">let</span> <span class="storage modifier rust">mut</span> output <span class="keyword operator rust">=</span> <span class="support macro rust">format!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{}</span>-<span class="constant other placeholder rust">{}</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span> value1<span class="punctuation separator rust">,</span> value2<span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="45"></span>  <span class="keyword control rust">if</span> <span class="storage type rust">let</span> <span class="support type rust">Some</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>extra</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span> <span class="keyword operator rust">=</span> options.<span class="support function rust">get</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>extra<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="46"></span>    output.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted single rust"><span class="punctuation definition string begin rust">&#39;</span>-<span class="punctuation definition string end rust">&#39;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="47"></span>    output.<span class="support function rust">push_str</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>extra</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="48"></span>  </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="49"></span>  <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> asseert_all_used ensures no unknown
<span class="line-marker" data-line="50"></span></span>  <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> arguments (or misspelled arguments)
<span class="line-marker" data-line="51"></span></span>  <span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span> are sent
<span class="line-marker" data-line="52"></span></span>  options.<span class="support function rust">assert_all_used</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="53"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta path rust">Value<span class="punctuation accessor rust">::</span></span>from_safe_string<span class="meta group rust"><span class="punctuation section group begin rust">(</span>output</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="54"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="55"></span><span class="comment line double-slash rust"><span class="punctuation definition comment rust">//</span></span></span></pre></div></div>





]]></summary>
  </entry>
  
  <entry>
    <title>Capture Errors from Command Line Tools</title><link href="https://al9000.com&#x2f;cli&#x2f;capture-both-stdout-and-stderror/"/><id>urn:uuid:6d121163-1b63-5455-973b-428a13905056</id>
    <updated>2026-04-11T09:58:51-04:00</updated>
    <summary><![CDATA[


<h2>TL;DR</h2>
<p>Use this to capture errors along with
regular output from command line tools:</p>
<div class="command-block"><pre><code><span class="line-marker" data-line="1"></span><span class="text plain">2&gt;&amp;1</span></code></pre></div>
<h2>Basic Capture</h2>
<p>For example:</p>
<div class="command-block"><pre><code><span class="line-marker" data-line="1"></span><span class="text plain">rm -v example.txt 2&gt;&amp;1 | cat &gt; report.txt</span></code></pre></div>
<p>If the file exists and is deleted, then it's file name is
output to the <code>report-1.txt</code> via <code>STDOUT</code>.</p>
<section class="output-wrapper"><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">example.txt</span></pre></section>
If the file doesn't exist, or can't be removed, then an
error message is output to `report-1.txt` via `STDERR`.
<section class="output-wrapper"><pre class="output-block"><span class="line-marker" data-line="1"></span><span class="text plain">rm: example.txt: No such file or directory</span></pre></section>
<h2>Seeing The Output</h2>
<p>Running the above command doesn't output anything to
the terminal. You can add <code>tee /dev/tty</code> to see
the messages there as well.</p>
<div class="command-block"><pre><code><span class="line-marker" data-line="1"></span><span class="text plain">rm -v example.txt 2&gt;&amp;1 | tee /dev/tty | cat &gt; report.txt</span></code></pre></div>
<h2>Wrap Up</h2>
<p>The <code>2&gt;&amp;1</code> looks weird to me. Totally worth it
to remeber though when trying to capture
the output of commands that use both <code>STDOUT</code>
and <code>STDERR</code>.</p>
<p>-a</p>


]]></summary>
  </entry>
  
  <entry>
    <title>Access Mac Keychain Access Passwords from a Rust App</title><link href="https://al9000.com&#x2f;rust&#x2f;general&#x2f;access-mac-keychain-passwords/"/><id>urn:uuid:ef651fb1-46ce-524b-8f54-99e79bebb120</id>
    <updated>2026-04-10T13:57:22-04:00</updated>
    <summary><![CDATA[
<p>I use the built-in macOS Keychain Access app to store credentials
for my various scripts and tools. I start off by creating
a <code>New Password Item...</code> from the Keychain Access menu
and filling in the details:</p>
<p><img src="images/raw/new-password.png" 
alt="The new password prompt from the macOS KeyChain Access app" /></p>
<p>Then, I use this rust code to pull in passwords
when I need them:</p>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="meta path rust">anyhow<span class="punctuation accessor rust">::</span></span>Result<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span><span class="keyword other rust">use</span> <span class="meta path rust">security_framework<span class="punctuation accessor rust">::</span></span><span class="meta path rust">passwords<span class="punctuation accessor rust">::</span></span>get_generic_password<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span>
<span class="line-marker" data-line="4"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="5"></span>  <span class="storage type rust">let</span> retreived_password <span class="keyword operator rust">=</span> <span class="support function rust">get_password</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>al9000-post-example<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="6"></span>  <span class="support macro rust">println!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span><span class="constant other placeholder rust">{}</span><span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation separator rust">,</span> retreived_password<span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="7"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="8"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="9"></span>
<span class="line-marker" data-line="10"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">get_password</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span><span class="variable parameter rust">key</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span><span class="storage type rust">str</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span>String<span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="11"></span>  <span class="storage type rust">let</span> account <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alan<span class="punctuation definition string end rust">&quot;</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="12"></span>  <span class="storage type rust">let</span> response <span class="keyword operator rust">=</span> <span class="support function rust">get_generic_password</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span>key<span class="punctuation separator rust">,</span> account</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="13"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="support type rust">String</span><span class="meta path rust"><span class="punctuation accessor rust">::</span></span>from_utf8<span class="meta group rust"><span class="punctuation section group begin rust">(</span>response</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="14"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
with this Cargo.toml:
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="meta group rust"><span class="punctuation section group begin rust">[</span>package<span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="2"></span>name <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>access-mac-keychain-passwords<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="3"></span>version <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>0.1.0<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="4"></span>edition <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>2024<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta group rust"><span class="punctuation section group begin rust">[</span>dependencies<span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="7"></span>anyhow <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>1.0.102<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="8"></span>security<span class="keyword operator rust">-</span>framework <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>3.7.0<span class="punctuation definition string end rust">&quot;</span></span></span></pre></div></div>
When I run the app from the command line I get
a prompt from Keychain Access to enter the
keychain's main password to unlock it. 
<p><img src="images/raw/keychain-access-prompt.png" 
alt="They macOS Keychain Access app prompt for the main password." /></p>
<p>Assuming I click &quot;Always Allow&quot; when I enter
the proper password Keychain Access provides
the requested password back to the app.
From that point forward the app can get
the password again without triggering
the prompt.</p>
<p>It's hard to beat.</p>
<p>-a</p>
<h2>Notes</h2>
<ul>
<li>
<p>I've been using Keychain Access for ages. There's
a new Passwords app too. The OS keeps prompting me
to use it:</p>
<p><img src="images/raw/open-passwords-prompt.png" 
alt="They macOS prompt to open Passwords instead of Keychain Access." /></p>
<p>I assume I'll be able to set up a similar system
with it. I just haven't dug into it yet.</p>
</li>
<li>
<p>I'm using the <a href="https://docs.rs/security-framework/latest/security_framework/index.html">security_framework crate</a>
to handle communication between my app and
Keychain Access. It's got north of
<a href="https://crates.io/crates/security-framework">200 million downloads on crates.io</a>.
I'm using that as social proof that it's
a good library to go with.</p>
</li>
<li>
<p>The security_framework crate works with Windows and Linux password
managers too.</p>
</li>
<li>
<p>The <code>correct-horse-battery-staple</code> password is from
<a href="https://xkcd.com/936/">this XKCD comic</a> which shows
you why passwords with words are better than ones
with a bunch of random characters.</p>
</li>
</ul>
<h3>References</h3>
<ul class="d">
<li><a href="https://crates.io/crates/security-framework">https://crates.io/crates/security-framework</a></li>
<li><a href="https://docs.rs/security-framework/latest/security_framework/">https://docs.rs/security-framework/latest/security_framework/</a></li>
<li><a href="https://docs.rs/security-framework/latest/security_framework/passwords/index.html">https://docs.rs/security-framework/latest/security_framework/passwords/index.html</a></li>
</ul>



]]></summary>
  </entry>
  
  <entry>
    <title>Create an HLS Encrypted Video with ffmpeg</title><link href="https://al9000.com&#x2f;ffmpeg&#x2f;create-an-hls-encrypted-video/"/><id>urn:uuid:d0d11ca2-07a9-5f41-8afd-0dfddca92611</id>
    <updated>2026-04-06T23:27:15-04:00</updated>
    <summary><![CDATA[<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="/styles/main.css" />

    <script src="&#x2f;scripts.raw&#x2f;bitty&#x2f;bitty-9.0.0-beta1.source.js" type="module"></script>

<link rel="shortcut icon" href="/favicon.ico" />
<title>Create an HLS Encrypted Video with ffmpeg</title>
<meta property="og:title" content="Create an HLS Encrypted Video with ffmpeg" />
<meta name="description" content="from alan w smith" />
<meta property="og:description" content="from alan w smith" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://al9000.com/rss/feed.xml" />
<meta property="og:image" content="https://al9000.com&#x2f;ffmpeg&#x2f;create-an-hls-encrypted-video/og-image-auto.jpg" />
<link rel="apple-touch-icon" sizes="180x180" href="&#x2f;favicons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="16x16" href="&#x2f;favicons/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="&#x2f;favicons/favicon-32x32.png" />
<link rel="manifest" href="&#x2f;favicons/site.webmanifest" />
<link rel="mask-icon" href="&#x2f;favicons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="alternate" type="application/atom+xml" title="al9000.com" href="/rss/feed.xml" />
<link
  rel="site.standard.publication"
  href="at://did:plc:hehia4csii5iipebsgolxxal/site.standard.publication&#x2f;3mp5l453r552a"
/>




    
    
    
    

    


    <style>
    </style>
    
  </head>
  <body class="page">
<noscript>
  <p>
    NOTE: Some pages on this site rely on JavaScript. 
    It's not currently available in your
    browser/reader. Depending on the page,
    some or all of the content may not
    work correctly without it. 
  </p>

</noscript>

    <div class="payload">
      
    </div>


    <div class="templates" hidden>
      <bitty-9 data-connect="/bits/default.js"></bitty-9>
      <script type="module" src="/bits/components.js"></script>



    </div>
  </body>
</html>
]]></summary>
  </entry>
  
  <entry>
    <title>A Media Source Extensions (MSE) Video Player</title><link href="https://al9000.com&#x2f;javascript&#x2f;media-source-video-player/"/><id>urn:uuid:81647956-49d4-5bc4-ae9e-5c7ba88e5cd4</id>
    <updated>2026-04-06T19:30:12-04:00</updated>
    <summary><![CDATA[

<h2>Overview</h2>
<ul>
<li>
<p>This is a very basic approach to using
the Media Source API (aka
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API">Media Source Extension</a>)
to load tracks in a &lt;video&gt; tag instead
of using a <code>src</code> attribute that points
to a single file (or <a href="https://en.wikipedia.org/wiki/HTTP_Live_Streaming">HLS</a>
playlist).</p>
</li>
<li>
<p>This is primarily a prototype I'm
working on for my <a href="/multi-player/">Multi-Player project</a>.
Chrome slows way down
as the number of videos on the page increases.
Hopefully, this approach can keep things snappy.</p>
</li>
<li>
<p>You should probably use <a href="https://videojs.org/">VideoJS</a>
instead of this in most cases.</p>
</li>
<li>
<p>This does not currently do an explicit check to see if the mime
type is supported in a given browser. I'm using <a href="https://www.webmproject.org/">.webm</a>
in the examples. Things are lined up already
with the videos (I'm using <code>video/webm; codecs=&quot;vp9, vorbis&quot;</code>).
See <a href="https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer#examples">the doc examples</a>
for details on how to check in situations where
you can't control the input files.</p>
</li>
<li>
<p>My original version of this didn't use global variables.
I ran into an issue where missing audio was breaking
chrome and added the feature to track videos
by UUID in the global <code>videos</code> variable during
the bug hunt. While I like the idea of avoiding
global variable I'm fine with them here.</p>
</li>
<li>
<p>This version is also prep work for making a version that works
with encrypted video files (e.g. by
<a href="/rust/wasm/static-site-file-decryption/">Password Protecting Static Site Content with WASM</a>).
You can check out the code for that on
<a href="/javascript/encrypted-media-source-video-player/">An Encrypted Media Source Extensions (MSE) Video Player</a>.</p>
</li>
</ul>
<h2>The Video</h2>
<p>Here's the output demo video to get started.
It's from <a href="https://www.pexels.com/video/a-drone-shot-of-a-church-in-belalp-3818213/">pexels</a>
which is a nice place to get free videos.</p>


<video id="videoPlayer" controls></video>

<script type="module">
import { loadVideo } from "/javascript/media-source-video-player/media-source-player.js"
const config = {
  codec: `video/webm; codecs="vp9, vorbis"`,
  urls: [
    "/javascript/media-source-video-player/sample-video/part-00.part",
    "/javascript/media-source-video-player/sample-video/part-01.part",
    "/javascript/media-source-video-player/sample-video/part-02.part",
    "/javascript/media-source-video-player/sample-video/part-03.part",
    "/javascript/media-source-video-player/sample-video/part-04.part",
    "/javascript/media-source-video-player/sample-video/part-05.part",
    "/javascript/media-source-video-player/sample-video/part-06.part",
    "/javascript/media-source-video-player/sample-video/part-07.part",
    "/javascript/media-source-video-player/sample-video/part-08.part",
    "/javascript/media-source-video-player/sample-video/part-09.part",
    "/javascript/media-source-video-player/sample-video/part-10.part",
  ],
  fallback: "/javascript/media-source-video-player/sample-video/church-3818213.webm",
}
loadVideo("#videoPlayer", config);
</script>



<h2>The JavaScript</h2>
<p>The main JavaScript consists of a
variable and two functions in
this module:</p>

<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source js"><span class="storage type js">const</span> <span class="variable other readwrite js">videos</span> <span class="keyword operator assignment js">=</span> <span class="meta object-literal js"><span class="punctuation section block js">{</span><span class="punctuation section block js">}</span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta export js"><span class="keyword control import-export js">export</span> <span class="variable other readwrite js">async</span> </span><span class="meta function declaration js"><span class="storage type function js">function</span> <span class="entity name function js">loadVideo</span><span class="punctuation section group begin js">(</span><span class="variable parameter function js">selector</span><span class="punctuation separator parameter function js">,</span> <span class="variable parameter function js">config</span><span class="punctuation section group end js">)</span><span class="meta function declaration js"> </span></span><span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="4"></span>  <span class="storage type js">const</span> <span class="variable other readwrite js">uuid</span> <span class="keyword operator assignment js">=</span> <span class="variable language self js">self</span><span class="punctuation accessor js">.</span><span class="meta property object js">crypto</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">randomUUID</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="5"></span>  <span class="storage type js">const</span> <span class="variable other readwrite js">el</span> <span class="keyword operator assignment js">=</span> <span class="support type object dom js">document</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">querySelector</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">selector</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="6"></span>  <span class="variable other object js">el</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">addEventListener</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>canplaythrough<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span> <span class="meta function declaration js"><span class="punctuation section group begin js">(</span><span class="punctuation section group end js">)</span><span class="meta function declaration js"> </span><span class="storage type function arrow js">=&gt;</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="7"></span>    <span class="meta function-call method js"><span class="support type object console js">console</span><span class="punctuation accessor js">.</span><span class="support function console js">log</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>Got canplaythrough.<span class="punctuation definition string end js">&quot;</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="8"></span>  <span class="punctuation section block js">}</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="9"></span>  <span class="storage type js">const</span> <span class="variable other readwrite js">mediaSource</span> <span class="keyword operator assignment js">=</span> <span class="meta instance constructor js"><span class="keyword operator word new js">new</span><span class="meta function-call constructor js"> <span class="variable type js">MediaSource</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="10"></span>  <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span> <span class="keyword operator assignment js">=</span> <span class="meta object-literal js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="11"></span>    <span class="meta object-literal key js">mediaSource</span><span class="punctuation separator key-value js">:</span> <span class="variable other readwrite js">mediaSource</span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="12"></span>    <span class="meta object-literal key js">urls</span><span class="punctuation separator key-value js">:</span> <span class="variable other object js">config</span><span class="punctuation accessor js">.</span><span class="meta property object js">urls</span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="13"></span>    <span class="meta object-literal key js">currentSegment</span><span class="punctuation separator key-value js">:</span> <span class="constant numeric js">0</span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="14"></span>  <span class="punctuation section block js">}</span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="15"></span>  <span class="meta conditional js"><span class="keyword control conditional js">if</span> <span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">mediaSource</span><span class="punctuation section group js">)</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="16"></span>    <span class="variable other object js">el</span><span class="punctuation accessor js">.</span><span class="meta property object js">src</span> <span class="keyword operator assignment js">=</span> <span class="variable other object js">URL</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">createObjectURL</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">mediaSource</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="17"></span>    <span class="variable other object js">mediaSource</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">addEventListener</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>sourceopen<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span> <span class="meta function declaration js"><span class="storage type js">async</span><span class="meta function declaration js"> </span><span class="punctuation section group begin js">(</span><span class="punctuation section group end js">)</span><span class="meta function declaration js"> </span><span class="storage type function arrow js">=&gt;</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="18"></span>      <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">sourceBuffer</span> <span class="keyword operator assignment js">=</span> <span class="variable other object js">mediaSource</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">addSourceBuffer</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other object js">config</span><span class="punctuation accessor js">.</span><span class="meta property object js">codec</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="19"></span>      <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">sourceBuffer</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">addEventListener</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>updateend<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span> <span class="meta function declaration js"><span class="storage type js">async</span><span class="meta function declaration js"> </span><span class="punctuation section group begin js">(</span><span class="variable parameter function js">event</span><span class="punctuation section group end js">)</span><span class="meta function declaration js"> </span><span class="storage type function arrow js">=&gt;</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="20"></span>        <span class="meta conditional js"><span class="keyword control conditional js">if</span> <span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">mediaSource</span><span class="punctuation accessor js">.</span><span class="meta property object js">readyState</span> <span class="keyword operator comparison js">===</span> <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>open<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation section group js">)</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="21"></span>          <span class="meta function-call js"><span class="variable function js">loadSegment</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">uuid</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="22"></span>        </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span>
<span class="line-marker" data-line="23"></span>      <span class="punctuation section block js">}</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="24"></span>      <span class="meta function-call js"><span class="variable function js">loadSegment</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">uuid</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="25"></span>    <span class="punctuation section block js">}</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="26"></span>  </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span> <span class="meta conditional js"><span class="keyword control conditional js">else</span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="27"></span>    <span class="variable other object js">el</span><span class="punctuation accessor js">.</span><span class="meta property object js">src</span> <span class="keyword operator assignment js">=</span> <span class="variable other object js">config</span><span class="punctuation accessor js">.</span><span class="meta property object js">fallback</span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="28"></span>  </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span>
<span class="line-marker" data-line="29"></span><span class="punctuation section block js">}</span></span>
<span class="line-marker" data-line="30"></span>
<span class="line-marker" data-line="31"></span><span class="meta function declaration js"><span class="storage type js">async</span> <span class="storage type function js">function</span> <span class="entity name function js">loadSegment</span><span class="punctuation section group begin js">(</span><span class="variable parameter function js">uuid</span><span class="punctuation section group end js">)</span><span class="meta function declaration js"> </span></span><span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="32"></span>  <span class="meta conditional js"><span class="keyword control conditional js">if</span> <span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">currentSegment</span> <span class="keyword operator relational js">&lt;</span> <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">urls</span><span class="punctuation accessor js">.</span><span class="meta property object js">length</span><span class="punctuation section group js">)</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="33"></span>    <span class="meta try js"><span class="keyword control trycatch js">try</span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="34"></span>      <span class="storage type js">const</span> <span class="support module node js">url</span> <span class="keyword operator assignment js">=</span> <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">urls</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">currentSegment</span><span class="punctuation section brackets js">]</span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="35"></span>      <span class="storage type js">const</span> <span class="variable other readwrite js">response</span> <span class="keyword operator assignment js">=</span> <span class="variable other readwrite js">await</span> <span class="meta function-call js"><span class="variable function js">fetch</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="support module node js">url</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="36"></span>      <span class="meta conditional js"><span class="keyword control conditional js">if</span> <span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other object js">response</span><span class="punctuation accessor js">.</span><span class="meta property object js">ok</span><span class="punctuation section group js">)</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="37"></span>        <span class="meta function-call method js"><span class="support type object console js">console</span><span class="punctuation accessor js">.</span><span class="support function console js">log</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string template js"><span class="punctuation definition string template begin js">`</span>processing segment: </span><span class="meta template expression js"><span class="punctuation definition template-expression begin js">${</span></span><span class="meta template expression js"><span class="source js embedded expression"><span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">currentSegment</span></span><span class="punctuation definition template-expression end js">}</span></span><span class="string template js"><span class="punctuation definition string template end js">`</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="38"></span>        <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">currentSegment</span><span class="keyword operator arithmetic js">++</span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="39"></span>        <span class="storage type js">const</span> <span class="support module node js">buffer</span> <span class="keyword operator assignment js">=</span> <span class="variable other readwrite js">await</span> <span class="variable other object js">response</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">arrayBuffer</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="40"></span>        <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">sourceBuffer</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">appendBuffer</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="support module node js">buffer</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="41"></span>      </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span> <span class="meta conditional js"><span class="keyword control conditional js">else</span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="42"></span>        <span class="meta function-call method js"><span class="support type object console js">console</span><span class="punctuation accessor js">.</span><span class="support function console js">error</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">response</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="43"></span>        <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">mediaSource</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">endOfStream</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>network<span class="punctuation definition string end js">&quot;</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="44"></span>      </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span>
<span class="line-marker" data-line="45"></span>    </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span> <span class="meta catch js"><span class="keyword control trycatch js">catch</span> <span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">error</span><span class="punctuation section group js">)</span></span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="46"></span>      <span class="meta function-call method js"><span class="support type object console js">console</span><span class="punctuation accessor js">.</span><span class="support function console js">error</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="variable other readwrite js">error</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="47"></span>      <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">mediaSource</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">endOfStream</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>network<span class="punctuation definition string end js">&quot;</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="48"></span>    </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span>
<span class="line-marker" data-line="49"></span>  </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span> <span class="meta conditional js"><span class="keyword control conditional js">else</span> <span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="50"></span>    <span class="variable other object js">videos</span><span class="meta brackets js"><span class="punctuation section brackets js">[</span><span class="variable other readwrite js">uuid</span><span class="punctuation section brackets js">]</span></span><span class="punctuation accessor js">.</span><span class="meta property object js">mediaSource</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">endOfStream</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="51"></span>  </span><span class="meta block js"><span class="punctuation section block js">}</span></span></span>
<span class="line-marker" data-line="52"></span><span class="punctuation section block js">}</span></span></span></pre></div></div>
<ul>
<li>
<p>The <code>loadVideo</code> function takes a selector that
points to an existing <code>video</code> element and
a config.</p>
</li>
<li>
<p>The format of the config is in the HTML below.</p>
</li>
<li>
<p>The config includes a fallback in addition to
the split up files the MediaSource uses.</p>
</li>
<li>
<p>A check is made to verify the MediaSource
available/loaded. If not, the fallback URL is used.</p>
</li>
<li>
<p>I'm using a direct link to a <code>.webm</code> file
for the fallback. In practice, I'd
probably use an <a href="https://en.wikipedia.org/wiki/HTTP_Live_Streaming">HLS</a>
playlist.</p>
</li>
<li>
<p>The module hangs a
<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplaythrough_event">canplaythrough</a>
event listener on the video element.
It's fired when the browser estimates it has enough
data to play the video without having to
stop for buffering.</p>
</li>
<li>
<p>I left the <code>console.log('processing segment...'</code> line in
to show how the <code>canplaythrough</code> event generally fires while
the individual segment files are still being
loaded.</p>
</li>
</ul>
<h2>The HTML</h2>
<p>Here's the HTML I'm using on the page:</p>

<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">video</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">videoPlayer</span><span class="punctuation definition string end html">&quot;</span></span></span> <span class="entity other attribute-name html">controls</span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">video</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta tag script begin html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag script html">script</span></span><span class="meta tag script begin html"> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>module<span class="punctuation definition string end html">&quot;</span></span></span></span><span class="meta tag script begin html"><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="4"></span><span class="source js embedded html"><span class="source js"><span class="meta import js"><span class="keyword control import-export js">import</span> <span class="meta block js"><span class="punctuation section block js">{</span> <span class="variable other readwrite js">loadVideo</span> <span class="punctuation section block js">}</span></span> <span class="keyword control import-export js">from</span> <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/media-source-player.js<span class="punctuation definition string end js">&quot;</span></span>
<span class="line-marker" data-line="5"></span></span><span class="storage type js">const</span> <span class="variable other readwrite js">config</span> <span class="keyword operator assignment js">=</span> <span class="meta object-literal js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="6"></span>  <span class="meta object-literal key js">codec</span><span class="punctuation separator key-value js">:</span> <span class="string template js"><span class="punctuation definition string template begin js">`</span>video/webm; codecs=&quot;vp9, vorbis&quot;<span class="punctuation definition string template end js">`</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="7"></span>  <span class="meta object-literal key js">urls</span><span class="punctuation separator key-value js">:</span> <span class="meta sequence js"><span class="punctuation section brackets js">[</span>
<span class="line-marker" data-line="8"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-00.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="9"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-01.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="10"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-02.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="11"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-03.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="12"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-04.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="13"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-05.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="14"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-06.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="15"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-07.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="16"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-08.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="17"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-09.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="18"></span>    <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/part-10.part<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="19"></span>  <span class="punctuation section brackets js">]</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="20"></span>  <span class="meta object-literal key js">fallback</span><span class="punctuation separator key-value js">:</span> <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>/javascript/media-source-video-player/sample-video/church-3818213.webm<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span>
<span class="line-marker" data-line="21"></span><span class="punctuation section block js">}</span></span>
<span class="line-marker" data-line="22"></span><span class="meta function-call js"><span class="variable function js">loadVideo</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>#videoPlayer<span class="punctuation definition string end js">&quot;</span></span><span class="punctuation separator comma js">,</span> <span class="variable other readwrite js">config</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="23"></span></span></span><span class="meta tag script end html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag script html">script</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>


<ul>
<li>
<p>The video tag has an <code>id</code> attribute that's
used in the selector to grab the element.</p>
</li>
<li>
<p>In this case, the config is set up
for a webm format and supporting codec.</p>
</li>
<li>
<p>The video is split into 11 parts
in the <code>urls</code> array. These get processed
in order by the module.</p>
</li>
<li>
<p>The last thing in the config is
the fallback to use if the MediaSource
doesn't work or isn't available.</p>
</li>
</ul>
<h2>The Prep Script</h2>
<p>The sample video I used didn't have an audio track
with it. It worked fine in Safari and Firefox.
It broke in chrome. It took a while to figure
out that the missing audio was the problem.</p>
<p>This is the <code>ffmpeg</code> command I used to fix
the issue. It makes a new <code>.webm</code> file
with a silent audio track.</p>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell">!/bin/bash</span><span class="comment line number-sign shell">
<span class="line-marker" data-line="2"></span></span>
<span class="line-marker" data-line="3"></span><span class="meta function-call shell"><span class="variable function shell">ffmpeg</span></span><span class="meta function-call arguments shell"><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>y</span><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>f</span> lavfi<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>i</span> anullsrc<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>i</span> INPUT.webm<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>c</span>:v copy<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>c</span>:a libvorbis<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>shortest</span> OUTPUT.webm</span></span></pre></div></div>
The resulting file is encoded so that it matches the
`video/webm; codecs="vp9, vorbis"` in
the JavaScript. 
<p>NOTE: I updated ffmpeg an hour after writing
this post and <code>libvorbis</code> didn't get installed
with the new version. I don't want to compile
ffmpeg myself so I'll see about using
<code>libopus</code> or something else instead
next time I have to mess with stuff.</p>
<h2>The Split Script</h2>
<p>Spitting the source <code>.webm</code> file into the parts
is done with this script that runs in bash
on mac/linux (I don't have a Windows machine
handy to determine the command on that OS).</p>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell">!/bin/bash</span><span class="comment line number-sign shell">
<span class="line-marker" data-line="2"></span></span>
<span class="line-marker" data-line="3"></span><span class="meta function-call shell"><span class="variable function shell">split</span></span><span class="meta function-call arguments shell"><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>b</span> 1M<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>d</span> <span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span>church-3818213.webm<span class="punctuation definition string end shell">&quot;</span></span> part-</span>
<span class="line-marker" data-line="4"></span><span class="keyword control for shell">for</span><span class="meta group for shell"> f <span class="keyword control in shell">in</span> part-<span class="keyword operator regexp quantifier shell">*</span></span><span class="keyword operator logical continue shell">;</span> <span class="keyword control do shell">do</span> <span class="meta function-call shell"><span class="variable function shell">mv</span></span><span class="meta function-call arguments shell"> <span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span><span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="variable other readwrite shell">f</span></span><span class="punctuation definition string end shell">&quot;</span></span> <span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span><span class="meta group expansion parameter shell"><span class="punctuation definition variable shell">$</span><span class="variable other readwrite shell">f</span></span>.part<span class="punctuation definition string end shell">&quot;</span></span></span><span class="keyword operator logical continue shell">;</span> <span class="meta function-call shell"><span class="variable function shell">done</span></span></span></pre></div></div>
Line 3 does the split. 
<p>Line 4 is optional. It adds file extensions.
Some servers require one
to server the proper mine time. It's
not necessary on mine. I just like
having explicit extensions.</p>
<h2>Error Messages</h2>
<p>Here's some of the Chrome console log
error messages I got before figuring out
that the audio track was the problem.
Putting them here in hopes that folks
searching for them will see these
instead of being sent down
dead ends by AI that doesn't
take into account that the video
could be the problem.</p>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text plain">MediaSource readyState is: closed
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span>MediaSource or SourceBuffer invalid
<span class="line-marker" data-line="4"></span>
<span class="line-marker" data-line="5"></span>InvalidStateError: Failed to execute 
<span class="line-marker" data-line="6"></span>&#39;appendBuffer&#39; on &#39;SourceBuffer&#39;: 
<span class="line-marker" data-line="7"></span>This SourceBuffer has been removed 
<span class="line-marker" data-line="8"></span>from the parent media source.
<span class="line-marker" data-line="9"></span>
<span class="line-marker" data-line="10"></span>InvalidStateError: Failed to execute 
<span class="line-marker" data-line="11"></span>&#39;endOfStream&#39; on &#39;MediaSource&#39;: 
<span class="line-marker" data-line="12"></span>The MediaSource&#39;s readyState is 
<span class="line-marker" data-line="13"></span>not &#39;open&#39;.
<span class="line-marker" data-line="14"></span>
<span class="line-marker" data-line="15"></span>--- From ffmpeg during processing
<span class="line-marker" data-line="16"></span>
<span class="line-marker" data-line="17"></span>Error parsing Opus packet header.</span></pre></div></div>
<h2>Wrap Up</h2>
<p>This is the first time I've really looked at web video
in the modern age. As with so much these
days, it's mind-blowing what you can do with it
without having to bend over backwards. It took me
way longer to figure out that the audio track was
causing issues than to write up the player script.</p>
<p>Very cool.</p>
<p>-a</p>
<h3>References</h3>
<ul>
<li><a href="/multi-player/">/multi-player/</a></li>
<li><a href="/rust/wasm/static-site-file-decryption/">/rust/wasm/static-site-file-decryption/</a></li>
<li><a href="/rust/wasm/static-site-file-encryption/">/rust/wasm/static-site-file-encryption/</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement">https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API">https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer">https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer#examples">https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer#examples</a></li>
<li><a href="https://en.wikipedia.org/wiki/HTTP_Live_Streaming">https://en.wikipedia.org/wiki/HTTP_Live_Streaming</a></li>
<li><a href="https://ffmpeg.org/ffmpeg-filters.html#anullsrc">https://ffmpeg.org/ffmpeg-filters.html#anullsrc</a></li>
<li><a href="https://ffmpeg.org/ffmpeg-formats.html#hls-1">https://ffmpeg.org/ffmpeg-formats.html#hls-1</a></li>
<li><a href="https://man7.org/linux/man-pages/man1/split.1.html">https://man7.org/linux/man-pages/man1/split.1.html</a></li>
<li><a href="https://videojs.org/">https://videojs.org/</a></li>
<li><a href="https://www.rfc-editor.org/rfc/rfc8216">https://www.rfc-editor.org/rfc/rfc8216</a></li>
<li><a href="https://www.webmproject.org/">https://www.webmproject.org/</a></li>
  <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video">https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video</a></li>
</ul>




]]></summary>
  </entry>
  
  <entry>
    <title>Split a File into Multiple Collections of Bytes</title><link href="https://al9000.com&#x2f;rust&#x2f;general&#x2f;split-a-file-into-collections-of-bytes/"/><id>urn:uuid:5cb4b65c-5aaf-5228-9114-ab7ac2a10e1b</id>
    <updated>2026-04-01T14:01:23-04:00</updated>
    <summary><![CDATA[
<p>This started as an idea for how to
split up files so they don't get ingested
by scrapper bots. It turns one
file into two with every other
byte going to the alternate file
from the one before it. These
can then be reassembled in
WASM on the front-end.</p>
<p>Then, I realized I could just encrypt
the files. They could be decoded
automatically by simply including
the password in the javascript
on the page. Or, you could set up
a form so that only folks with
the password could get them.</p>
<p>I really like that idea in general.
Basically, a way to serve encrypted
content on a static site.
I built a prototype of that
here: <a href="/rust/wasm/static-site-file-decryption/">Password Protecting Static Site Content with WASM</a>.</p>
<p>In the mean time, here's the
code that does the split.</p>


<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="meta path rust">anyhow<span class="punctuation accessor rust">::</span></span>Result<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span>fs<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="3"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span><span class="meta path rust">path<span class="punctuation accessor rust">::</span></span>Path<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="4"></span><span class="keyword other rust">use</span> <span class="meta path rust">std<span class="punctuation accessor rust">::</span></span><span class="meta path rust">path<span class="punctuation accessor rust">::</span></span>PathBuf<span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">main</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="7"></span>  <span class="support macro rust">println!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>Unzipping file bytes<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="8"></span>  <span class="storage type rust">let</span> input_file <span class="keyword operator rust">=</span> <span class="meta path rust">PathBuf<span class="punctuation accessor rust">::</span></span>from<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>samples/church-3818213.webm<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="9"></span>  <span class="storage type rust">let</span> output_dir <span class="keyword operator rust">=</span> <span class="meta path rust">PathBuf<span class="punctuation accessor rust">::</span></span>from<span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>samples/output<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="10"></span>  <span class="support function rust">unzip_file_bytes</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">&amp;</span>input_file<span class="punctuation separator rust">,</span> <span class="keyword operator rust">&amp;</span>output_dir</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="11"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="12"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span>
<span class="line-marker" data-line="13"></span>
<span class="line-marker" data-line="14"></span><span class="meta function rust"><span class="meta function rust"><span class="storage type function rust">fn</span> </span><span class="entity name function rust">unzip_file_bytes</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span>
<span class="line-marker" data-line="15"></span>  <span class="variable parameter rust">input_file</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span>PathBuf,
<span class="line-marker" data-line="16"></span>  <span class="variable parameter rust">output_dir</span><span class="punctuation separator rust">:</span> <span class="keyword operator rust">&amp;</span>Path,
<span class="line-marker" data-line="17"></span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> <span class="meta generic rust">Result<span class="punctuation definition generic begin rust">&lt;</span><span class="punctuation section group begin rust">(</span><span class="punctuation section group end rust">)</span><span class="punctuation definition generic end rust">&gt;</span></span></span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="18"></span>  <span class="storage type rust">let</span> bytes <span class="keyword operator rust">=</span> <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>read<span class="meta group rust"><span class="punctuation section group begin rust">(</span>input_file</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="19"></span>
<span class="line-marker" data-line="20"></span>  <span class="storage type rust">let</span> <span class="storage modifier rust">mut</span> alfa <span class="keyword operator rust">=</span> <span class="support macro rust">vec!</span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="punctuation section group end rust">]</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="21"></span>  <span class="storage type rust">let</span> <span class="storage modifier rust">mut</span> bravo <span class="keyword operator rust">=</span> <span class="support macro rust">vec!</span><span class="meta group rust"><span class="punctuation section group begin rust">[</span><span class="punctuation section group end rust">]</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="22"></span>  bytes.<span class="support function rust">iter</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">enumerate</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>.<span class="support function rust">for_each</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">|</span></span></span><span class="meta function closure rust"><span class="meta function parameters rust"><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="variable parameter rust">index</span><span class="punctuation separator rust">,</span> <span class="variable parameter rust">value</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation section parameters end rust">|</span></span> </span><span class="meta function closure rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="23"></span>    <span class="keyword control rust">if</span> index <span class="keyword operator rust">%</span> <span class="constant numeric integer decimal rust">2</span> <span class="keyword operator rust">=</span><span class="keyword operator rust">=</span> <span class="constant numeric integer decimal rust">0</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="24"></span>      alfa.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">*</span>value</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="25"></span>    </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span> <span class="keyword control rust">else</span> <span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="26"></span>      bravo.<span class="support function rust">push</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="keyword operator rust">*</span>value</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="27"></span>    </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span>
<span class="line-marker" data-line="28"></span>  </span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="29"></span>
<span class="line-marker" data-line="30"></span>  <span class="storage type rust">let</span> alfa_out <span class="keyword operator rust">=</span> output_dir.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>alfa<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="31"></span>  <span class="storage type rust">let</span> bravo_out <span class="keyword operator rust">=</span> output_dir.<span class="support function rust">join</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>bravo<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="32"></span>  <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>write<span class="meta group rust"><span class="punctuation section group begin rust">(</span>alfa_out<span class="punctuation separator rust">,</span> alfa</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="33"></span>  <span class="meta path rust">fs<span class="punctuation accessor rust">::</span></span>write<span class="meta group rust"><span class="punctuation section group begin rust">(</span>bravo_out<span class="punctuation separator rust">,</span> bravo</span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="keyword operator rust">?</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="34"></span>  <span class="support macro rust">println!</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>Done<span class="punctuation definition string end rust">&quot;</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="35"></span>  <span class="support type rust">Ok</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="36"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>
<div class="highlight-wrapper"><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="meta group rust"><span class="punctuation section group begin rust">[</span>package<span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="2"></span>name <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>unzip_a_file<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="3"></span>version <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>0.1.0<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="4"></span>edition <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>2024<span class="punctuation definition string end rust">&quot;</span></span>
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span><span class="meta group rust"><span class="punctuation section group begin rust">[</span>dependencies<span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="7"></span>anyhow <span class="keyword operator rust">=</span> <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>1.0.102<span class="punctuation definition string end rust">&quot;</span></span></span></pre></div></div>
<p>I haven't written the re-assembly code yet
since I'm going with encryption. I don't
expect it to be difficult if I come back to it.</p>
<p>-a</p>



]]></summary>
  </entry>
  
  <entry>
    <title>Hello, World in Rust WASM</title><link href="https://al9000.com&#x2f;rust&#x2f;wasm&#x2f;hello-world/"/><id>urn:uuid:81dedf75-44bf-550c-bd72-be9dac79432a</id>
    <updated>2026-04-01T11:40:00-04:00</updated>
    <summary><![CDATA[

<p>
  This is a basic `Hello, World` WASM 
  app written in rust.
</p>

<h3>Rust</h3>
<div class="highlight-wrapper"><div class="file-name">Cargo.toml</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text html basic">[package]
<span class="line-marker" data-line="2"></span>name = &quot;hello-world&quot;
<span class="line-marker" data-line="3"></span>version = &quot;0.1.0&quot;
<span class="line-marker" data-line="4"></span>edition = &quot;2024&quot;
<span class="line-marker" data-line="5"></span>
<span class="line-marker" data-line="6"></span>[lib]
<span class="line-marker" data-line="7"></span>crate-type = [&quot;cdylib&quot;]
<span class="line-marker" data-line="8"></span>
<span class="line-marker" data-line="9"></span>[dependencies]
<span class="line-marker" data-line="10"></span>wasm-bindgen = &quot;0.2.116&quot;</span></pre></div></div>

<div class="highlight-wrapper"><div class="file-name">src/lib.rs</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source rust"><span class="keyword other rust">use</span> <span class="meta path rust">wasm_bindgen<span class="punctuation accessor rust">::</span></span><span class="meta path rust">prelude<span class="punctuation accessor rust">::</span></span><span class="keyword operator rust">*</span><span class="punctuation terminator rust">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta annotation rust"><span class="punctuation definition annotation rust">#</span><span class="punctuation section group begin rust">[</span><span class="variable annotation rust">wasm_bindgen</span><span class="punctuation section group end rust">]</span></span>
<span class="line-marker" data-line="4"></span><span class="meta function rust"><span class="meta function rust"><span class="storage modifier rust">pub</span> <span class="storage type function rust">fn</span> </span><span class="entity name function rust">hello_world</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters begin rust">(</span></span><span class="meta function rust"><span class="meta function parameters rust"><span class="punctuation section parameters end rust">)</span></span></span></span><span class="meta function rust"> <span class="meta function return-type rust"><span class="punctuation separator rust">-&gt;</span> String</span> </span><span class="meta function rust"><span class="meta block rust"><span class="punctuation section block begin rust">{</span>
<span class="line-marker" data-line="5"></span>  <span class="string quoted double rust"><span class="punctuation definition string begin rust">&quot;</span>Hello, world!<span class="punctuation definition string end rust">&quot;</span></span>.<span class="support function rust">to_string</span><span class="meta group rust"><span class="punctuation section group begin rust">(</span></span><span class="meta group rust"><span class="punctuation section group end rust">)</span></span>
<span class="line-marker" data-line="6"></span></span><span class="meta block rust"><span class="punctuation section block end rust">}</span></span></span></span></pre></div></div>

<div class="highlight-wrapper"><div class="file-name">build script</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell">!/bin/bash</span><span class="comment line number-sign shell">
<span class="line-marker" data-line="2"></span></span>
<span class="line-marker" data-line="3"></span><span class="meta function-call shell"><span class="variable function shell">wasm-pack</span></span><span class="meta function-call arguments shell"> build<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>target</span> web</span></span></pre></div></div>

<h3>HTML</h3>
<div class="highlight-wrapper"><div class="file-name">page.html</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="text html basic"><span class="meta tag script begin html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag script html">script</span></span><span class="meta tag script begin html"> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>module<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">src</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>//rust/wasm/hello-world/hello-world.js<span class="punctuation definition string end html">&quot;</span></span></span></span><span class="meta tag script begin html"><span class="punctuation definition tag end html">&gt;</span></span><span class="source js embedded html"></span><span class="meta tag script end html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag script html">script</span><span class="punctuation definition tag end html">&gt;</span></span>
<span class="line-marker" data-line="2"></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">div</span> <span class="meta attribute-with-value id html"><span class="entity other attribute-name id html">id</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value id html"><span class="string quoted double html"><span class="meta toc-list id html">output</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">div</span><span class="punctuation definition tag end html">&gt;</span></span></span></pre></div></div>

<h4>JavaScript</h4>
<div class="highlight-wrapper"><div class="file-name">hello-world.js</div><div class="code-block numbers copy-button"><pre><span class="line-marker" data-line="1"></span><span class="source js"><span class="meta import js"><span class="keyword control import-export js">import</span> <span class="variable other readwrite js">init</span><span class="punctuation separator comma js">,</span> <span class="meta block js"><span class="punctuation section block js">{</span> <span class="variable other readwrite js">hello_world</span> <span class="punctuation section block js">}</span></span> <span class="keyword control import-export js">from</span> <span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>./pkg/hello_world.js<span class="punctuation definition string end js">&quot;</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="2"></span>
<span class="line-marker" data-line="3"></span><span class="meta function declaration js"><span class="storage type js">async</span> <span class="storage type function js">function</span> <span class="entity name function js">main</span><span class="punctuation section group begin js">(</span><span class="punctuation section group end js">)</span><span class="meta function declaration js"> </span></span><span class="meta block js"><span class="punctuation section block js">{</span>
<span class="line-marker" data-line="4"></span>  <span class="keyword control flow js">await</span> <span class="meta function-call js"><span class="variable function js">init</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="5"></span>  <span class="storage type js">const</span> <span class="variable other readwrite js">el</span> <span class="keyword operator assignment js">=</span> <span class="support type object dom js">document</span><span class="punctuation accessor js">.</span><span class="meta function-call method js"><span class="variable function js">querySelector</span><span class="meta group js"><span class="punctuation section group js">(</span><span class="string quoted double js"><span class="punctuation definition string begin js">&quot;</span>#output<span class="punctuation definition string end js">&quot;</span></span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="6"></span>  <span class="variable other object js">el</span><span class="punctuation accessor js">.</span><span class="meta property object js">innerHTML</span> <span class="keyword operator assignment js">=</span> <span class="meta function-call js"><span class="variable function js">hello_world</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span>
<span class="line-marker" data-line="7"></span><span class="punctuation section block js">}</span></span>
<span class="line-marker" data-line="8"></span>
<span class="line-marker" data-line="9"></span><span class="meta function-call js"><span class="variable function js">main</span><span class="meta group js"><span class="punctuation section group js">(</span></span><span class="meta group js"><span class="punctuation section group js">)</span></span></span><span class="punctuation terminator statement js">;</span></span></pre></div></div>

<h4>Output</h4>
<div class="output-block"><pre><code>
<script type="module" src="/rust/wasm/hello-world/hello-world.js"></script>
<div id="output"></div>

</code></pre></div>



]]></summary>
  </entry>
  
  <entry>
    <title>Scratchpad</title><link href="https://al9000.com&#x2f;scratchpad/"/><id>urn:uuid:3d657954-64c0-50dd-a360-7eadd25f6012</id>
    <updated>2026-01-01T11:12:12-05:00</updated>
    <summary><![CDATA[

<ul>
  <li>
    <a href="&#x2f;scratchpad&#x2f;css-only-tabs&#x2f;index.html">CSS Only Tabs Scratchpad</a>
  </li>
  <li>
    <a href="&#x2f;scratchpad&#x2f;line-numbers&#x2f;index.html">Line Numbers Scratchpad</a>
  </li>
  <li>
    Untitled item
  </li>
  <li>
    Untitled item
  </li>
</ul>

]]></summary>
  </entry>
  
  <entry>
    <title>The Clicky Sound</title><link href="https://al9000.com&#x2f;posts&#x2f;the-clicky-sound/"/><id>urn:uuid:9a00181b-dd35-54eb-a82e-2f7c73a3eddd</id>
    <updated>2020-09-09T00:00:00-04:00</updated>
    <summary><![CDATA[
<p>Okay.</p>
<p>Just make the clicky sound.</p>
<p><em>[clickity, click]</em></p>
<p>This isn't the start. It's just making the sound.</p>
<p><em>[clickity, clickity, click]</em></p>
<p>Don't worry about the words. They don't matter.</p>
<p>Just <em>clickity, clickity, click</em> any ol' thing.</p>
<p>Maybe something like:</p>
<p><em>Check test - one, two - one, two</em></p>
<p><em>These words, words, words don't matter</em></p>
<p><em>The quick brown fox jumps over the lazy dog</em></p>
<p><em>[clickity, clickity, click]</em></p>
<p>Good.</p>
<p>The fingers are moving. Finding momentum.</p>
<p>Started without starting. Now I can start for real.</p>
<p><em>[clickity, clickity, go...]</em></p>
<p>--</p>
<p>Howdy, folks.</p>
<p>Welcome to the show.</p>
<p>There won't be a narrative today. I spent hours trying to
make one. All I got was a mess.</p>
<p>There's just too much. I'm too out of practice.</p>
<p>Good news, tough. My hands are moving. I'm
putting down words. They aren't the ones I expected, but they'll do.</p>
<p>You see, I'm recovering from bipolar episodes.
One of mania. One of suicidal depression. Each caused
brain damage. Not a lot, but still.</p>
<p>Combined with the fog of meds, my brain got pretty fucked.</p>
<p>Somewhere in there, I lost my ability to write. Words were gone.
Reaching for them was like reaching for something in the
dark and missing. I could feel the space, but nothing was there.</p>
<p>After two years, the fog is lifting. Words coming back. I can hear
them again. I can <strong>feel</strong> them again. They have weight and shape. But,
I don't know if I can use them. I don't know if my writing is gone.</p>
<p>Imagining life without writing is impossible. I hear static.
White noise. And, there's fear. Fear I didn't know existed.
Not until I started writing this. It was hidden. Low, guttural.</p>
<p>Fear I'd lost my foundations. Not just my writing,
but everything that makes me me.</p>
<p>It was paralyzing. I couldn't write, or think, or... anything.</p>
<p>Then, I started making the clicky sound.</p>


]]></summary>
  </entry>

</feed>