<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title></title>
    <link rel="self" type="application/atom+xml" href="https://blobcode.net/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blobcode.net"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-06T00:00:00+00:00</updated>
    <id>https://blobcode.net/atom.xml</id>
    <entry xml:lang="en">
        <title>moving to github pages</title>
        <published>2026-03-06T00:00:00+00:00</published>
        <updated>2026-03-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/moving-to-github-pages/"/>
        <id>https://blobcode.net/blog/moving-to-github-pages/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/moving-to-github-pages/">&lt;p&gt;Once again, the optimization gods have taken their hold on me. The site is now running on github pages, with a nix-based build system running on top of github actions.
It turns out that turning your website into a nix package lets you cache the build system! &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;DeterminateSystems&#x2F;magic-nix-cache&quot;&gt;Magic Nix Cache&lt;&#x2F;a&gt; is extremely cool, and
means that deploys are pretty much instant.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A Reading List</title>
        <published>2025-10-20T00:00:00+00:00</published>
        <updated>2025-10-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/reading-list/"/>
        <id>https://blobcode.net/blog/reading-list/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/reading-list/">&lt;p&gt;Here I preset my reading lists (broadly split among a couple categories), mostly to provide as reference for myself &#x2F; others. Also includes some notable papers &#x2F; short stories.&lt;&#x2F;p&gt;
&lt;p&gt;Entries marked with (*) are highly recommended.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;programming-programming-languages&quot;&gt;Programming, Programming Languages&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Iverson (1972), &lt;em&gt;Algebra: An Algorithmic Treatment&lt;&#x2F;em&gt; - this covers some the ideas behind APL and similar array languages.&lt;&#x2F;li&gt;
&lt;li&gt;Dijkstra (1977), &lt;em&gt;On the foolishness of &quot;natural language programming&quot;&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Naur (1985), &lt;em&gt;Programming As Theory Building&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Sussman et al. (1985), &lt;em&gt;Structure and Interpretation of Computer Programs&lt;&#x2F;em&gt; *&lt;&#x2F;li&gt;
&lt;li&gt;Pierce (2002), &lt;em&gt;Types and Programming Languages&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lexi-lambda.github.io&#x2F;blog&#x2F;2019&#x2F;11&#x2F;05&#x2F;parse-don-t-validate&#x2F;&quot;&gt;Parse, Don&#x27;t Validate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;people.freebsd.org&#x2F;~lstewart&#x2F;articles&#x2F;cpumemory.pdf&quot;&gt;What Every Programmer Should Know About Memory&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;software-systems&quot;&gt;Software &amp;amp; Systems&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Thompson (1984), &lt;em&gt;Reflections on Trusting Trust&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Brooks (1986), &lt;em&gt;No Silver Bullet&lt;&#x2F;em&gt; *&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;MapReduce Paper&lt;&#x2F;em&gt; (2004)&lt;&#x2F;li&gt;
&lt;li&gt;Kerrisk (2010), &lt;em&gt;The Linux Programming Interface&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pages.cs.wisc.edu&#x2F;~remzi&#x2F;OSTEP&#x2F;&quot;&gt;OSTEP&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;science-fiction&quot;&gt;Science Fiction&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Gibson (1984), &lt;em&gt;Neuromancer&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Card (1985), &lt;em&gt;Ender&#x27;s Game&lt;&#x2F;em&gt;&lt;label for=&quot;sn-44761015&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-44761015&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;(1977) for the short story&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 *&lt;&#x2F;li&gt;
&lt;li&gt;Card (1986), &lt;em&gt;Speaker for the Dead&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Banks (1988), &lt;em&gt;Player of Games&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Simmons (1989), &lt;em&gt;Hyperion&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Banks (1990), &lt;em&gt;Use of Weapons&lt;&#x2F;em&gt;&lt;label for=&quot;sn-38384254&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-38384254&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;All of the culture series is good, these are selected recommendations.&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 *&lt;&#x2F;li&gt;
&lt;li&gt;Stephenson (1995), &lt;em&gt;The Diamond Age&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Reynolds (2000), &lt;em&gt;Revelation Space&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Ted Chiang (2002), &lt;em&gt;Stories of Your Life and Others&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Stross (2005), &lt;em&gt;Accelerando&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Watts (2006), &lt;em&gt;Blindsight&lt;&#x2F;em&gt; *&lt;&#x2F;li&gt;
&lt;li&gt;Reynolds (2008), &lt;em&gt;House of Suns&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Reynolds (2016), &lt;em&gt;Beyond the Aquila Rift&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;qntm (2020), &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;qntm.org&#x2F;mmacevedo&quot;&gt;&lt;em&gt;Lena&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;qntm (2021), &lt;em&gt;Ra&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;history-of-science-technology&quot;&gt;History of Science, Technology&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Kuhn (1962), &lt;em&gt;The Structure of Scientific Revolutions&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Popper (1962), &lt;em&gt;Conjectures and Refutations&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Donald MacKenzie (1993), &lt;em&gt;Inventing Accuracy&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Gleick (2011), &lt;em&gt;The Information: A History, a Theory, a Flood&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Yanofsky (2013), &lt;em&gt;The Outer Limits of Reason&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Dithering (and math)!</title>
        <published>2025-06-05T00:00:00+00:00</published>
        <updated>2025-06-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/dither/"/>
        <id>https://blobcode.net/blog/dither/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/dither/">&lt;p&gt;I love! (love)&lt;label for=&quot;sn-81789863&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-81789863&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;I love it so much&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 dithering.&lt;&#x2F;p&gt;
