<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>adamsimpson.net Post Feed</title>
    <link>https://adamsimpson.net/</link>
    <description>Last 20 posts for adamsimpson.net</description>
    <lastBuildDate>Sat, 28 Mar 2026 18:29:12 +0000</lastBuildDate>
    <language>en-us</language>

      <item>
        <title>Another reason to love NixOS</title>
          <link>https://adamsimpson.net/writing/another-reason-to-love-nixos</link>

        <guid>https://adamsimpson.net/writing/another-reason-to-love-nixos</guid>
        <pubDate>Sat, 28 Mar 2026 18:27:15 +0000</pubDate>

          <description>
            <![CDATA[ Nix is a great fit for LLMs and humans. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Clearly, I <a href="https://adamsimpson.net/writing/nixpkgs-is-a-treasure" >love Nix</a>.</p>

<p><a href="https://www.birkey.co/2026-03-22-why-i-love-nixos.html" >So does Birkey Consulting</a>:</p>

<blockquote>
<p>I love NixOS because it fits especially well with the way I work in the current LLM coding era.
Tools are changing very quickly. Coding agents often need very specific versions of utilities, compilers and runtimes. They need to install something, use it, throw it away, try another version and keep going without turning my PC into a garbage dump of conflicting state. Nix fits that model naturally. If I tell a coding agent that I use Nix, it is usually clever enough to reach for nix shell or nix develop to bring the needed tool into an isolated environment and execute it there. That is especially handy because Nix treats tooling as a declared input instead of an accidental side effect on the system.</p>
</blockquote>

<p>One wrinkle I've found is that Codex will get tripped up if I add a <code>shell.nix</code> file after the session has started. My theory: Codex gets the <code>$PATH</code> value at start and has no way to update it later. Not a huge deal to exit the session, start a new one, and <code>/resume</code> the conversation.</p>

<p>Also, the Nix language is like if <a href="https://jsonnet.org" ><code>jsonnet</code></a> got hit by an even more function-oriented truck. LLMs make this suck less though since they're great at writing Nix!</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Another reason to love NixOS">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>My typical shell.nix file</title>
          <link>https://adamsimpson.net/writing/my-typical-shell-nix-file</link>

        <guid>https://adamsimpson.net/writing/my-typical-shell-nix-file</guid>
        <pubDate>Sat, 21 Mar 2026 23:59:02 +0000</pubDate>

          <description>
            <![CDATA[ I use nix to manage packages on macOS and on Linux (nixOS). This is for my future self more than anything to document my "ideal" `shell.nix` file. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I use nix to manage packages on macOS and on Linux (nixOS). This is for my future self more than anything to document my &quot;ideal&quot; <code>shell.nix</code> file.</p><pre style="color:#f8f8f2;background-color:#282a36">{ pkgs <span style="color:#ff79c6">?</span> <span style="color:#ff79c6">import</span> <span style="color:#f1fa8c">&lt;nixpkgs&gt;</span> {} }:

pkgs<span style="color:#ff79c6">.</span>mkShell {
  buildInputs <span style="color:#ff79c6">=</span> [
    pkgs<span style="color:#ff79c6">.</span>go
    pkgs<span style="color:#ff79c6">.</span>gopls
    pkgs<span style="color:#ff79c6">.</span>nodejs
  ];

  hardeningDisable <span style="color:#ff79c6">=</span> [ <span style="color:#f1fa8c">&#34;fortify&#34;</span> ];

  shellHook <span style="color:#ff79c6">=</span> <span style="color:#f1fa8c">&#39;&#39;
</span><span style="color:#f1fa8c">    DIRECTORY_NAME=&#34;/tmp/$(basename &#34;$PWD&#34;)&#34;
</span><span style="color:#f1fa8c">    mkdir -p $DIRECTORY_NAME/go-cache $DIRECTORY_NAME/go $DIRECTORY_NAME/npm
</span><span style="color:#f1fa8c">    export GOPATH=$DIRECTORY_NAME/go
</span><span style="color:#f1fa8c">    export GOCACHE=$DIRECTORY_NAME/go-cache
</span><span style="color:#f1fa8c">    export NODE_PATH=$DIRECTORY_NAME/npm
</span><span style="color:#f1fa8c">    export NPM_CONFIG_PREFIX=$NODE_PATH
</span><span style="color:#f1fa8c">    export PATH=$DIRECTORY_NAME/go/bin:$PATH:$NODE_PATH/bin
</span><span style="color:#f1fa8c">  &#39;&#39;</span>;
}</pre>


<p>The goal of <code>shell.nix</code> is to give every project it's own shell where all the needed tools are available and isolate each project from itself, e.g. one project can use a different version of <code>node</code>.</p>

<p>I've settled on the convention of <code>/tmp/&lt;project-dir-name&gt;</code> as the location for &quot;language&quot; or &quot;runtime&quot; dependencies. Meaning, <code>nix</code> handles bringing in <code>node</code> but then <code>node</code> wants to install things too. <code>/tmp</code> is a nice place because I don't care where that stuff goes I just don't want it to collide with other things.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: My typical shell.nix file">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>MacBook Neo</title>
          <link>https://adamsimpson.net/writing/macbook-neo</link>

        <guid>https://adamsimpson.net/writing/macbook-neo</guid>
        <pubDate>Thu, 19 Mar 2026 03:30:13 +0000</pubDate>

          <description>
            <![CDATA[ Any iPad + a keyboard case makes zero sense compared to the Neo. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>The MacBook Neo feels like the 11&quot; Air.</p>

<p><aside class="pa2 bg-light-gray">
  My top three favorite Macs:</p>

<ol>
<li>PowerBook G4 (12&quot;)</li>
<li>MacBook Neo</li>
<li>MacBook Air (11&quot;)
</aside></li>
</ol>

<p>Any iPad + a keyboard case makes zero sense compared to the Neo.</p>

<p>All the iPad's capabilities (M-series CPU, OLED screen, premium everything) are wasted on iPadOS. iPad is also needlessly stuck with a single USB-C port. Is the Neo's second port good? No! But in a pinch it's better than no port.</p>

<p>The A18 Pro is great, already compiled a few Xcode projects, listened to multiple sources of audio at once, and even managed my clipboard.</p>

<p>Oh, and the Neo actually goes to sleep, like real sleep. No dead battery issues like iPadOS.</p>

<p>It's the cheapest, most repairable, and smallest Mac. Win, win, win.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: MacBook Neo">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>nixpkgs is a treasure</title>
          <link>https://adamsimpson.net/writing/nixpkgs-is-a-treasure</link>

        <guid>https://adamsimpson.net/writing/nixpkgs-is-a-treasure</guid>
        <pubDate>Fri, 10 May 2024 18:07:43 +0000</pubDate>

          <description>
            <![CDATA[ Nix and NixOS continue to be the best way to manage and build software that I've found. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Nix and NixOS continue to be the best way to manage and build software that I've found. Every project has a <code>shell.nix</code> file in the root where I can define the specific software needed to work on that project along with any necessary environment variables or <code>$PATH</code> modifications. I ran into an issue this week though where I needed an &quot;old&quot; version of Go (<code>1.20</code>) but the version had already been <a href="https://github.com/NixOS/nixpkgs/tree/2e31c3a7e9825ec1ef087b5db2b801e1a9fb6f3b/pkgs/development/compilers/go" >removed from <code>nixpkgs</code></a>. How can I pull in an &quot;unlisted&quot; version into my <code>shell.nix</code>?</p>

<p>It's actually pretty straightforward, utilize <a href="https://nixos.org/manual/nix/stable/language/builtins.html?highlight=fetchtarball#builtins-fetchTarball" ><code>fetchTarball</code></a> to pull in <code>nixpkgs</code> based on a commit where the version was present sometime in the past. You can mix that <code>import</code> in with regular/&quot;current&quot; packages with no issue like so:</p><pre style="color:#f8f8f2;background-color:#282a36">{ pkgs <span style="color:#ff79c6">?</span> <span style="color:#ff79c6">import</span> <span style="color:#f1fa8c">&lt;nixpkgs&gt;</span> {} }:

<span style="color:#ff79c6">let</span> oldGo <span style="color:#ff79c6">=</span> <span style="color:#ff79c6">import</span> (<span style="color:#8be9fd;font-style:italic">builtins</span><span style="color:#ff79c6">.</span><span style="color:#8be9fd;font-style:italic">fetchTarball</span> {
    url <span style="color:#ff79c6">=</span> <span style="color:#f1fa8c">&#34;https://github.com/NixOS/nixpkgs/archive/33c51330782cb486764eb598d5907b43dc87b4c2.tar.gz&#34;</span>;
    sha256 <span style="color:#ff79c6">=</span> <span style="color:#f1fa8c">&#34;sha256:0nflmpfp3pk704vhlvlgh5vgwl8qciqi18mcpl32k79qjziwmih8&#34;</span>;
    }) {};
<span style="color:#ff79c6">in</span> 

pkgs<span style="color:#ff79c6">.</span>mkShell {
  buildInputs <span style="color:#ff79c6">=</span> [
    oldGo<span style="color:#ff79c6">.</span>go_1_20
    pkgs<span style="color:#ff79c6">.</span>gopls
    pkgs<span style="color:#ff79c6">.</span>nodejs_18
  ];
  
  hardeningDisable <span style="color:#ff79c6">=</span> [ <span style="color:#f1fa8c">&#34;fortify&#34;</span> ];

  shellHook <span style="color:#ff79c6">=</span> <span style="color:#f1fa8c">&#39;&#39;
</span><span style="color:#f1fa8c">    mkdir -p .go .npm
</span><span style="color:#f1fa8c">    export GOPATH=$PWD/.go
</span><span style="color:#f1fa8c">    export NODE_PATH=$PWD/.npm
</span><span style="color:#f1fa8c">    export NPM_CONFIG_PREFIX=$NODE_PATH
</span><span style="color:#f1fa8c">    export PATH=$PWD/.yarn/sdks/typescript/bin:$PWD/.go/bin:$PATH:$NODE_PATH/bin
</span><span style="color:#f1fa8c">  &#39;&#39;</span>;
}</pre>


<p>Notice I can reference the &quot;<code>nixpkgs</code>&quot; tarball/snapshot, <code>oldGo</code>, and pull in the version of Go I need?! <code>nixpkgs</code> is such a treasure trove of software, it's absolutely incredible!</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: nixpkgs is a treasure">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Lessons learned from integrating OpenAI into a Grafana data source</title>
          <link>https://adamsimpson.net/writing/lessons-learned-from-integrating-openai-into-a-grafana-data-source</link>

        <guid>https://adamsimpson.net/writing/lessons-learned-from-integrating-openai-into-a-grafana-data-source</guid>
        <pubDate>Tue, 25 Jul 2023 19:10:24 +0000</pubDate>

          <description>
            <![CDATA[ I wrote over on the <a href="https://grafana.com/blog/">Grafana blog</a> about a few <a href="https://grafana.com/blog/2023/07/25/lessons-learned-from-integrating-openai-into-a-grafana-data-source/">lessons or observations we learned while integrating OpenAI into the ADX data source</a>. It's my first post on the Grafana blog and I'm pretty excited, so check it out! ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I wrote over on the <a href="https://grafana.com/blog/" >Grafana blog</a> about a few <a href="https://grafana.com/blog/2023/07/25/lessons-learned-from-integrating-openai-into-a-grafana-data-source/" >lessons or observations we learned while integrating OpenAI into the ADX data source</a>. It's my first post on the Grafana blog and I'm pretty excited, so check it out!</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Lessons learned from integrating OpenAI into a Grafana data source">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Better scripting with gh</title>
          <link>https://adamsimpson.net/writing/better-scripting-with-gh</link>

        <guid>https://adamsimpson.net/writing/better-scripting-with-gh</guid>
        <pubDate>Sat, 22 Jul 2023 15:33:16 +0000</pubDate>

          <description>
            <![CDATA[ I've become a big fan of the <a href="https://cli.github.com/">gh</a> CLI tool from Github. It has eliminated the need for me to manage developer tokens for my scripts. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I've become a big fan of the <a href="https://cli.github.com/" >gh</a> CLI tool from Github. It has eliminated the need for me to manage developer tokens for my scripts. Instead of using <code>curl</code> with a Github token and the Github API, I can simply use <code>gh</code>. What's even better is that in more advanced situations where there isn't a valid subcommand for what I want to script, I can use the <a href="https://cli.github.com/manual/gh_api" ><code>gh api</code></a> escape hatch to do <code>curl</code>-style HTTP requests to the API without messing with authentication or even pagination. Here are two recent scripts I wrote that highlight the power and convenience of <code>gh</code>.</p>

<h2>PR Kudos</h2>

<p>I created this script to help me give better kudos to folks in our retro meeting. When I provide a Github team name as an argument, it displays all PRs from members of that team. What I really like is that it only shows PRs from the last two weeks, which gives me a nice overview of recent activity.</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">#!/bin/bash
</span><span style="color:#ff79c6"></span>
<span style="color:#8be9fd;font-style:italic">start</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>date -d <span style="color:#f1fa8c">&#34;2 weeks ago&#34;</span> +%Y-%m-%d<span style="color:#ff79c6">)</span>
<span style="color:#8be9fd;font-style:italic">end</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>date +%Y-%m-%d<span style="color:#ff79c6">)</span>

<span style="color:#8be9fd;font-style:italic">details</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>gh api /orgs/grafana/teams/<span style="color:#8be9fd;font-style:italic">$1</span> | jq -r <span style="color:#f1fa8c">&#39;&#34;\(.id),\(.organization.id)&#34;&#39;</span><span style="color:#ff79c6">)</span>
<span style="color:#8be9fd;font-style:italic">teamId</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">details</span><span style="color:#f1fa8c">}</span> | cut -d , -f 1<span style="color:#ff79c6">)</span>
<span style="color:#8be9fd;font-style:italic">orgId</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">details</span><span style="color:#f1fa8c">}</span> | cut -d , -f 2<span style="color:#ff79c6">)</span>

gh api <span style="color:#f1fa8c">&#34;organizations/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">orgId</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/team/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">teamId</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/members&#34;</span> | <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>  jq -r <span style="color:#f1fa8c">&#39;.[] | .login&#39;</span> | <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>  xargs -I % gh search prs --author<span style="color:#ff79c6">=</span>% --created<span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">start</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">..</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">end</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>  --json<span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#34;state,repository,url,title,updatedAt,author&#34;</span> --template <span style="color:#f1fa8c">&#39;{{range .}}{{tablerow (.author.login | autocolor &#34;green&#34;) (hyperlink .url .title) (.repository.name | autocolor &#34;blue&#34;) (.state | autocolor &#34;red&#34;) (timeago .updatedAt)}}{{end}}
</span><span style="color:#f1fa8c">{{tablerender}}&#39;</span></pre>


<h2>Notification OCD</h2>

<p>The second script focuses on managing notifications related to pull requests and issues. I usually find that about one-third of my notifications are for merged PRs, PRs created by bots, or closed Issues. I don't care about these types of events. With this script, I can mark those notifications as done, which reduces clutter in my GitHub notifications and helps me see important updates. As I mentioned above, one cool feature of the <code>api</code> subcommand is that it allows me to consume all possible pages of a response using the <code>--paginate</code> flag, eliminating the need for a loop + token field dance!</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">#!/bin/bash
</span><span style="color:#ff79c6"></span><span style="color:#8be9fd;font-style:italic">declare</span> -A typeLookup
typeLookup<span style="color:#ff79c6">[</span><span style="color:#f1fa8c">&#34;PullRequest&#34;</span><span style="color:#ff79c6">]=</span><span style="color:#f1fa8c">&#34;pull&#34;</span>
typeLookup<span style="color:#ff79c6">[</span><span style="color:#f1fa8c">&#34;Issue&#34;</span><span style="color:#ff79c6">]=</span><span style="color:#f1fa8c">&#34;issues&#34;</span>

<span style="color:#8be9fd;font-style:italic">resp</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>gh api /notifications --paginate | jq -r <span style="color:#f1fa8c">&#39;.[] | select(.subject.type == &#34;PullRequest&#34; or .subject.type == &#34;Issue&#34;) | &#34;\(.repository.full_name),\(.subject.url),\(.id),\(.subject.type)&#34;&#39;</span><span style="color:#ff79c6">)</span>

<span style="color:#ff79c6">for</span> x in <span style="color:#8be9fd;font-style:italic">$resp</span>; <span style="color:#ff79c6">do</span>
  <span style="color:#8be9fd;font-style:italic">name</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">x</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> | cut -d <span style="color:#f1fa8c">&#39;,&#39;</span> -f 1<span style="color:#ff79c6">)</span>
  <span style="color:#8be9fd;font-style:italic">id</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">x</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> | cut -d <span style="color:#f1fa8c">&#39;,&#39;</span> -f 3<span style="color:#ff79c6">)</span>
  <span style="color:#8be9fd;font-style:italic">number</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>basename <span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">x</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> | cut -d <span style="color:#f1fa8c">&#39;,&#39;</span> -f 2<span style="color:#ff79c6">))</span>
  <span style="color:#8be9fd;font-style:italic">ofType</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">x</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> | cut -d <span style="color:#f1fa8c">&#39;,&#39;</span> -f 4<span style="color:#ff79c6">)</span>
  <span style="color:#8be9fd;font-style:italic">urlType</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span><span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">typeLookup</span>[<span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">ofType</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span>]<span style="color:#f1fa8c">}</span><span style="color:#ff79c6">)</span>
  <span style="color:#8be9fd;font-style:italic">isBot</span><span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#34;false&#34;</span>

  <span style="color:#ff79c6">if</span> <span style="color:#ff79c6">[</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">ofType</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#34;PullRequest&#34;</span> <span style="color:#ff79c6">]</span>; <span style="color:#ff79c6">then</span>
    <span style="color:#8be9fd;font-style:italic">isMerged</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>gh pr view --repo <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">number</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> --json closed | jq -r .closed<span style="color:#ff79c6">)</span>
    <span style="color:#8be9fd;font-style:italic">isBot</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>gh pr view --repo <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">number</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> --json author | jq -r .author.is_bot<span style="color:#ff79c6">)</span>
  <span style="color:#ff79c6">fi</span>

  <span style="color:#ff79c6">if</span> <span style="color:#ff79c6">[</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">ofType</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#34;Issue&#34;</span> <span style="color:#ff79c6">]</span>; <span style="color:#ff79c6">then</span>
    <span style="color:#8be9fd;font-style:italic">isMerged</span><span style="color:#ff79c6">=</span><span style="color:#ff79c6">$(</span>gh issue view --repo <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">number</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> --json closed | jq -r .closed<span style="color:#ff79c6">)</span>
  <span style="color:#ff79c6">fi</span>

  <span style="color:#ff79c6">if</span> <span style="color:#ff79c6">[</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">isMerged</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#34;true&#34;</span> <span style="color:#ff79c6">]</span> <span style="color:#ff79c6">||</span> <span style="color:#ff79c6">[</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">isBot</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#34;true&#34;</span> <span style="color:#ff79c6">]</span>; <span style="color:#ff79c6">then</span>
    <span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">&#34;marking https://github.com/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">urlType</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">number</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c"> as done...&#34;</span>
    gh api -X PATCH <span style="color:#f1fa8c">&#34;/notifications/threads/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">id</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span>
  <span style="color:#ff79c6">fi</span>
<span style="color:#ff79c6">done</span></pre>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Better scripting with gh">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>End of an era</title>
          <link>https://adamsimpson.net/writing/end-of-an-era</link>

        <guid>https://adamsimpson.net/writing/end-of-an-era</guid>
        <pubDate>Thu, 15 Jun 2023 18:13:50 +0000</pubDate>

          <description>
            <![CDATA[ Today I removed two of my most-used apps on my phone, <a href='https://apolloapp.io/'>Apollo</a> and <a href='https://tapbots.com/tweetbot/'>Tweetbot</a>. It feels like the end of an era. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Today I removed two of my most-used apps on my phone, <a href="https://apolloapp.io/" >Apollo</a> and <a href="https://tapbots.com/tweetbot/" >Tweetbot</a>. It feels like the end of an era. </p>

<p>Twitter and Reddit were both social websites that are/were terrible without a lot of cultivation and effort, but over the years I had shaped my experience on those services to be pretty good thanks in large part to Apollo and Tweetbot being such powerful tools. </p>

<p>Ironically the only social web thing I still use (outside of Instagram) is <a href="https://feedbin.com/" >RSS</a>. I will probably spin up a Mastodon instance here eventually but for now I've subscribed to folks via Mastodon's RSS support and it's good enough for now.</p>

<p>I guess I just wanted to give a shout out to the devs of Apollo and Tweetbot: thank you for making such great apps, I will miss them.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: End of an era">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Hacking on Grafana with Web Assembly</title>
          <link>https://adamsimpson.net/writing/hacking-on-grafana-with-web-assembly</link>

        <guid>https://adamsimpson.net/writing/hacking-on-grafana-with-web-assembly</guid>
        <pubDate>Fri, 19 Aug 2022 19:10:19 +0000</pubDate>

          <description>
            <![CDATA[ Grafana had a hack week this past week and I opted to work on WebAssembly(WASM)-related things. My vague original idea was to see if I could compile the Grafana server for WASM. ]]>
          </description>
          <content:encoded><![CDATA[
            <p><aside class="pa2 bg-light-gray">
I <em>finally</em> got around to pushing the code (<a href="https://github.com/asimpson/hackathon-2022-08-wasm" >repo</a>) I outline here to a S3 bucket as a demo: <a href="http://wasm-hack-week-2022.s3-website-us-east-1.amazonaws.com" >http://wasm-hack-week-2022.s3-website-us-east-1.amazonaws.com</a>
</aside>
<a href="https://grafana.com/" >Grafana</a> had a hack week this past week and I opted to work on WebAssembly(WASM)-related things. My vague original idea was to see if I could compile the Grafana server for WASM.</p>

<p>The original inspiration for this idea came from <a href="https://simonwillison.net/2022/May/4/datasette-lite/" >Simon Willison’s work with Datasette Lite</a>. However, compiling Grafana as a WASM binary proved <a href="https://github.com/golang/go/issues/32548" >difficult</a> with existing <a href="https://pkg.go.dev/go/build#hdr-Build_Constraints" >build constraints</a>. After spending some time trying to get that to work I changed course a bit and instead focused on compiling a basic <code>go</code> HTTP server as a WASM module. The new goal being to have a proof of concept that bundled the HTTP server as a WASM binary and intercepted any clicked links on the page and finally passed those links to be resolved by the <code>go</code> server in WASM. </p>

<p>I used a <a href="https://developer.mozilla.org/en-US/docs/WebAssembly/Concepts" >Web Worker</a> to interact with the WASM binary. This frees up the main thread of the browser. To put the WASM binary into the worker I loaded the binary and sent a message that contained the binary as a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module" ><code>WebAssembly.Module</code></a>. </p>

<p>The Web Worker can then call any <code>go</code> functions that have been exposed via <a href="https://pkg.go.dev/syscall/js#FuncOf" ><code>FuncOf</code></a>. Once the <code>go</code> function returns data, the worker posts that response back to the main thread via another message.</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#8be9fd;font-style:italic">let</span> module;
importScripts(<span style="color:#f1fa8c">&#34;wasm_exec.js&#34;</span>)
go <span style="color:#ff79c6">=</span> <span style="color:#ff79c6">new</span> Go();

self.onmessage <span style="color:#ff79c6">=</span> async (e) =&gt; {
  <span style="color:#ff79c6">if</span> (e.data.type <span style="color:#ff79c6">===</span> <span style="color:#f1fa8c">&#34;module&#34;</span>) {
    module <span style="color:#ff79c6">=</span> e.data.module;
    <span style="color:#ff79c6">return</span>;
  }

  <span style="color:#ff79c6">if</span> (module) {
    console.log(<span style="color:#f1fa8c">&#39;Message received: &#39;</span>, e.data.path);
    <span style="color:#ff79c6">const</span> instance <span style="color:#ff79c6">=</span> await WebAssembly.instantiate(module, go.importObject);
    go.run(instance);
    postMessage(parsePath(e.data.path)); <span style="color:#6272a4">// parsePath is exposed via FuncOf
</span><span style="color:#6272a4"></span>  }
}
</pre>


<p>Sidenote: I wish <code>go</code> could use the same pragma syntax <code>tinygo</code> uses to expose functions instead of the verbose <code>FuncOf</code>. There's <a href="https://github.com/golang/go/issues/25612" >an issue</a> but it has been open since 2018. </p>

<p>Obviously, there is no <code>localhost</code> to listen on in a WASM environment. To get around that I created a bare bones <a href="https://pkg.go.dev/net/http#ResponseWriter" ><code>ResponseWriter</code></a> and used that with the <a href="https://pkg.go.dev/net/http#Request" ><code>Request</code></a> to run the Handler’s <a href="https://pkg.go.dev/net/http#HandlerFunc.ServeHTTP" ><code>ServeHTTP</code></a> function which consults the routes that are defined and runs the matching handler code. This allowed me to use a build constraint (<code>setup.go</code> and <code>setup_js.go</code>) and keep my HTTP server functioning normally when run from a terminal but then also worked when run in a WASM context. Here's what those two files look like:</p>

<p><code>setup</code></p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#6272a4">//go:build !js
</span><span style="color:#6272a4">// +build !js
</span><span style="color:#6272a4"></span>
<span style="color:#ff79c6">package</span> main

<span style="color:#ff79c6">import</span> (
    <span style="color:#f1fa8c">&#34;fmt&#34;</span>
    <span style="color:#f1fa8c">&#34;net/http&#34;</span>
)

<span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">setup</span>() {
    s <span style="color:#ff79c6">:=</span> <span style="color:#50fa7b">NewServer</span>()
    err <span style="color:#ff79c6">:=</span> http.<span style="color:#50fa7b">ListenAndServe</span>(<span style="color:#f1fa8c">&#34;:9001&#34;</span>, s.mux)
    <span style="color:#ff79c6">if</span> err <span style="color:#ff79c6">!=</span> <span style="color:#ff79c6">nil</span> {
        fmt.<span style="color:#50fa7b">Println</span>(<span style="color:#f1fa8c">&#34;error: &#34;</span>, err)
    }
}
</pre>


<p><code>setup_js</code></p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">package</span> main

<span style="color:#ff79c6">import</span> (
    <span style="color:#f1fa8c">&#34;bytes&#34;</span>
    <span style="color:#f1fa8c">&#34;fmt&#34;</span>
    <span style="color:#f1fa8c">&#34;io/ioutil&#34;</span>
    <span style="color:#f1fa8c">&#34;net/http&#34;</span>
    <span style="color:#f1fa8c">&#34;syscall/js&#34;</span>
)

<span style="color:#8be9fd;font-style:italic">type</span> ResponseWriter <span style="color:#8be9fd;font-style:italic">struct</span> {
    Body <span style="color:#ff79c6">*</span>bytes.Buffer
}

<span style="color:#8be9fd;font-style:italic">func</span> (r ResponseWriter) <span style="color:#50fa7b">Header</span>() http.Header {
    <span style="color:#ff79c6">return</span> <span style="color:#8be9fd;font-style:italic">make</span>(http.Header)
}

<span style="color:#8be9fd;font-style:italic">func</span> (r ResponseWriter) <span style="color:#50fa7b">Write</span>(buf []<span style="color:#8be9fd">byte</span>) (<span style="color:#8be9fd">int</span>, <span style="color:#8be9fd">error</span>) {
    <span style="color:#ff79c6">if</span> r.Body <span style="color:#ff79c6">!=</span> <span style="color:#ff79c6">nil</span> {
        r.Body.<span style="color:#50fa7b">Write</span>(buf)
    }
    <span style="color:#ff79c6">return</span> <span style="color:#8be9fd;font-style:italic">len</span>(buf), <span style="color:#ff79c6">nil</span>
}

<span style="color:#8be9fd;font-style:italic">func</span> (r ResponseWriter) <span style="color:#50fa7b">WriteHeader</span>(statusCode <span style="color:#8be9fd">int</span>) {}

<span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">createWriter</span>() ResponseWriter {
    <span style="color:#ff79c6">return</span> ResponseWriter{
        Body: <span style="color:#8be9fd;font-style:italic">new</span>(bytes.Buffer),
    }
}

<span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">parsePath</span>(this js.Value, args []js.Value) <span style="color:#8be9fd;font-style:italic">interface</span>{} {
    fmt.<span style="color:#50fa7b">Println</span>(<span style="color:#f1fa8c">&#34;args: &#34;</span>, args)
    server <span style="color:#ff79c6">:=</span> <span style="color:#50fa7b">NewServer</span>()
    path <span style="color:#ff79c6">:=</span> args[<span style="color:#bd93f9">0</span>].<span style="color:#50fa7b">String</span>()
    req, err <span style="color:#ff79c6">:=</span> http.<span style="color:#50fa7b">NewRequest</span>(http.MethodGet, path, <span style="color:#ff79c6">nil</span>)

    <span style="color:#ff79c6">if</span> err <span style="color:#ff79c6">!=</span> <span style="color:#ff79c6">nil</span> {
        fmt.<span style="color:#50fa7b">Println</span>(<span style="color:#f1fa8c">&#34;request error: &#34;</span>, err)
    }

    h, p <span style="color:#ff79c6">:=</span> server.mux.<span style="color:#50fa7b">Handler</span>(req)

    fmt.<span style="color:#50fa7b">Println</span>(<span style="color:#f1fa8c">&#34;pattern: &#34;</span>, p)

    w <span style="color:#ff79c6">:=</span> <span style="color:#50fa7b">createWriter</span>()

    h.<span style="color:#50fa7b">ServeHTTP</span>(w, req)

    b, err <span style="color:#ff79c6">:=</span> ioutil.<span style="color:#50fa7b">ReadAll</span>(w.Body)

    <span style="color:#ff79c6">if</span> err <span style="color:#ff79c6">!=</span> <span style="color:#ff79c6">nil</span> {
        fmt.<span style="color:#50fa7b">Println</span>(<span style="color:#f1fa8c">&#34;ioutil error: &#34;</span>, err)
    }

    <span style="color:#ff79c6">return</span> <span style="color:#8be9fd;font-style:italic">string</span>(b)
}

<span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">setup</span>() {
    js.<span style="color:#50fa7b">Global</span>().<span style="color:#50fa7b">Set</span>(<span style="color:#f1fa8c">&#34;parsePath&#34;</span>, js.<span style="color:#50fa7b">FuncOf</span>(parsePath))
}
</pre>


<h2>Conclusions</h2>

<p>The PoC worked! It's pretty slick to see a HTTP server running in WASM return back the correct data when a link is clicked. However, in my opinion, WASM continues to be a &quot;solution in search of a problem&quot;. Yes it's incredibly cool technology but so are the JS engines in Chrome, Firefox, and Safari. The sheer amount of money and engineering time being spent on making JS fast is a race no other technology can win at the moment.</p>

<p>That said, Go seems to have done decent work at providing the necessary pieces to make compiling to WASM not awful. </p>

<p>Honestly, the thing that surprised and impressed me the most was working with Web Workers. They are seriously useful and seem to &quot;just work&quot;.</p>

<h2>Links that helped me out along the way</h2>

<ul>
<li><a href="https://simonwillison.net/2022/May/4/datasette-lite/" >Simon Willison’s post about Datasette Lite</a></li>
<li><a href="https://blog.suborbital.dev/foundations-wasm-in-golang-is-fantastic" >Philippe Charrière's post</a></li>
<li><a href="https://itnext.io/webassemply-with-golang-by-scratch-e05ec5230558" >Roman Romadin's post</a></li>
</ul>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Hacking on Grafana with Web Assembly">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>New workstation</title>
          <link>https://adamsimpson.net/writing/new-workstation</link>

        <guid>https://adamsimpson.net/writing/new-workstation</guid>
        <pubDate>Mon, 2 May 2022 18:14:25 +0000</pubDate>

          <description>
            <![CDATA[ I detail my new workstation build featuring the Intel i5-12600k. ]]>
          </description>
          <content:encoded><![CDATA[
            <p><a href="/writing/goodbye-sparkbox" >New job</a> means time for a new workstation.</p>

<h2>Some history</h2>

<p>The first computer I ever purchased was the <a href="https://everymac.com/systems/apple/powerbook_g4/specs/powerbook_g4_1.5_12.html" >12&quot; Powerbook G4</a>. Since that Powerbook I've always had laptops as my main machines (desktop gaming PC not withstanding). Remote working the last few years has made me realize that the portability of a laptop is largely wasted since I only travel a handful of times a year and yet I live with the downsides of a laptop the rest of the time. So, last year I started thinking about a desktop machine for my primary workstation. A desktop is appealing for a handful of reasons:</p>

<ul>
<li>More powerful CPUs</li>
<li>More expansion capabilities</li>
<li>More durable</li>
</ul>

<h2>The options</h2>

<p>The <a href="https://www.apple.com/mac-studio/" >Mac Studio</a> was recently released to much fanfare and was really intriguing to me. However, when I started considering it I only had about a week to 10 days before my start date at <a href="https://grafana.com" >Grafana</a> and I couldn't wait the quoted 4-6 weeks delivery time for a Mac Studio with 32GB of RAM.</p>

<p>I was also pretty unwilling to leave my comfy <a href="https://nixos.org" >NixOS</a> install + <a href="https://i3wm.org/" >i3</a>. <a href="https://michael.stapelberg.ch/posts/2022-01-15-high-end-linux-pc/" >Michael Stapelberg's latest post</a> about his new workstation proved timely and convinced me to give the new Intel Alder Lake CPUs a shot.</p>

<p>Apple's M1 family of chips deliver incredible performance per watt but I wasn't as concered about the power usage given this was a desktop machine not a laptop. I was however focused on at least matching the M1 chips in single-threaded performance since a good chunk of my development work (Node, build tools, etc) are still single-threaded. I ended up with the Intel i5-12600k and I really couldn't be happier. Here's the full parts list:</p>

<table style="margin-bottom: 1rem;">
<thead>
<tr>
<th style="text-align: left;">Part</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://www.amazon.com/Intel-i5-12600K-Desktop-Processor-Unlocked/dp/B09FX4D72T" rel="nofollow">i5-12600k</a></td>
<td>$278</td>
</tr>
<tr>
<td><a href="https://www.sliger.com/products/cases/cerberus/" rel="nofollow">Sliger Cerberus case</a></td>
<td>$285</td>
</tr>
<tr>
<td><a href="https://www.amazon.com/Noctua-NF-A14-PWM-Premium-Cooling/dp/B00CP6QLY6" rel="nofollow">140mm Noctua NF-A14 PWM</a></td>
<td>$21</td>
</tr>
<tr>
<td><a href="https://www.amazon.com/Noctua-NH-C14S-Premium-Cooler-NF-A14/dp/B00XUV3JTK" rel="nofollow">Noctua NH-C14S</a></td>
<td>$85</td>
</tr>
<tr>
<td><a href="https://www.amazon.com/Sabrent-Internal-Extreme-Performance-SB-ROCKET-NVMe4-1TB/dp/B07TLYWMYW" rel="nofollow">Sabrent 1TB Rocket NVMe</a></td>
<td>$130</td>
</tr>
<tr>
<td><a href="https://www.amazon.com/CORSAIR-SF600-Modular-Supply-Certified/dp/B01CGI5M24" rel="nofollow">Corsair SF600</a></td>
<td>$130</td>
</tr>
<tr>
<td><a href="https://www.amazon.com/ASUS-ROG-Z690-G-motherboard-Thunderbolt/dp/B09JRVXRJC" rel="nofollow">ASUS ROG Strix Z690-G</a></td>
<td>$350</td>
</tr>
<tr>
<td><a href="https://www.amazon.com/G-Skill-Trident-PC5-48000-CL36-36-36-96-F5-6000J3636F16GA2-TZ5K/dp/B09PTS2NMZ/" rel="nofollow">G.SKILL Trident Z5 Series 32GB DDR5</a></td>
<td>$330</td>
</tr>
</tbody>
</table>

<h2>XMP issues</h2>

<p>I ran into the same memory XMP issues that Michael mentions in his post so I disabled the XMP profile and the system passed the &quot;<a href="https://blog.codinghorror.com/is-your-computer-stable/" >Coding Horror burn in tests</a>&quot; with flying colors.</p>

<h2>Cooling</h2>

<p>I mounted the 140mm fan to the bottom of the case as intake and the CPU cooler is of course positioned as intake as well. Hot air rises out the top of the case quite well. During the prime95 torture test the CPU never got over 78°C and I couldn't ever hear either fan. I run both fans in the &quot;silent profile&quot; in the BIOS and I use <a href="https://noctua.at/en/na-src7" >Noctua's adapters</a> to lower the voltage even more. Now the only fan I could hear during max load was the PSU fan which doesn't spin at all under low to medium loads but under high load it kicks on. Day to day it's hardly on so the system is dead quiet most of the time.</p>

<h2>Case</h2>

<p>I absolutely love the Cerberus case. It's Mini-ATX but still super compact and fits on my desk quite well. All the panels are solid metal and the way all the panels pop off is really really nice. I opted for the handle mount on the top and the internal PSU moutning.</p>

<h2>Linux</h2>

<p>NixOS <a href="https://github.com/asimpson/dotfiles/blob/master/nixos/fin/configuration.nix" >installed just fine</a>. I'm runing the 5.17 kernel because Alder Lake needs a newer kernel for it's graphics and CPU scheduler (coming soon?). I have WiFi and Bluetooh disabled in the BIOS since everything is hard-wired to the machine.</p>

<h2>Verdict</h2>

<p>This build has proven quite comfortable over the few weeks I've used it. I love that I have 2 free RAM slots if I ever feel the need for more RAM. I also love that I have 3 remaining Nvme slots on the motherboard for additional solid state storage in the future.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: New workstation">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>👋 Sparkbox</title>
          <link>https://adamsimpson.net/writing/goodbye-sparkbox</link>

        <guid>https://adamsimpson.net/writing/goodbye-sparkbox</guid>
        <pubDate>Fri, 1 Apr 2022 18:20:31 +0000</pubDate>

          <description>
            <![CDATA[ I can’t believe I’m writing this but after 9 and a half years today is my last day at Sparkbox. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I can’t believe I’m writing this but after 9 and a half years today is my last day at <a href="https://sparkbox.com" >Sparkbox</a>.</p>

<p>Now, I know it can be problematic to think about work like your (extended) family but when you work at the same place through your twenties and early thirties, have 3 different apartments, buy a house, and have two kids it’s impossible not to view that place differently. I can confidently say Sparkbox changed my life. The team there will always have a special place in my heart.</p>

<p><em>deep breath</em></p>

<p>So where to? Well, I’m super stoked to be joining <a href="https://grafana.com" >Grafana</a> as a Senior Software Engineer on their Cloud Data team! I’m looking forward to writing more Go, solving new problems, and learning from the stellar folks there.</p>

<p>Here we go…</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: 👋 Sparkbox">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Thirty five</title>
          <link>https://adamsimpson.net/writing/thirty-five</link>

        <guid>https://adamsimpson.net/writing/thirty-five</guid>
        <pubDate>Thu, 3 Mar 2022 15:28:44 +0000</pubDate>

          <description>
            <![CDATA[ It's been 5 years since I wrote 'Thirty'. So now I have to come up with 35 things as I turned 35 yesterday. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Well crap.</p>

<p>It's been 5 years since I wrote <a href="/writing/thirty" >&quot;Thirty&quot;</a>. So now I have to come up with 35 things as I turned 35 yesterday. If anything from Thirty is grossly wrong or really interesting I'll update it at the same number eh?</p>

<p>Let's go...</p>

<ol>
<li>I still don't have it figured out, but this isn't such a shock anymore.</li>
<li>Building a house is <em>more</em> scary.</li>
<li>Minivans are <em>awesome</em>.</li>
<li>Expecting a third kid is not nearly as scary as expecting the first.</li>
<li>COVID sucked.</li>
<li>Modern medicine is pretty cool actually.</li>
<li>More stuff hurts, still just as healthy.</li>
<li>Dishwashers aren't really as scary to repair as they seem (but that doesn't mean you won't lose your mind fixing one).</li>
<li>The feeling you get as a parent when your kid gets hurt is impossible to describe.</li>
<li>Being knocked out from a crazy car accident is also no fun.</li>
<li>Carseats are magic.</li>
<li>I've accepted that the music I liked in 2010 is going to be the music I'll like forever.</li>
<li>Thanks to the internet there is an endless stream of new music that is at home with music from 2010 or even 2000 (Underoath just released a new album for crying out loud).</li>
<li>Open source software is incredible.</li>
<li>The thrill from in-progress software working for the first time will never get old for me.</li>
<li>Feedback loops are important in every area of life not just software.</li>
<li>The year of Linux on the desktop is a moving target.</li>
<li>RSS will never die.</li>
<li>Mechanical keyboards are a refreshing change and I'm not sure why.</li>
<li>The Aeropress is still incredible.</li>
<li>Computers were a mistake.</li>
<li>Computers are a miracle.</li>
<li>The Three-Body Problem trilogy continues to knock around in my brain months after finishing it.</li>
<li>Watching your child accomplish something for the first time that they've been working on is a feeling unlike any other.</li>
<li>I've realized I learn best by doing, I need to get better at accounting for the bumps along the way.</li>
<li>I write things down to remember them later not to look them up later which means most note systems are not worth the trouble for me.</li>
<li>Life will be shallow if you only hang out with people like you.</li>
<li>Anything is possible on an infinite timescale the trick is figuring out what do with finite time.</li>
<li>RIP Rdio.</li>
<li>Never pass on an opportunity to twirl your kids around when they're small. They get big fast.</li>
<li>Hanlon's razor explains most of social media.</li>
<li>If you work at a desk all day you owe it to yourself to remove as much Bluetooth from that setup as possible.</li>
<li>None of your peers has it all figured out. Ask them &quot;dumb&quot; questions.</li>
<li>Properly evaluating risks when your kids are involved is <em>hard</em>.</li>
<li>Keep a sweatshirt handy by your bed when your kids are young, getting up at 2am in the winter is <em>cold</em>.</li>
</ol>

<p>❤️ you Christi</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Thirty five">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Windows 11 as KVM guest</title>
          <link>https://adamsimpson.net/writing/windows-11-as-kvm-guest</link>

        <guid>https://adamsimpson.net/writing/windows-11-as-kvm-guest</guid>
        <pubDate>Mon, 28 Feb 2022 18:39:37 +0000</pubDate>

          <description>
            <![CDATA[ How I work with Windows 11 as a KVM guest on a NixOS host using virt-manager. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Windows 11 famously has new, stricter <a href="https://www.microsoft.com/en-us/windows/windows-11-specifications" >requirements for installation</a>; a TPM device and Secure Boot. Here's how I satisfied those requirements with Windows 11 as a KVM guest with NixOS as the host. The following is pulled from my <a href="https://github.com/asimpson/dotfiles/commit/ab08fd88a5617d9199f78726c1f22f32b8fc85d0" >NixOS <code>configuration.nix</code></a>:</p><pre style="color:#f8f8f2;background-color:#282a36">libvirtd<span style="color:#ff79c6">.</span>qemu = {
  package <span style="color:#ff79c6">=</span> pkgs<span style="color:#ff79c6">.</span>qemu_kvm;
  runAsRoot <span style="color:#ff79c6">=</span> true;
  swtpm<span style="color:#ff79c6">.</span>enable <span style="color:#ff79c6">=</span> true;
  ovmf <span style="color:#ff79c6">=</span> {
    enable <span style="color:#ff79c6">=</span> true;
    package <span style="color:#ff79c6">=</span> (pkgs<span style="color:#ff79c6">.</span>OVMFFull<span style="color:#ff79c6">.</span>override {
      secureBoot <span style="color:#ff79c6">=</span> true;
      tpmSupport <span style="color:#ff79c6">=</span> true;
    });
  };
};</pre>


<p>The most important bit is the <code>pkgs.OVMFFull.override</code> section where you must specify <code>tpmSupport</code> and <code>secureBoot</code> as <code>true</code>.</p>

<p>In <a href="https://virt-manager.org/" >virt-manager</a> you'll need to add &quot;new hardware&quot; and select TPM v2.0. Here's the relevant XML from my config:</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">&lt;tpm</span> <span style="color:#50fa7b">model=</span><span style="color:#f1fa8c">&#34;tpm-crb&#34;</span><span style="color:#ff79c6">&gt;</span>
  <span style="color:#ff79c6">&lt;backend</span> <span style="color:#50fa7b">type=</span><span style="color:#f1fa8c">&#34;emulator&#34;</span> <span style="color:#50fa7b">version=</span><span style="color:#f1fa8c">&#34;2.0&#34;</span><span style="color:#ff79c6">/&gt;</span>
<span style="color:#ff79c6">&lt;/tpm&gt;</span></pre>


<p>With the above settings you should be able to go through the Windows 11 installer and get the machine up and running as a KVM guest.</p>

<h2>Stretch goal: nested virtualization</h2>

<p>If you want to use Docker or WSL 2 inside KVM you'll need to enable &quot;nested virtualization&quot; in virt-manager. I couldn't figure this out until I found <a href="https://superuser.com/a/1589286" >this great answer on superuser</a>.</p>

<p>My original CPU config XML looked like this:</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">&lt;cpu</span> <span style="color:#50fa7b">mode=</span><span style="color:#f1fa8c">&#34;host-model&#34;</span> <span style="color:#50fa7b">check=</span><span style="color:#f1fa8c">&#34;partial&#34;</span><span style="color:#ff79c6">&gt;</span>
  <span style="color:#ff79c6">&lt;topology</span> <span style="color:#50fa7b">sockets=</span><span style="color:#f1fa8c">&#34;1&#34;</span> <span style="color:#50fa7b">dies=</span><span style="color:#f1fa8c">&#34;1&#34;</span> <span style="color:#50fa7b">cores=</span><span style="color:#f1fa8c">&#34;2&#34;</span> <span style="color:#50fa7b">threads=</span><span style="color:#f1fa8c">&#34;4&#34;</span><span style="color:#ff79c6">/&gt;</span>
<span style="color:#ff79c6">&lt;/cpu&gt;</span></pre>


<p>The new XML looks like this:</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">&lt;cpu</span> <span style="color:#50fa7b">mode=</span><span style="color:#f1fa8c">&#34;custom&#34;</span> <span style="color:#50fa7b">match=</span><span style="color:#f1fa8c">&#34;exact&#34;</span> <span style="color:#50fa7b">check=</span><span style="color:#f1fa8c">&#34;partial&#34;</span><span style="color:#ff79c6">&gt;</span>
  <span style="color:#ff79c6">&lt;model</span> <span style="color:#50fa7b">fallback=</span><span style="color:#f1fa8c">&#34;allow&#34;</span><span style="color:#ff79c6">&gt;</span>Skylake-Client-noTSX-IBRS<span style="color:#ff79c6">&lt;/model&gt;</span>
  <span style="color:#ff79c6">&lt;topology</span> <span style="color:#50fa7b">sockets=</span><span style="color:#f1fa8c">&#34;1&#34;</span> <span style="color:#50fa7b">dies=</span><span style="color:#f1fa8c">&#34;1&#34;</span> <span style="color:#50fa7b">cores=</span><span style="color:#f1fa8c">&#34;2&#34;</span> <span style="color:#50fa7b">threads=</span><span style="color:#f1fa8c">&#34;4&#34;</span><span style="color:#ff79c6">/&gt;</span>
  <span style="color:#ff79c6">&lt;feature</span> <span style="color:#50fa7b">policy=</span><span style="color:#f1fa8c">&#34;disable&#34;</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;hypervisor&#34;</span><span style="color:#ff79c6">/&gt;</span>
  <span style="color:#ff79c6">&lt;feature</span> <span style="color:#50fa7b">policy=</span><span style="color:#f1fa8c">&#34;require&#34;</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;vmx&#34;</span><span style="color:#ff79c6">/&gt;</span>
<span style="color:#ff79c6">&lt;/cpu&gt;</span></pre>


<p>With this applied I could install WSL2 <em>and</em> get Docker Desktop for Windows installed and running.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Windows 11 as KVM guest">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>A few POSIX shell tips</title>
          <link>https://adamsimpson.net/writing/a-few-posix-shell-tips</link>

        <guid>https://adamsimpson.net/writing/a-few-posix-shell-tips</guid>
        <pubDate>Mon, 19 Jul 2021 18:53:16 +0000</pubDate>

          <description>
            <![CDATA[ I wrote down a few of my most used POSIX shell commands and features. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I was recently working on the <a href="https://github.com/sparkbox/sb/commit/f9d2a0bc5339c4777e73432d9a8208b092a2e9ac" >release build script</a> for <a href="https://github.com/sparkbox/sb" ><code>sb</code></a> and decided I should document a few things I find myself looking up just about every time. One of the advantages of the POSIX shell (not bash, zsh, but Bourne shell, usually <code>/bin/sh</code> on most unix-y systems) is that it has <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html" >a specification</a> however I'm usually frustrated trying to find the information I need.</p>

<p><aside class="pa2 bg-light-gray">
<code>sb</code> is a tool I'm working on at <a href="https://sparkbox.com" >Sparkbox</a> to automate SSH authentication via SSH Certificates and Slack's <a href="https://api.slack.com/docs/sign-in-with-slack" >&quot;Sign on with Slack&quot;</a> feature.</p>

<p>You can check it out here: <a href="https://github.com/sparkbox/sb" >https://github.com/sparkbox/sb</a>
</aside></p>

<p>I prefer the POSIX shell because it's <em>the default</em> on most unix-y system. If I have to be sure if the shell is installed on the target system (like <code>bash</code> or <code>zsh</code>) I'd rather just use a higher-level scripting language like node or ruby where the same requirement exists.</p>

<h2>Arrays</h2>

<p>Psych! There aren't any arrays. Bash has arrays but POSIX does not. If I need an array structure I can use a space-separated string (or another delimiter if you've set <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_03" ><code>$IFS</code></a>) as the data structure, e.g. <code>PLATFORMS=&quot;arm64-darwin amd64-linux amd64-darwin&quot;</code>. Now I can loop over the variable using a for loop:</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#8be9fd;font-style:italic">PLATFORMS</span><span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#34;arm64-darwin amd64-linux amd64-darwin&#34;</span>

<span style="color:#ff79c6">for</span> PLATFORM in <span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">PLATFORMS</span><span style="color:#f1fa8c">}</span>; <span style="color:#ff79c6">do</span>
  <span style="color:#6272a4"># GOOS=FOO GOARCH=BAR go build ...</span>
<span style="color:#ff79c6">done</span></pre>


<p>Or I can take the lack of arrays as a signal I should stop writing a shell script and reach for a language that has the concept of arrays to solve my problem.</p>

<h2>Conditional &quot;flags&quot;</h2>

<p>I often forget the various flags one can use in a conditional (aka test/if) statement. Here's the <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html" >documentation</a> and here are a few of my favorites:</p>

<ul>
<li><code>-n</code> tests if the string is non-zero, e.g.</li>
</ul><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#ff79c6">if</span> <span style="color:#ff79c6">[</span> -n <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">UPLOAD_URL</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#ff79c6">]</span>; <span style="color:#ff79c6">then</span>
    upload_file <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">PLATFORM</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span>
<span style="color:#ff79c6">fi</span></pre>


<ul>
<li><code>-z</code> the opposite of <code>-n</code>.</li>
<li><code>-f</code> tests if the pathname resolves to a file.</li>
</ul>

<h2>Functions and args</h2>

<ul>
<li>Functions must be declared before they are invoked.</li>
<li>Functions look like:</li>
</ul><pre style="color:#f8f8f2;background-color:#282a36">someFunc<span style="color:#ff79c6">()</span> <span style="color:#ff79c6">{</span>
  <span style="color:#8be9fd;font-style:italic">echo</span> <span style="color:#f1fa8c">&#34;a func!&#34;</span>
<span style="color:#ff79c6">}</span></pre>


<ul>
<li>There is no syntax for functions accepting args instead they are mapped to <code>$n</code>. <code>$@</code> is all the args.</li>
</ul><pre style="color:#f8f8f2;background-color:#282a36">upload_file<span style="color:#ff79c6">()</span> <span style="color:#ff79c6">{</span>
    <span style="color:#8be9fd;font-style:italic">NAME</span><span style="color:#ff79c6">=</span><span style="color:#8be9fd;font-style:italic">$1</span>

    zip <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">NAME</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">.zip&#34;</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">NAME</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span>
    curl -H <span style="color:#f1fa8c">&#34;Accept: application/vnd.github.v3+json&#34;</span> <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>         -H <span style="color:#f1fa8c">&#34;Authorization: Bearer </span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">GITHUB_TOKEN</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span> <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>         -H <span style="color:#f1fa8c">&#34;Content-Type: application/zip&#34;</span> <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>         --data-binary <span style="color:#f1fa8c">&#34;@</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">NAME</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">.zip&#34;</span> <span style="color:#f1fa8c">\
</span><span style="color:#f1fa8c"></span>         <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">UPLOAD_URL</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">?name=</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">NAME</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">.zip&#34;</span>
<span style="color:#ff79c6">}</span>

upload_file <span style="color:#f1fa8c">&#34;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">PLATFORM</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span></pre>


<h2>Use shellcheck</h2>

<p>This is just preference but I really love using <a href="https://www.shellcheck.net/" ><code>shellcheck</code></a> to avoid any footguns and enforce a consistent style with my shell scripts. I typically invoke it like this: <code>shellcheck -o all script-name.sh</code>.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: A few POSIX shell tips">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Recently</title>
          <link>https://adamsimpson.net/writing/recently-16</link>

        <guid>https://adamsimpson.net/writing/recently-16</guid>
        <pubDate>Fri, 23 Apr 2021 15:37:19 +0000</pubDate>

          <description>
            <![CDATA[ A random assortment of links and miscellaneous updates on things. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I'm stealing the title format of this post from <a href="https://macwright.com/" >Tom MacWright's</a> Recently posts.</p>

<p>Here's a random assortment of links and miscellaneous updates on things.</p>

<h2>autofs</h2>

<p><a href="https://help.ubuntu.com/community/Autofs" >autofs</a> is a cool utility that watches a specific directory path and when a program tries to read or write to that path it mounts a filesystem at that location. I'm using this to auto mount my NAS via SMB for <a href="https://www.musicpd.org" >mpd</a>. With autofs in place I can run mpd locally (in a <a href="https://www.musicpd.org/doc/html/user.html#satellite-setup" >&quot;satellite setup&quot;</a>) and have its <code>music_directory</code> point to a path managed by autofs.</p>

<p>One thing that was helpful getting the configuration right was testing autofs by running <code>automount -f -v</code> directly which puts it in the foreground and gives verbose output.</p>

<p>The two files I configured were <code>auto.master.d/foo.autofs</code> and <code>auto.foo</code>.</p>

<ul>
<li><strong>foo.autofs</strong> contains one line: <code>/- /etc/auto.foo</code></li>
<li><strong>auto.foo</strong> contains one line as well: <code>/foo -fstype=cifs,rw,credentials=/home/me/.foo-creds ://NAS.IP/foo</code></li>
</ul>

<h2>mailpreview updates</h2>

<p><a href="https://git.sr.ht/~asimpson/mailpreview-cli" >mailpreview-cli</a> is a little program I use multiple times a day to quickly see my unread email without moving from what I'm currently working on and without touching my mouse. I recently noticed it wasn't grabbing the body of a specific type of email. In the process of fixing that I also added proper unit tests for every format I currently parse through. Yay faster feedback loops!</p>

<h2>ffmpeg</h2>

<p>I've been a fan of OBS for awhile now. I was recently doing a quick screen recording of my browser window and the browser window wasn't full-screen so there were black bars around the edges of the recording. I didn't love that but it's time to touch the &quot;ffmpeg exists and is awesome&quot; sign again.</p>

<p><a href="https://superuser.com/a/810524" >This superuser post</a> has the answer which consists of two steps:</p>

<ol>
<li>Get the crop parameters of the video from ffmpeg. ffmpeg will detect the black borders and report back the actual content coordinates.
<code>ffmpeg.exe -i '.\some-video.mkv' -vf cropdetect -f null -</code></li>
<li>Re-encode and crop using the crop parameters to trim the borders.
<code>ffmpeg.exe -i '.\some-video.mkv' -vf crop=624:704:332:10 -c:a copy output.mp4</code></li>
<li>Enjoy your pristine video.</li>
</ol>

<h2>Links I've enjoyed</h2>

<ul>
<li><a href="https://fly.io/blog/docker-without-docker/" >Docker without docker</a>
Really anything on the fly.io blog is <em>gold</em>.</li>
<li><a href="https://www.youtube.com/watch?v=RqubKSF3wig" >David Crawshaw: SQLite and Go</a>(Talk)</li>
<li><a href="https://blog.benjojo.co.uk/post/dns-filesystem-true-cloud-storage-dnsfs" >DNSFS</a></li>
<li><a href="https://stevelosh.com/blog/2021/03/small-common-lisp-cli-programs/" >Writing Small CLI Programs in Common Lisp</a></li>
<li><a href="https://www.wired.com/story/my-dream-of-the-great-unbundling/" >My Dream of the Great Unbundling</a></li>
</ul>

<p>Fin</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Recently">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>A firewall in 8 lines</title>
          <link>https://adamsimpson.net/writing/8-line-firewall</link>

        <guid>https://adamsimpson.net/writing/8-line-firewall</guid>
        <pubDate>Wed, 31 Mar 2021 15:18:24 +0000</pubDate>

          <description>
            <![CDATA[ You only need about 8 lines in iptables to have a great home firewall. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Since 2017 my home router has been a <a href="https://ark.intel.com/content/www/us/en/ark/products/95597/intel-celeron-processor-j3355-2m-cache-up-to-2-5-ghz.html" >plain x86 box</a> running Alpine Linux. I never really think about it anymore. Recently, I was helping a relative set up their own Linux-based router and took the time to appreciate how little config is needed to setup a serviceable home router firewall using <code>iptables</code>. You can see my base rule-sets (port forwarding omitted) below:</p><pre style="color:#f8f8f2;background-color:#282a36">-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -i eth0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o eth1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT</pre>


<p>The benefit of running a x86 box with Alpine (or any version of Linux) is that the box will receive a steady stream of security updates and upgraded kernels as Alpine Linux releases new versions. This is a much better situation to be in than relying on OS and security updates from a vendor like TPLink or Linksys.</p>

<p>If you have ideas for how to improve the config I listed above or want to chat more about home network stuff, send an email to my <a href="https://lists.sr.ht/~asimpson/public-inbox" >public-inbox</a>.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: A firewall in 8 lines">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>How to use Siji font on polybar</title>
          <link>https://www.reddit.com/r/Polybar/comments/ht0jnr/guide_how_to_use_the_siji_font_on_polybar/</link>

        <guid>https://adamsimpson.net/writing/how-to-use-siji-font-on-polybar</guid>
        <pubDate>Fri, 6 Nov 2020 16:18:47 +0000</pubDate>


          <content:encoded><![CDATA[
            <p>Nice guide on Reddit about how to use the <a href="https://github.com/stark/siji" >Siji font</a> with polybar.</p>

<blockquote>
<p>[..] install the siji font, and then run <code>&quot;view.sh&quot;</code> in the terminal. If you get an error, try to launch the <code>install.sh</code> again. You'll get a list of all the glyphs available, select the one you want [..] to use and then look where it says &quot;Character 0x00e002&quot; or something like that.</p>
</blockquote>

<p>Of note is that you'll end up with weird looking glyphs but siji will interpret it correctly. This is because Siji maps character codes to different icons than other fonts do.</p>

            <a title="permalink for How to use Siji font on polybar" href="https://adamsimpson.net/writing/how-to-use-siji-font-on-polybar">🔗</a>
            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: How to use Siji font on polybar">Discuss further in my public inbox</a>
          ]]></content:encoded>
      </item>
      <item>
        <title>On Polybar bitmap fonts and Ubuntu</title>
          <link>https://adamsimpson.net/writing/polybar-fonts-and-ubuntu</link>

        <guid>https://adamsimpson.net/writing/polybar-fonts-and-ubuntu</guid>
        <pubDate>Fri, 6 Nov 2020 15:15:09 +0000</pubDate>

          <description>
            <![CDATA[ Enable bitmap fonts on Ubuntu for an optimal polybar experience. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I use <a href="https://polybar.github.io/" >polybar</a> as my status bar in i3 and it's been going great for months now. However, I was recently grepping through the <code>syslog</code> trying to figure out why a browser crash happened and the log was filled with polybar spam that looked like this: <code>polybar|warn:  Dropping unmatched character</code>. So I started picking at solving the warning.</p>

<p>Turns out there's a <a href="https://github.com/polybar/polybar/issues/392#issuecomment-310778138" >Github issue</a> that contains the solution which is to enable bitmap fonts which I'll paste here for posterity:</p><pre style="color:#f8f8f2;background-color:#282a36"><span style="color:#6272a4"># &#34;Un-disable&#34; bitmap fonts</span>
sudo rm /etc/fonts/conf.d/70-no-bitmaps.conf
<span style="color:#6272a4"># Clear the font cache</span>
sudo fc-cache -f -v</pre>


<p>Apparently Ubuntu disables bitmap fonts by default but polybar uses bitmap fonts for icon rendering. I also needed to install the <a href="https://github.com/stark/siji" >sijj icon font family</a> which was painless.</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: On Polybar bitmap fonts and Ubuntu">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Recently</title>
          <link>https://adamsimpson.net/writing/recently-44</link>

        <guid>https://adamsimpson.net/writing/recently-44</guid>
        <pubDate>Wed, 28 Oct 2020 03:30:46 +0000</pubDate>

          <description>
            <![CDATA[ I've written a few small tools over the last couple months and I figured it's time I post about them. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>I've published a few new projects in the last couple of months and I'm behind on announcing them, so I bundled them up together into this post. I'm stealing the title format of this post from <a href="https://macwright.com/" >Tom MacWright's</a> Recently posts.</p>

<p>One thing to note is that the source code for all these projects is stored on <a href="https://sourcehut.org/" >sourcehut</a>. Sourcehut (or sr.ht) bills itself as &quot;the hacker's forge&quot;. I highly recommend checking it out. It's also where I host <a href="https://lists.sr.ht/~asimpson/public-inbox" >my public inbox</a>.</p>

<h2>hover-dns</h2>

<p>Now that I have fiber internet at the house I've been hosting one-off services and apps on my own hardware at the house. This is great, however my residential connection is a typical dynamic IP not a static one. Instead of using a service like <a href="https://account.dyn.com/" >DynamicDNS</a> I decided to write some Rust (shocker) and leverage the &quot;unofficial&quot; Hover API. The result is: <a href="https://git.sr.ht/~asimpson/hover-dns" >hover-dns</a>.</p>

<p>I have <code>hover-dns</code> running in a crontab for a few different domains to keep my domains pointed to the correct IP for my house. While I'm a little uncomfortable with how similar <code>npm</code> and <code>cargo</code> can feel, the <a href="https://docs.rs/trust-dns-resolver" ><code>trust-dns</code></a> package is <em>excellent</em>. I was able to quickly read the source code to understand how to setup a <code>Resolver</code> for <a href="https://www.opendns.com/" >opendns</a>. Also impressive is that <code>hover-dns ip</code> beats out <code>dig</code> in returning your public IP. I didn't expect that!</p>

<h2>podcastfilter</h2>

<p>Speaking of hosting things at home, <a href="https://podcastfilter.com" >podcastfilter.com</a> is one of those things. <a href="https://git.sr.ht/~asimpson/podcast-filter" >podcast-filter is a small Go project</a> that allows you to filter a podcast feed by each episode's description and return a feed of just those episodes that match.</p>

<h2>mailpreview</h2>

<p>The recent project I use the most day-to-day is <a href="https://git.sr.ht/~asimpson/mailpreview-cli" >mailpreview-cli</a>. <code>mailpreview-cli</code> is very straight-forward, it accepts a Mail message and returns either the plain text version or the html version of that message. The reason I don't just pull the Mail message directly is because a Mail message can contain several versions of the message in different encodings (start here if you're curious: <a href="https://tools.ietf.org/html/rfc822" >RFC-822</a>). Instead of writing my own parser I grabbed the excellent <a href="https://docs.rs/mailparse/" >mailparse crate</a> and wrapped the behavior I wanted around it. On it's own <code>mailpreview-cli</code> isn't super fancy but I trigger it from <code>rofi</code> via a <a href="https://github.com/asimpson/dotfiles/blob/master/linux/mail-preview" >shell script</a> which allows me to browse (and then view) all my unread emails right from <code>rofi</code>. Shameless plug: I wrote a short post about <a href="https://adamsimpson.net/writing/getting-started-with-rofi" >getting started with <code>rofi</code></a> if you're unfamiliar. <code>mailpreview-cli</code> could be used with <a href="https://www.alfredapp.com/" >Alfred</a> if you're on a Mac to accomplish the same thing as I'm doing with a shell script and <code>rofi</code>.</p>

<p>Fin</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Recently">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Four ways to approach Hacktoberfest 2020</title>
          <link>https://adamsimpson.net/writing/four-ways-to-approach-hacktoberfest-2020</link>

        <guid>https://adamsimpson.net/writing/four-ways-to-approach-hacktoberfest-2020</guid>
        <pubDate>Thu, 1 Oct 2020 14:26:38 +0000</pubDate>

          <description>
            <![CDATA[ I came up with a four different approaches for Hacktoberfest this year: The Dependency Scrub, Polygot Achievement, Unknown Lands, and the Bug Doctor. ]]>
          </description>
          <content:encoded><![CDATA[
            <p>Hacktoberfest 2020 is here! I can't believe 2020 is winding down, good riddance!</p>

<p>I've been talking about Hacktoberfest with my co-worker <a href="https://www.bryanbraun.com/" >Bryan</a> and I thought of four different approaches to Hacktoberfest this year that I wanted to share.</p>

<p><aside class="pa2 bg-light-gray">If you stop and think about it Hacktoberfest is a weird event: tying an incentive to the number of Pull-Requests a person submits probably (I could be wrong on this but I doubt it) produces a flood of low-effort and low-quality pull-requests across the open source landscape. However, the event is here to stay so what are some ways developers who care about quality and open-source can use this extra attention to make things better not worse?</aside></p>

<h2>Dependency scrub</h2>

<p>This is probably common everywhere but the Javascript/web communities are filled with npm packages. It's packages all the way down. I think it would be interesting to approach this month looking for ways to remove third-party code from projects you love and use frequently.</p>

<h2>Polygot Achievement</h2>

<p>Try to submit four pull requests in four different languages. As <a href="https://drewdevault.com/2018/03/17/Hack-everything-without-fear.html" >Drew DeVault writes</a>: Hack everything without fear!</p>

<h2>Unknown lands</h2>

<p>Similar to the previous one it could be fun to submit PRs against a project you've never been in before that's in a language you don't know. This could be anything from diving into Wordpress core, to working on some C for some Linux utilities, or even submitting PRs to open source Mac/iOS applications.</p>

<h2>Bug doctor</h2>

<p>Go into a project and find the oldest issues and try to resolve them via PR. This is inspired by <a href="https://schneems.com/2020/09/22/triage-with-me-11-issues-2-prs-in-15-hours/" >Richard Schneeman's video</a> and post where he runs through 11 issues and 2 PRs in a hour and a half.</p>

<p>How are you approaching Hacktoberfest this year? My <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re:%20Four%20ways%20to%20approach%20Hacktoberfest%202020">public inbox</a> is open, let me know!</p>

            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Four ways to approach Hacktoberfest 2020">Discuss further in my public inbox</a>
          ]]></content:encoded>

      </item>
      <item>
        <title>Small tech</title>
          <link>https://scattered-thoughts.net/writing/small-tech/</link>

        <guid>https://adamsimpson.net/writing/small-tech</guid>
        <pubDate>Fri, 25 Sep 2020 19:53:06 +0000</pubDate>


          <content:encoded><![CDATA[
            <p><a href="https://scattered-thoughts.net/" >Jamie Brandon</a> has a nice post about &quot;small tech&quot;: tech that isn't backed by a big corporation like Microsoft or Apple but still has an out-sized impact. I love the post and I thought I would add a few additional products to the list.</p>

<ul>
<li><p><a href="https://curl.haxx.se/" >curl</a> is open-source and has thousands of contributors but is still primarily designed and managed by <a href="https://daniel.haxx.se/" >@bagder (Daniel Stenberg)</a>. If you ever do anything with http for any kind of development mastering <code>curl</code> is worth the time investment.</p></li>
<li><p><a href="https://git-scm.com/" >git</a> is <em>the</em> premier version control system on the planet. It started out as a side-project to manage Linux kernel development.</p></li>
<li><p><a href="https://www.alpinelinux.org/" >Alpine Linux</a> is a Linux distribution that is maintained by a small group of folks and yet is the first choice for most folks when creating Docker images.</p></li>
<li><p><a href="https://sr.ht/" >sr.ht</a> does not have the type of scale or impact that the others items on this list have <em>but</em> I think it could some day. sr.ht is version control host, issue tracker, mailing list tool, and CI toolbox. It competes directly with Github, Gitlab, and Bitbucket. However, sr.ht is run by one person—<a href="https://drewdevault.com/" >Drew DeVault</a>—and is 100% open-source.</p></li>
</ul>

            <a title="permalink for Small tech" href="https://adamsimpson.net/writing/small-tech">🔗</a>
            <a href="mailto:~asimpson/public-inbox@lists.sr.ht?Subject=Re: Small tech">Discuss further in my public inbox</a>
          ]]></content:encoded>
      </item>
  </channel>
</rss>