&lt;p&gt;You might ask - what is dithering? It&#x27;s intentional noise applied to an image to prevent quantized error in some set of data.&lt;label for=&quot;sn-70582826&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-70582826&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dither&quot;&gt;Dither - Wikipedia&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 This data - at least for our purposes, is an image.&lt;&#x2F;p&gt;
&lt;p&gt;It can also either be used to represent gradients and increase the number of representative colors in an image, or to increase the ability of data to be compressed, or just to look cool!&lt;&#x2F;p&gt;
&lt;p&gt;Dithering is fundamentally about &lt;em&gt;error diffusion&lt;&#x2F;em&gt; - where the individual quantized pixel&#x27;s value is spread to a certain area of the unprocessed image&#x27;s pixels.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start by picking an image to play with - I like this one, but feel free to pick your own!&lt;&#x2F;p&gt;
&lt;div class=&quot;image-container&quot;&gt;
&lt;canvas id=&quot;original-canvas&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;
&lt;div&gt;
&lt;input type=&quot;file&quot; id=&quot;imageInput&quot; accept=&quot;image&#x2F;*&quot;&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;floyd-steinberg-dithering&quot;&gt;Floyd-Steinberg Dithering&lt;&#x2F;h2&gt;
&lt;p&gt;The first, and arguably most famous example of an image dithering algorithm which we will cover is the Floyd-Steinberg algorithm, which in essence visits each pixel and then applies a kernel transformation to it of the form
$$
\begin{bmatrix}
&amp;amp; * &amp;amp; \frac{7}{16} \\
\frac{3}{16} &amp;amp; \frac{5}{16} &amp;amp; \frac{1}{16}
\end{bmatrix}
$$&lt;&#x2F;p&gt;
&lt;p&gt;But how is a kernel transformation applied? For those unfamiliar, we first convert the image to grayscale&lt;label for=&quot;sn-51810435&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-51810435&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;averaging sRGB color&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
, then take the value of the current pixel (indicated by the *), and then because of it being an error diffusion algorithm, by definition we add the value of the current pixel to the surrounding pixels based on their position in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;The algorithm (in pseudocode) goes something like the following:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;for y = 0 to height-1:
       for x = 0 to width-1:
           old_pixel = image[y][x]
           new_pixel = quantize(old_pixel)
           image[y][x] = new_pixel
           error = old_pixel - new_pixel
           
           if x+1 &amp;lt; width:
               image[y][x+1] += error * 7&#x2F;16
           if y+1 &amp;lt; height:
               if x-1 &amp;gt;= 0:
                   image[y+1][x-1] += error * 3&#x2F;16
               image[y+1][x] += error * 5&#x2F;16
               if x+1 &amp;lt; width:
                   image[y+1][x+1] += error * 1&#x2F;16
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This results in&lt;&#x2F;p&gt;
&lt;div class=&quot;image-container&quot;&gt;
&lt;div id=&quot;canvas1&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This gives us a nice base result to work off of (and to compare to).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;atkinson-dithering&quot;&gt;Atkinson Dithering&lt;&#x2F;h2&gt;
&lt;p&gt;A popular variant of the approach used by the Floyd-Steinberg algorithm is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Atkinson_dithering&quot;&gt;Atkinson dithering&lt;&#x2F;a&gt;, developed for the Macintosh.
It uses the same error-diffusion approach, with the kernel
$$
\begin{bmatrix}
&amp;amp; * &amp;amp; \frac{1}{8} &amp;amp; \frac{1}{8} \\
... &amp;amp; \frac{1}{8} &amp;amp; \frac{1}{8} &amp;amp; \frac{1}{8} &amp;amp; ...\\
... &amp;amp;  &amp;amp; \frac{1}{8} &amp;amp; &amp;amp; ...\\
\end{bmatrix}
$$&lt;&#x2F;p&gt;
&lt;p&gt;This was useful because the $\frac{1}{8}$ is simple to compute on limited hardware as opposed to the awkward fractions of steinberg dithering,
as it can be performed by a bitshift 3 bits to the right.&lt;&#x2F;p&gt;
&lt;div class=&quot;image-container&quot;&gt;
&lt;div id=&quot;canvas2&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;There are a number of other error diffusion methodologies to use, each of which have strengths and weaknesses and a unique look - you can also try your own kernel below!&lt;&#x2F;p&gt;
&lt;div class=&quot;image-container&quot;&gt;
&lt;div id=&quot;canvas3&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Note that we see some interesting results for certain large values in the matrix, as the pixels become saturated and this is subsequently propagated - mildly interesting geometries, especially with shadows!&lt;&#x2F;p&gt;
&lt;p&gt;All in all, I hope you enjoyed this short exploration of dithering methods, with hopefully more to come at some indeterminate point in the future!&lt;&#x2F;p&gt;
&lt;script src=&quot;&#x2F;dither.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;style&gt;
.dither-container.interactive {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
  margin-top: 10px;
}
.fs-kernel-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5px;
  max-width: 200px;
  margin: 0 auto; &#x2F;* Center the grid *&#x2F;
}
.fs-kernel-input {
  width: 60px;
  text-align: center;
}
.fs-preset-buttons {
  margin-top: 10px;
  display: flex;
  gap: 5px;
  justify-content: center;
  flex-wrap: wrap;
}
canvas {
    margin: auto;
    display: block;
    margin-top: 1em;
    border: 1px solid #ccc
}
&lt;&#x2F;style&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>easy dev environments with nix and direnv</title>
        <published>2025-05-24T00:00:00+00:00</published>
        <updated>2025-05-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/easy-environments/"/>
        <id>https://blobcode.net/blog/easy-environments/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/easy-environments/">&lt;p&gt;I recently delved back into the nixos ecosystem, now that it&#x27;s more mature - I&#x27;ve found a new&lt;label for=&quot;sn-52021521&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-52021521&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;at least, new to me (it&#x27;s been around a while, alright...)&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 way to do dev environments for the
many different projects, running on many different ecosystems that I have on the go at any given time. Enter the great combination of
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;nix&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;direnv.net&#x2F;&quot;&gt;direnv&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Myself and many others have long extolled the virtues of reproducible builds and nix in general - I won&#x27;t do that here (tl:dr - nix is amazing). In short, nix allows for deterministic builds - and
pertinent to our current situation, development environments. It means that your team no longer has to say &quot;it works with my setup&quot; - or ask &quot;what gcc version are you on?&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Note that a big advantage of using nix like this is it doesn&#x27;t matter what distro you&#x27;re on - and your local dev environment can come for the ride! What&#x27;s not to love? Now to the fun bit.&lt;&#x2F;p&gt;
&lt;p&gt;First, install &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;download&#x2F;&quot;&gt;nix&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;direnv.net&#x2F;docs&#x2F;installation.html&quot;&gt;direnv&lt;&#x2F;a&gt;, and make sure to enable &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.wiki&#x2F;wiki&#x2F;Flakes#Enable_flakes_permanently_in_NixOS&quot;&gt;flakes&lt;&#x2F;a&gt;.
Then find a &lt;del&gt;victim&lt;&#x2F;del&gt; project you wish to make determinate.&lt;&#x2F;p&gt;
&lt;p&gt;Now create a &lt;code&gt;flake.nix&lt;&#x2F;code&gt; file in your project&#x27;s root directory - note that this can be a bit different depending on your dev environment, but it generally looks something like&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;{
  inputs.nixpkgs.url = &amp;quot;nixpkgs&#x2F;nixos-unstable&amp;quot;;

  outputs = inputs:
    let
      supportedSystems = [ &amp;quot;x86_64-linux&amp;quot; &amp;quot;aarch64-linux&amp;quot; &amp;quot;x86_64-darwin&amp;quot; &amp;quot;aarch64-darwin&amp;quot; ];
      forEachSupportedSystem = f: inputs.nixpkgs.lib.genAttrs supportedSystems (system: f {
        pkgs = import inputs.nixpkgs { inherit system; };
      });
    in
    {
      devShells = forEachSupportedSystem ({ pkgs }: {
        default = pkgs.mkShell {
          packages = with pkgs; [&amp;lt;your packages here&amp;gt;];
        };
      });
    };
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can find packages for common programs &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;packages&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You can test that this is working by running &lt;code&gt;nix develop&lt;&#x2F;code&gt;. You should get a basic shell with the commands you need. But why stop here? Let&#x27;s make it a bit easier to switch between our projects (and keep our preferred shells!).&lt;&#x2F;p&gt;
&lt;p&gt;Now for the final bit - create a &lt;code&gt;.envrc&lt;&#x2F;code&gt; file with the contents &lt;code&gt;use flake&lt;&#x2F;code&gt;, and run &lt;code&gt;direnv allow&lt;&#x2F;code&gt;, which tells direnv not to ignore the file you just created.&lt;label for=&quot;sn-77607705&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-77607705&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;it does this for security reasons&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Now when you &lt;code&gt;cd&lt;&#x2F;code&gt; into your project folder, you should see the flake environment activate by default. However, you might notice that it&#x27;s a bit slow - you can install &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nix-direnv&quot;&gt;nix-direnv&lt;&#x2F;a&gt;,
which aims to fix this by caching the &lt;code&gt;nix-shell&lt;&#x2F;code&gt; environment.&lt;&#x2F;p&gt;
&lt;p&gt;Now you&#x27;re all set to have easily shareable, reproducible dev environments!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Interactive Simulated Annealing</title>
        <published>2025-04-07T00:00:00+00:00</published>
        <updated>2025-04-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/simulated-annealing/"/>
        <id>https://blobcode.net/blog/simulated-annealing/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/simulated-annealing/">&lt;style&gt;
canvas {
        background-color: white;
        width: 60%;
        margin-left: auto;
        margin-right: auto;
        display: block;
        margin-top: 1em;
    }
&lt;&#x2F;style&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h2&gt;
&lt;p&gt;There exist many problems where finding the local, and in some cases, global minima of a function is desirable - most commonly in optimization problems such as
the traveling salesman problem (TSP). Oftentimes, however, computing this minima often requires traversing the entire state-space - this can be extremely difficult&lt;label for=&quot;sn-87964442&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-87964442&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;&lt;em&gt;read NP-Hard&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 to do efficiently. However, for some classes of problem an approximate solution often suffices. How might we find an approximate solution?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-metropolis-algorithm&quot;&gt;The Metropolis Algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;Let us take a break from finding global minima and focus on a closely related problem. Say we wish for a method to sample from some arbitrary probability distribution, $p(x)$.
In many cases we know the probability $p(x)$, but not how to sample some $x$ from $p(x)$. For a (trivial) example, let $$p(x)= \frac{3}{8} e^{-x^2} + \frac{1}{4} e^{-(x - 4)^2} + \frac{1}{4} e^{-(x + 2)^2}$$&lt;&#x2F;p&gt;
&lt;p&gt;This is the thinking behind the &lt;em&gt;Metropolis algorithm&lt;&#x2F;em&gt;, originally proposed in 1953, though many other variations exist.
The idea is define a markov chain over possible values of $p(x)$ such that we asymptotically reach a unique stationary distribution $p(x)$.&lt;&#x2F;p&gt;
&lt;p&gt;We start with the detailed balance representing this condition&lt;&#x2F;p&gt;
&lt;p&gt;$$
\begin{align*}
p(x&#x27; | x)\ p(x) = p(x | x&#x27;)\ p(x&#x27;)
\end{align*}
$$
$$
\frac{p(x&#x27; | x)}{p(x | x&#x27;)} =\frac{p(x&#x27;)}{p(x)}
$$&lt;&#x2F;p&gt;
&lt;p&gt;We then split this into the proposal and acceptance &#x2F; rejection, where $q(x&#x27; | x)$ represents the conditional probability of proposing $x&#x27;$ over $x$ and $A(x&#x27;,x)$ is the probability of accepting said proposed state
$$
p(x&#x27; | x) = q(x&#x27; | x)\ A(x&#x27;,x)
$$
Thus
$$
A(x&#x27;,x)=\min\left( 1, \frac{p(x&#x27;)}{p(x)} \times \frac{q(x | x&#x27;)}{q(x&#x27; | x)} \right)
$$&lt;&#x2F;p&gt;
&lt;p&gt;As an algorithm, it runs in couple relatively simple steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Pick some initial state $x_0$ (typically random), let $t=0$;&lt;&#x2F;li&gt;
&lt;li&gt;Generate a random candidate $x&#x27;$ according to $q(x&#x27;|x_t)$;&lt;&#x2F;li&gt;
&lt;li&gt;Calculate the acceptance probability $A(x&#x27;,x_t)$.&lt;&#x2F;li&gt;
&lt;li&gt;Accept the state if $random(0,1) \leq A(x&#x27;,x_t)$ and set $x_{t+1}=x&#x27;$, otherwise reject it ($x_{t+1}=x_t$);&lt;&#x2F;li&gt;
&lt;li&gt;increment $t$.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;container&quot;&gt;
&lt;div class=&quot;simulation&quot;&gt;
&lt;canvas id=&quot;metropolisCanvas&quot; width=&quot;800&quot; height=&quot;600&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;div class=&quot;controls&quot;&gt;
&lt;button id=&quot;startMetropolis&quot;&gt;Start&lt;&#x2F;button&gt;
&lt;button id=&quot;resetMetropolis&quot;&gt;Reset&lt;&#x2F;button&gt;
&lt;button id=&quot;clearHistogram&quot;&gt;Clear&lt;&#x2F;button&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;status&quot; id=&quot;metropolisStatus&quot;&gt;
Current position: 0&lt;br&gt;
Accepted moves: 0 &#x2F; 0 (0%)&lt;br&gt;
Samples collected: 0
&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;You can play with this yourself here - observe how the distribution builds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;simulated-annealing&quot;&gt;Simulated Annealing&lt;&#x2F;h2&gt;
&lt;p&gt;It should now hopefully be more clear as to how we might approach a local minimization problem like the one presented in the beginning.
We now have some context to pursue an approach to simulated annealing. Simulated annealing was initially devised to solve the physical problem of (you guessed it) annealing of metals! As such, it revolves around the idea that heating and cooling affect both the temperature and free energy of a given system.&lt;&#x2F;p&gt;
&lt;p&gt;We can derive this by modifying our metropolis algorithm in two key ways&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;introduce a temperature $T$, and a cooling schedule which decreases $T$, typically exponentially&lt;label for=&quot;sn-78009724&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-78009724&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;though other examples of cooling schedules exist, they may not be optimal&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
.&lt;&#x2F;li&gt;
&lt;li&gt;introduce an energy function $E(x)$ which we wish to optimize, in place of the probability function, where $p(x) \propto e^{-E(x)&#x2F;T}$, which aligns with the boltzmann distribution.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Then
$$
A(x&#x27;,x)= \min \left( 1,\frac{e^{-E(x&#x27;)&#x2F;T}}{e^{-E(x)&#x2F;T}} \right) = \min(1,e^{−(E(x′)−E(x))&#x2F;T})
$$&lt;&#x2F;p&gt;
&lt;p&gt;which is exactly the acceptance probability for simulated annealing. Here temperature serves as an analog for risk - at high temperatures, the algorithm is more likely to accept an uphill move to a higher energy state. As the temperature decreases, the algorithm becomes less and less willing to take an uphill move in &quot;hopes&quot; that we will find a new global minima beyond it, reducing to hill-climbing as $T\to 0$. It also turned out that this is a relatively good&lt;label for=&quot;sn-19850740&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-19850740&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;(barring some objections)&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 way to minimize some arbitrary function - which is really nice if we happen to have a problem which is difficult to compute exactly.&lt;&#x2F;p&gt;
&lt;p&gt;The algorithm for simulated annealing is quite similar to what we&#x27;ve already seen with the metropolis algorithm (shortened for simplicity here)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Pick some initial state $x\ \leftarrow x_0$ (typically random);&lt;&#x2F;li&gt;
&lt;li&gt;For $k=0$ through to $k_{max}$,
&lt;ul&gt;
&lt;li&gt;$T\ \leftarrow\ schedule(k)$&lt;&#x2F;li&gt;
&lt;li&gt;$x&#x27;=neighbor(x)$&lt;&#x2F;li&gt;
&lt;li&gt;if $A(x,x&#x27;) &amp;gt; random(0,1)$
&lt;ul&gt;
&lt;li&gt;$x\ \leftarrow\ x&#x27;$&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Return $x$&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We can also modify this procedure to optimize for the most total energy, or maximum, as opposed to minimizing our total energy.
You can try this out with the simulation below&lt;&#x2F;p&gt;
&lt;div class=&quot;simulation&quot;&gt;
&lt;canvas id=&quot;annealingCanvas&quot; width=&quot;800&quot; height=&quot;600&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;div class=&quot;controls&quot;&gt;
&lt;button id=&quot;startAnnealing&quot;&gt;Start&lt;&#x2F;button&gt;
&lt;button id=&quot;resetAnnealing&quot;&gt;Reset&lt;&#x2F;button&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;status&quot; id=&quot;annealingStatus&quot;&gt;
Current position: 0&lt;br&gt;
Temperature: 1.0&lt;br&gt;
Accepted moves: 0 &#x2F; 0 (0%)&lt;br&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We can also apply this approach quite effectively to similar types of problem where we aim to minimize some total energy function.&lt;&#x2F;p&gt;
&lt;script src=&quot;&#x2F;sa.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;In conclusion, I hope that you learnt something!&lt;&#x2F;p&gt;
&lt;p&gt;Note that there is a whole ton of rigour which I have completely neglected to mention as to the requirements and types of systems that can be represented this way - and why, in order for this introduction to remain accessible. I would recommend reading the original paper if you are interested in the details.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>hello again!</title>
        <published>2025-02-17T00:00:00+00:00</published>
        <updated>2025-02-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/hello-again/"/>
        <id>https://blobcode.net/blog/hello-again/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/hello-again/">&lt;p&gt;Hello once again - after a period characterized by a distinct lack of blog posts (me being busy) - I come again with
a (for the third time, no less) rewritten website. It is now written using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jaspervdj.be&#x2F;hakyll&#x2F;&quot;&gt;hakyll&lt;&#x2F;a&gt; and deployed to a S3 bucket for simplicity&#x27;s sake.
I now have greatly improved features such as sidenotes&lt;label for=&quot;sn-48894907&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-48894907&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;They&#x27;re pretty cool&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
 and references. I also have equation parsing handled, so things like
$x=\frac{1}{2}$ work - and more advanced typesetting as well.&lt;&#x2F;p&gt;
&lt;p&gt;$$
\int_{a}^{b} x^2 \ dx
$$&lt;&#x2F;p&gt;
&lt;p&gt;We even have cool html sidenotes!
&lt;label for=&quot;sn-50395033&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-50395033&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;like this one: $x^2+2=4$&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;And tables!&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Month&lt;&#x2F;th&gt;&lt;th&gt;Savings&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;January&lt;&#x2F;td&gt;&lt;td&gt;$250&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;February&lt;&#x2F;td&gt;&lt;td&gt;$80&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;March&lt;&#x2F;td&gt;&lt;td&gt;$420&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;That&#x27;s about it - I should have a couple of articles that I&#x27;ve been meaning to write in the backlog coming out soon(ish)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, so stay tuned for those!&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;subject to when I feel like it &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>internet radio with icecast and liquidsoap</title>
        <published>2023-05-23T00:00:00+00:00</published>
        <updated>2023-05-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/internet-radio-icecast/"/>
        <id>https://blobcode.net/blog/internet-radio-icecast/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/internet-radio-icecast/">&lt;p&gt;This is a quick guide on setting up a personal internet radio station. Note that this assumes you have a realtively mainstream linux vps (this tutorial will be using debian, but feel free to substitute distro of choice).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-note-on-audio&quot;&gt;a note on audio&lt;&#x2F;h2&gt;
&lt;p&gt;This guide will assume that you have audio files placed in a liquidsoap-compatible format in &lt;code&gt;&#x2F;usr&#x2F;share&#x2F;music&lt;&#x2F;code&gt;, although feel free to substitute this directory for whatever is convienent (and hopefully FHS compliant).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;icecast&quot;&gt;icecast&lt;&#x2F;h2&gt;
&lt;p&gt;Icecast is the service in this setup that actually broadcasts our audio from an internal source. The first step is to set up and install an icecast server - you can find releases &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;icecast.org&#x2F;download&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;. Once you have the package installed, open &lt;code&gt;&#x2F;etc&#x2F;icecast2&#x2F;icecast.xml&lt;&#x2F;code&gt;. Here you should change the default password for both &lt;code&gt;source&lt;&#x2F;code&gt;, &lt;code&gt;relay&lt;&#x2F;code&gt; and &lt;code&gt;admin-user&lt;&#x2F;code&gt;, and keep track of them for later. We can also tweak settings such as the max number of users here. Once you&#x27;re done, you can start icecast with &lt;code&gt;systemctl icecast2 start&lt;&#x2F;code&gt; and `systemctl icecast2 enable&#x27;.&lt;&#x2F;p&gt;
&lt;p&gt;You can now check that the server is running at &lt;code&gt;&amp;lt;server-address&amp;gt;:8000&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;liquidsoap&quot;&gt;liquidsoap&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.liquidsoap.info&#x2F;&quot;&gt;liquidsoap&lt;&#x2F;a&gt; is the audio provider for this setup, allowing for you to create and customize your audio stream. Once installed, you will need to create a &lt;code&gt;.liq&lt;&#x2F;code&gt; file for your stream. A common location is at &lt;code&gt;&#x2F;bin&#x2F;liquidsoap&#x2F;&lt;&#x2F;code&gt;. We&#x27;ll be creating a file &lt;code&gt;&#x2F;bin&#x2F;liquidsoap&#x2F;main.liq&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;main.liq&lt;&#x2F;code&gt;, we can now start to create our station programming. We&#x27;ll be working with something fairly basic, but feel free to take a look at the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.liquidsoap.info&#x2F;doc-2.1.4&#x2F;cookbook.html&quot;&gt;liquidsoap docs for inspiration&lt;&#x2F;a&gt;. Replace the contents of &lt;code&gt;main.liq&lt;&#x2F;code&gt; with&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;music = playlist(&amp;quot;&#x2F;usr&#x2F;share&#x2F;music&amp;quot;)

radio = mksafe(random([music]))

# Stream it out
output.icecast(%mp3.vbr,
host = &amp;quot;localhost&amp;quot;, port = 8000,
password = &amp;quot;&amp;lt;ICECAST SOURCE PASSWORD&amp;gt;&amp;quot;, mount = &amp;quot;stream.mp3&amp;quot;,
name = &amp;quot;very cool name&amp;quot;, description = &amp;quot;description&amp;quot;,
radio)

&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a &lt;em&gt;very&lt;&#x2F;em&gt; basic server, with no fallback audio that randomly streams audio from the &lt;code&gt;&#x2F;usr&#x2F;share&#x2F;music&lt;&#x2F;code&gt; folder (recursively) in an mp3 format.&lt;&#x2F;p&gt;
&lt;p&gt;Note that at this point, due to the inane number of issues encountered running &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;savonet&#x2F;liquidsoap-daemon&#x2F;&quot;&gt;liquidsoap-daemon&lt;&#x2F;a&gt;, we will be running our own service. Create a file named &lt;code&gt;main.sh&lt;&#x2F;code&gt; in &lt;code&gt;&#x2F;bin&#x2F;liquidsoap&lt;&#x2F;code&gt;, with the following contents&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash 
liquidsoap &#x2F;bin&#x2F;liquidsoap&#x2F;main.liq
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;now create a service file for liquidsoap in &lt;code&gt;&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;liquidsoap.service&lt;&#x2F;code&gt; with the following&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=liquidsoap

[Service]
User=&amp;lt;non-root user&amp;gt;
ExecStart=&#x2F;bin&#x2F;liquidsoap&#x2F;main.sh

[Install]
WantedBy=multi-user.target
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and now you can get the service going with &lt;code&gt;systemctl enable liquidsoap&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;systemctl start liquidsoap&lt;&#x2F;code&gt;. At this point the audio stream should be available at &lt;code&gt;http:&#x2F;&#x2F;&amp;lt;server-address&amp;gt;:8000&#x2F;stream.mp3&lt;&#x2F;code&gt;. From here, you can stream from a local client or setup a web-based streaming setup.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>issues with nix</title>
        <published>2023-01-24T00:00:00+00:00</published>
        <updated>2023-01-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/nix-issues/"/>
        <id>https://blobcode.net/blog/nix-issues/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/nix-issues/">&lt;p&gt;Inspired by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34492401&quot;&gt;this comment on hacker news&lt;&#x2F;a&gt;, I feel as a fairly excited nix user that I could take a stab at lot of the issues and papercuts I&#x27;ve experienced in my time with nix and nixos. I&#x27;m highlighting a lot of issues that are at the forefront for anyone wanting to learn &#x2F; adopt nix. As follows are some of the issues that I&#x27;ve experienced and that can (hopefully) be rectified, because although I do &lt;em&gt;really like&lt;&#x2F;em&gt; nixos, It&#x27;s just not really ready for a large production environment (in my opinion).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;docs&quot;&gt;docs&lt;&#x2F;h2&gt;
&lt;p&gt;The biggest issue, by far and away with nix as a whole is a massive lack of documentation. Although things may have improved, there&#x27;s still massive amounts of documentation that is either out of date or simply nonexistent. The biggest help in this category is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;packages&quot;&gt;the nixos package search&lt;&#x2F;a&gt;, which I still find myself relying on even as a relatively experienced nix user. This is also pretty evident in the surrounding nixos community - there are heaps and heaps of posts praising nixos, with comparatively many fewer guides or help resources for beginners.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compatibility&quot;&gt;compatibility&lt;&#x2F;h2&gt;
&lt;p&gt;Nixos also (like any emerging technology, to be fair), is quite lacking when comes to backwards-compatibility - although the os is great about this, the language and surrounding tooling is... significantly less so. The big ecosystem-level issue here is the channels&#x2F;flakes divide, where although flakes &lt;em&gt;are&lt;&#x2F;em&gt; the recommended pathway nowadays,
there&#x27;s a huge mess surrounding the messaging of what to use for new users - for example flakes are behind a flag and are still &lt;em&gt;technically&lt;&#x2F;em&gt; an experimental feature, despite being around for a majority of(?) of the ecosystem&#x27;s life.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errors&quot;&gt;errors&lt;&#x2F;h2&gt;
&lt;p&gt;Expect a rant here if I ever get around to it...&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>new year, new backend</title>
        <published>2023-01-23T00:00:00+00:00</published>
        <updated>2023-01-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/new-backend/"/>
        <id>https://blobcode.net/blog/new-backend/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/new-backend/">&lt;p&gt;This is a bit of an update on the backend &#x2F; hosting changeover that I&#x27;ve made over the Christmas Break. The big items are&lt;&#x2F;p&gt;
&lt;h2 id=&quot;backend-rewrite&quot;&gt;backend rewrite&lt;&#x2F;h2&gt;
&lt;p&gt;Out of papercuts with both packaging go binaries &#x2F; managing go dependencies with nix as well as wanting to try &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;maud.lambda.xyz&#x2F;&quot;&gt;maud&lt;&#x2F;a&gt;, a (relatively) new rust html engine that came highly recommended from a friend. This was relatively painless, as the old backend was written in &amp;gt;100 lines of go anyways. This allows for a lot more flexibility with site structure, so expect some cool changes coming up!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hosting-deploy-changes&quot;&gt;hosting &#x2F; deploy changes&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve also changed over from aws to OVHcloud, mainly due to the (much) better pricing and friendlier support. There were some issues with nixos images, but thankfully it&#x27;s possible to get terraform to provision a light vm and run nixos-infect on it on the first deploy. This is supported by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zhaofengli&#x2F;colmena&quot;&gt;colmena&lt;&#x2F;a&gt;, which is nice semi-successor to morph. I&#x27;ve found it nice to work with, and overall this works quite a bit better than relying on terraform to build system images.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, this should allow for me to work to build more interactive posts, which is a goal I&#x27;ve been working towards for the past while.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>teaching go as a first programming language</title>
        <published>2022-11-16T00:00:00+00:00</published>
        <updated>2022-11-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/first-languages/"/>
        <id>https://blobcode.net/blog/first-languages/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/first-languages/">&lt;p&gt;I&#x27;ve been getting back into teaching coding lately, and coming back to it I had the chance to move away from teaching python, what we&#x27;ve historically taught in because of a myriad of small, irritating problems that exist in the teaching workflow.&lt;&#x2F;p&gt;
&lt;p&gt;So the question was asked - what language &lt;em&gt;do&lt;&#x2F;em&gt; we use?&lt;&#x2F;p&gt;
&lt;p&gt;Talking to my friends there were quickly very many suggestions. Java? Go? C++? Javascript? Rust?&lt;&#x2F;p&gt;
&lt;p&gt;Now before we get into things, I should metion that my first language was Unreal&#x27;s &lt;strong&gt;incredibly&lt;&#x2F;strong&gt; cursed version of C++ - so really anthing would have been an upgrade over learning that.&lt;&#x2F;p&gt;
&lt;p&gt;After a bit of discussion(read debate), we narrowed down to four main contenders, Java, Rust, Go and C.&lt;&#x2F;p&gt;
&lt;p&gt;Honestly any language &quot;works&quot; as a first language - a lot of learning programming comes down to learning fundamental concepts, and this is why languages like racket are common in introductory computer science courses. Ideally, though,
we wanted a language that is low-level enough that you can work with some of the core aspects of computer architecture. This more or less takes Java out of the equation, as it (more or less) requires the JVM to work.&lt;&#x2F;p&gt;
&lt;p&gt;Secondly, a lot of us noticed that when teaching in a loosely-typed language, such as python, types often caused a lot of confusion over what type was implicitly assigned - and although to someone with experience it isn&#x27;t too bad,
we often had to resort to &quot;forcing&quot; students to explicitly define types to avoid this. This goes hand in hand with language semantics - although languages like rust have a great compiler, a lot of language features that exist to
stop you from shooting yourself in the foot add a lot of (for beginners) unwieldy language semantics. That more or less takes rust out, for better or for worse.&lt;&#x2F;p&gt;
&lt;p&gt;This leaves Go and C, and although as much as C is a classic for teaching and has it advantages in teaching how to effectively manage memory manually, go beats it out by a mile when it comes to cross platform compiler support, as
well as supporting tooling and ecosystem. In addition, a lot of what makes go great for teaching is that it gives immediate feedback and a feeling of progress to students - they don&#x27;t need 150 lines to get a webpage up and running,
and that combined with the very wide breadth of things that you can do with go, from kernels to databases to webpages to cli &#x2F; gui apps make it great for whatever direction a student wants to go after they learn the basics.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-golang-lacks&quot;&gt;what golang lacks&lt;&#x2F;h2&gt;
&lt;p&gt;The one big thing that go is missing is a lot of OOP structures, and although this makes teaching in a more traditional style a bit more difficult, it is still very much possible to structure a go program in OOP style, which covers
most of the key concepts, if we need to then is a good jumping-off point to switch into something like C++ or Java depending on the situation.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;endnotes&quot;&gt;endnotes&lt;&#x2F;h2&gt;
&lt;p&gt;I intend to let people know (after some more teaching) what some of the highlights and disadvantages with go are so far, so check back in a bit.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>markdown!</title>
        <published>2022-08-28T00:00:00+00:00</published>
        <updated>2022-08-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/markdown/"/>
        <id>https://blobcode.net/blog/markdown/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/markdown/">&lt;p&gt;If you&#x27;ve stopped by in the past little bit, you might have noticed I now have &lt;strong&gt;markdown&lt;&#x2F;strong&gt;.
It was about 15 mins. to overhaul the templating system in the website, and it lets me do all sorts of
&lt;em&gt;fun stuff&lt;&#x2F;em&gt;, like&lt;&#x2F;p&gt;
&lt;h2 id=&quot;headings&quot;&gt;headings&lt;&#x2F;h2&gt;
&lt;p&gt;and&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;proper&lt;&#x2F;li&gt;
&lt;li&gt;lists&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;that&#x27;s about it for now - but expect me to be a &lt;em&gt;bit&lt;&#x2F;em&gt; more active writing since I&#x27;m back from all of my summer trips!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>hello world!</title>
        <published>2022-08-04T00:00:00+00:00</published>
        <updated>2022-08-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/hello-world/"/>
        <id>https://blobcode.net/blog/hello-world/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/hello-world/">&lt;p&gt;Hello there - this is the start of a whole new blog, written by me, blobcode!
I hope that this is the first article of many!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>on cobalt</title>
        <published>2022-05-09T00:00:00+00:00</published>
        <updated>2022-05-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/cobalt/"/>
        <id>https://blobcode.net/blog/cobalt/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/cobalt/">&lt;p&gt;So I&#x27;ve spent the last little while writing a new project, cobalt&lt;label for=&quot;sn-564146&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-564146&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;cobalt&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;cobalt&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
.
It&#x27;s a minimal reverse proxy that handles http - take a look if it sounds interesting.
It&#x27;s the descendant of the earlier pine&lt;label for=&quot;sn-26958716&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-26958716&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;pine&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;pine&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
, which was a more naive implementation.
I figured that talking about the design and implementation would be a good exercise.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem-space&quot;&gt;the problem space&lt;&#x2F;h2&gt;
&lt;p&gt;I wanted a simple reverse proxy that was reasonably performant without bloat.
I took a look at&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;nginx&lt;&#x2F;li&gt;
&lt;li&gt;caddy&lt;&#x2F;li&gt;
&lt;li&gt;haproxy&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All of which, with the exception of haproxy, are not first and foremost, proxies.
Although the features they offer are great, I prefer having dedicated, configurable
solution for everything. Thus, I decided to make cobalt (I was also pretty bored).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design&quot;&gt;design&lt;&#x2F;h2&gt;
&lt;p&gt;cobalt is a really simple, based around the tokio async runtime, which runs a tcp server.
cobalt expects raw http input, with a host header present. It takes in a single argument,
[-c], which is the path to a toml file that defines the config.&lt;&#x2F;p&gt;
&lt;p&gt;cobalt will serialize the hosts segment of the config into a hashmap, which is used by
the server.&lt;&#x2F;p&gt;
&lt;p&gt;The server is pretty minimal. It reads a tcpstream, looks for a http host header in the
first 1024 bytes, and splits then proxies the stream. All of this is done through the
aforementioned tokio, which has been great.&lt;&#x2F;p&gt;
&lt;p&gt;I can get around 100,000 requests a second through it running on an i5-1135, and I plan
to test it on a proper server sometime, given it can effectively max out all of my cores
and is heavily cpu-bound.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, I&#x27;m pretty happy with cobalt, which is a large improvement over pine. If you&#x27;d like to
see any new features &#x2F; find any bugs, feel free to submit a pull request or raise an issue.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>why I love tiny software</title>
        <published>2022-04-12T00:00:00+00:00</published>
        <updated>2022-04-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/tiny-software/"/>
        <id>https://blobcode.net/blog/tiny-software/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/tiny-software/">&lt;p&gt;I love tiny software - it&#x27;s no surprise. I&#x27;ve even written some myself over the past couple
years&lt;label for=&quot;sn-74347448&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-74347448&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;such as [pine&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
(https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;pine) and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;amp&quot;&gt;amp&lt;&#x2F;a&gt;].&lt;&#x2F;p&gt;
&lt;p&gt;First, let&#x27;s define &lt;em&gt;tiny&lt;&#x2F;em&gt;. To me tiny means that it&#x27;s&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;small in file size&lt;&#x2F;li&gt;
&lt;li&gt;simple to setup &#x2F; configure with sane defaults&lt;&#x2F;li&gt;
&lt;li&gt;simple in function and limited in scope&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some might find this similar to the unix philosophy&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and I&#x27;d be inclined to agree.
There&#x27;s something magical about being able to have software that just works. With tiny software,
it&#x27;s also much more understandable, and thus hackable.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s a great thing because it both allows for users to customize it however they choose (for a
great example of this, take a look at suckless tools&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and it also
promotes open source involvement - with a small codebase changes are easy to understand, and the purpose
and intended use case of the software is clear, because it only has one or two functions.&lt;&#x2F;p&gt;
&lt;p&gt;If you need to know how something works, just look at the source.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why&quot;&gt;why?&lt;&#x2F;h2&gt;
&lt;p&gt;That&#x27;s a good question. It might seem attractive or more convenient to have a piece of software
that does everything for a job - take a look at something like MySQL. It has a &lt;em&gt;huge&lt;&#x2F;em&gt; spec, with
hundreds if not thousands of features, and I&#x27;m sure that a vast majority of them are useful
for running at &lt;em&gt;webscale&lt;&#x2F;em&gt; or a very niche case - but most people aren&#x27;t webscale. You can
do most of everything you need to do using something like sqlite instead.&lt;&#x2F;p&gt;
&lt;p&gt;So why? - because you can get along just fine using simple choices and tiny software&lt;label for=&quot;sn-25585059&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;sn-25585059&quot; class=&quot;margin-toggle&quot;&#x2F;&gt;
&lt;aside class=&quot;sidenote&quot;&gt;
    &lt;p&gt;and I find it fun!&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unix_philosophy&quot;&gt;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unix_philosophy&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;suckless.org&quot;&gt;https:&#x2F;&#x2F;suckless.org&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>about this website</title>
        <published>2022-04-11T00:00:00+00:00</published>
        <updated>2022-04-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Lucas Helme
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blobcode.net/blog/this-website/"/>
        <id>https://blobcode.net/blog/this-website/</id>
        
        <content type="html" xml:base="https://blobcode.net/blog/this-website/">&lt;p&gt;When I started with wanting to create a website, I decided that I wanted something that was&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;easy to build &#x2F; deploy&lt;&#x2F;li&gt;
&lt;li&gt;minimal configuration &#x2F; state&lt;&#x2F;li&gt;
&lt;li&gt;easibly changable &#x2F; hackable&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I decided to write some custom webserver software with go, mostly as a learning project - while I was doing this,
I stumbled upon the embed&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-0-1&quot;&gt;&lt;a href=&quot;#fn-0&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; feature, which allows for you to embed static assets in a go binary.&lt;&#x2F;p&gt;
&lt;p&gt;This got me thinking...&lt;&#x2F;p&gt;
&lt;p&gt;Could I create a single binary blog?&lt;&#x2F;p&gt;
&lt;p&gt;Yes!
This is that blog. I&#x27;m calling it puffin, and it&#x27;s about 100 lines of go&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, using exclusively the standard library.
All of the blog posts are just .txt files (though I might move to markdown at some point), which are
aliased to &lt;code&gt;\*.html&lt;&#x2F;code&gt; files by puffin.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deployment&quot;&gt;deployment&lt;&#x2F;h2&gt;
&lt;p&gt;For deployment, I wanted something that I don&#x27;t have to mess with. I hate dealing with local system state,
and so when I was recomended nixos&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, it was perfect. I don&#x27;t have space to explain the incredible number of
reasons nixos is amazing, but I should get around posting a blog post on it soon. Here are some quick points&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;it supports fully declarative configuartion using the nix language&lt;&#x2F;li&gt;
&lt;li&gt;it has a great package manager, confusingly also named named nix&lt;&#x2F;li&gt;
&lt;li&gt;it supports easily building &#x2F; compiling custom packages&lt;&#x2F;li&gt;
&lt;li&gt;it supports building custom images super easily&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;my nix config was suprisingly simple to setup. I decided to build a hermetic deploy using niv
to pin my package versions. I pinned them at 21.05, as a result of issues I&#x27;ll talk about later.&lt;&#x2F;p&gt;
&lt;p&gt;On nix, I&#x27;m running a pretty standard config with a ngnix instance revese proxying puffin&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-2&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The webserver is built
with a nix expression and packaged as a service.&lt;&#x2F;p&gt;
&lt;p&gt;On that note, I was surprised at just how effortless it was to create a nix config.
Once you get over some of prickly bits of the language and the lack of documentation (I found the nix option search&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
to be a lifesaver), it&#x27;s super easy to get a working system state - my whole config is less than 200 lines it total across
only 3 files!&lt;&#x2F;p&gt;
&lt;p&gt;For actually deploying to hardware, I&#x27;m using terraform. I&#x27;d love to use nixops - it seems to have a much smoother
ux in my experience, however it&#x27;s in process of being upgraded to v2 and it doesn&#x27;t support remote state,
which is a requirement for me.&lt;&#x2F;p&gt;
&lt;p&gt;The terraform config is pretty simple. It consists of a single ec2 instance, which is currently a t3.micro. The only
special part of it is the deploy_nixos module[ref]. I&#x27;ve found it to be pretty great - although
it runs into the aforementioned issues when initally deploying to nixos &amp;gt; 21.05, as 21.11
deprecated RSA keys. This is compounded by terraform_tls not liking ed25519 keys for whatever
reason. If anyone has any idea why they don&#x27;t work, please let me know.&lt;&#x2F;p&gt;
&lt;p&gt;The actual deployment is a simple makefile (I&#x27;m fond of them but I&#x27;m not quite sure why) that
runs nix-shell and then terraform apply.&lt;&#x2F;p&gt;
&lt;p&gt;This will automatically pick up any changes in my terraform state, nixos config or go binary
and rebuild them if neccesary.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, I&#x27;m pretty pleased with how things turned out for about 5-6 hours of work, though I might (and probably will)
rework some of it later.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-0&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;embed&quot;&gt;https:&#x2F;&#x2F;pkg.go.dev&#x2F;embed&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-0-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;puffin&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;blobcode&#x2F;puffin&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-1-2&quot;&gt;↩2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;https:&#x2F;&#x2F;nixos.org&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;options?&quot;&gt;https:&#x2F;&#x2F;search.nixos.org&#x2F;options?&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
</feed>
