<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <link href="https://afontaine.dev:80/feed"/>
  <author>
    <name>Andrew Fontaine</name>
    <email>andrew@afontaine.ca</email>
  </author>
  <id>https://afontaine.dev:80/</id>
  <title>Andrew Fontaine · Mostly Code</title>
  <updated>2022-10-20T14:46:15+00:00</updated>
  <entry>
    <content type="html"><![CDATA[<p>
I’ve decided to try using <a href="https://notmuchmail.org/" title=""><code class="inline">notmuch</code></a> for my email instead of <a href="https://www.djcbsoftware.nl/code/mu/" title=""><code class="inline">mu</code></a>.</p>
<p>
This is mostly due to the tagging nature (instead of folders), as well as the
built-in hooks that run pre- and post- indexing. It makes setting up certain
behaviours, along with <a href="https://github.com/afewmail/afew" title=""><code class="inline">afew</code></a>, much easier than in GMail’s filters.</p>
<p>
I’ve also moved to using <a href="https://github.com/gauteh/lieer" title=""><code class="inline">lieer</code></a> to sync the GMail inbox, as it hopefully
gets along nicer with large GMail inboxs, which is the case when you’re
accepting the flood of emails from watching the <a href="https://gitlab.com/gitlab-org/gitlab" title="">GitLab</a> project. The initial
sync is going very slowly though. <code class="inline">lieer</code> syncs GMail’s labels with <code class="inline">notmuch</code>‘s
tags, and so syncing, tagging, and syncing 1.1 million emails can take some
time. I guess that’s another reason to start using <code class="inline">notmuch</code>: it was easy to set
up hooks to delete threads of issues and merge requests that are either closed
or merged, so hopefully that number drops quickly. I should modify my current
hook to preserve threads that I was involved in…</p>
<p>
The main reason for the lack of posts is that its been a busy year. My travels
are as follows:</p>
<ol>
  <li>
Hawaii, for a wedding  </li>
  <li>
Montreal, for fun  </li>
  <li>
Whitby, for a wedding  </li>
  <li>
Portugal, for fun  </li>
  <li>
Niagara-on-the-lake, for a wedding  </li>
  <li>
North Carolina, for a wedding  </li>
  <li>
Sarnia, for a wedding  </li>
</ol>
<p>
Not all of these were long trips, and the longest was Portugal at 10 days, but
boy does it feel like a lot!</p>
<p>
I’ve also bought a house this year. Maybe not the most perfect time to buy, but
we had the money and actually found a wonderful place in Toronto. It’s a
completely different neighbourhood than we previously lived in, but it’s
extremely walkable, bikeable, and right off the subway. I can easily continue my
car-free life.</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/life-updates-aka-where-are-all-the-posts</id>
    <title>Life Updates, aka Where are all the posts?</title>
    <updated>2022-10-20T14:46:15+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
That’s right! This blog is now live on the <code class="inline">gemini</code> protocol. Using your
favourite gemini browser, you can now see all this text in lo-fi glory.</p>
<h2>
What is <code class="inline">gemini</code>?</h2>
<p>
<a href="https://gemini.circumlunar.space/" title=""><code class="inline">gemini</code></a> is a new protocol, first introduced in a 2019, as a stripped down
protocol for the transferring of data, similar to that of HTTP, but with a
purposely smaller scope. It was inspired by a protocol called Gopher, an older
protocol that was competing against HTTP when the web was new.</p>
<p>
Gemini also comes with a new markup format, <a href="https://gemini.circumlunar.space/docs/gemtext.gmi" title=""><code class="inline">gemtext</code></a>. Gemtext is similar
to markdown, but is also stripped down. There are no <strong>bold</strong>, <em>italics</em>, or
other in-line formatting. Links live on their own line, and there’s no way to
embed images. This is by design, leaving any formatting (with a few exceptions)
to the client. There are still headers, blockquotes, and a way to display
preformatted text, but that’s it.</p>
<h2>
Why <code class="inline">gemini</code>?</h2>
<p>
Well this blog (or <em>gemlog</em>, in gemini) is entirely text, so it seemed like a
good enough reason to be available on a text-first platform. It was also an
interesting addition to the elixir application that runs this site. It is still
one monolith, there is no separate gemini microservice. It has interesting
design constraints as well. As the document is just text, the layout of that
text is important, and creating and displaying sections in a coherent manner is
a fun challenge that I’m not sure I’ve worked out.</p>
<h2>
How <code class="inline">gemini</code>?</h2>
<p>
Well <code class="inline">phoenix</code>, the web side of this application, doesn’t know how to speak
gemini, but after a little digging, I found <a href="https://sr.ht/~sgiath/spaceboy/" title=""><code class="inline">spaceboy</code></a>, a “[h]eavily
simplified” take on the phoenix framework for gemini.</p>
<p>
First I added a new application to my umbrella, with <code class="inline">mix new</code>. Trying to
install the dependency was met with several dependency conflicts. It turns out
<code class="inline">phoenix</code> and <code class="inline">spaceboy</code> rely on the same dependencies for TLS and TCP (the
backbones of sending things on a network), but different versions. <code class="inline">cowboy</code>, the
HTTP server that <code class="inline">phoenix</code> relies on, was set to depend on <code class="inline">ranch</code>, the TCP
library, version 1.something, whereas <code class="inline">spaceboy</code> relied on <code class="inline">ranch</code> version 2.0.
This looked like a pretty major conflict that I <em>could</em> override, but didn’t
look promising.</p>
<p>
After a little digging, however, I found <a href="https://github.com/ninenines/cowboy/issues/1476" title="">an issue</a> that stated that the
version of <code class="inline">cowboy</code> that I was using actually supports <em>both</em> <code class="inline">ranch</code> v1 and v2,
so overriding the dependencies was correct here.</p>
<p>
The next struggle was with <code class="inline">spaceboy</code>‘s (minimal) templating system. <code class="inline">phoenix</code>
very fancily handles things like layouts and actually compiles the templates
into elixir code. <code class="inline">spaceboy</code> does not, so when I went to deploy it for the first
time, none of my pages worked as the templates were left behind. I <a href="https://lists.sr.ht/~sgiath/spaceboy/%3C87mtj7fcjh.fsf%40afontaine.ca%3E#%3C87mtj7fcjh.fsf@afontaine.ca%3E" title="">reached
out</a> for any ideas, but ultimately came up with a solution before the author
could respond. It has given me some ideas on how to contribute back to
<code class="inline">spaceboy</code> though.</p>
<h2>
Where gemini?</h2>
<p>
So that’s pretty much the whole story! If you’re interested in seeing this site
on gemini, you can grab a <a href="https://gemini.circumlunar.space/clients.html" title="">gemini client</a>, and start exploring the space. I
checked out Lagrange and found it quite lovely for desktop computers, and deedum
works great on android. I have some things to touch up on here and there, but
for now it is live. Please check it out, and let me know what you think!</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/this-blog-is-now-also-a-gemlog</id>
    <title>This blog is now (also) a gemlog</title>
    <updated>2022-02-09T02:20:59+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
Another multi-day combo post! I didn’t get to start day 8 until late, and
finished it with 10 minutes to spare. Thus, no time to write a post yesterday.</p>
<h2>
Day 8</h2>
<p>
These elves need to maintain their stuff more. It seems the whale problem has
left the seven-segment display <a href="https://adventofcode.com/2021/day/8" title="">busted</a>.</p>
<p>
Now… I know where this is going, and it’s going to be <em>awful</em>. Let’s play
along though, all we have to do is find all the easy digits.</p>
<p>
Parsing is a bit of a mess, so I’ll skip that. The end result is pretty simple
though:</p>
<pre><code class="ocaml">let find_easy list =
  List.filter
    (fun n -&gt;
      let len = String.length n in
      len = 2 || len = 4 || len = 3 || len = 7)
    list

let p1 =
  List.map (fun (_, o) -&gt; find_easy o) input
  |&gt; List.flatten |&gt; List.length |&gt; string_of_int</code></pre>
<p>
All I do is check to see if the length of the pattern matches the length of a 1,
4, 7, or 8, and count the number of times those appear.</p>
<p>
⭐ one done!</p>
<h3>
Part 2</h3>
<p>
<em>Of course</em> they want us to solve for all the wires.</p>
<p>
This code is a mess, so I’m just going to start at the top and work my way in.</p>
<pre><code class="ocaml">let group patterns =
  List.map
    (fun p -&gt;
      match String.length p with
      | 2 -&gt; (p, [ 1 ])
      | 3 -&gt; (p, [ 7 ])
      | 4 -&gt; (p, [ 4 ])
      | 5 -&gt; (p, [ 2; 3; 5 ])
      | 6 -&gt; (p, [ 0; 6; 9 ])
      | 7 -&gt; (p, [ 8 ])
      | _ -&gt; raise (BadPattern p))
    patterns

let initial_guess numbers map char =
  let pos =
    List.map
      (function
        | 0 -&gt; [ &#39;a&#39;; &#39;b&#39;; &#39;c&#39;; &#39;e&#39;; &#39;f&#39;; &#39;g&#39; ]
        | 1 -&gt; [ &#39;c&#39;; &#39;f&#39; ]
        | 2 -&gt; [ &#39;a&#39;; &#39;c&#39;; &#39;d&#39;; &#39;e&#39;; &#39;g&#39; ]
        | 3 -&gt; [ &#39;a&#39;; &#39;c&#39;; &#39;d&#39;; &#39;f&#39;; &#39;g&#39; ]
        | 4 -&gt; [ &#39;b&#39;; &#39;c&#39;; &#39;d&#39;; &#39;f&#39; ]
        | 5 -&gt; [ &#39;a&#39;; &#39;b&#39;; &#39;d&#39;; &#39;f&#39;; &#39;g&#39; ]
        | 6 -&gt; [ &#39;a&#39;; &#39;b&#39;; &#39;d&#39;; &#39;e&#39;; &#39;f&#39;; &#39;g&#39; ]
        | 7 -&gt; [ &#39;a&#39;; &#39;c&#39;; &#39;f&#39; ]
        | 8 -&gt; [ &#39;a&#39;; &#39;b&#39;; &#39;c&#39;; &#39;d&#39;; &#39;e&#39;; &#39;f&#39;; &#39;g&#39; ]
        | 9 -&gt; [ &#39;a&#39;; &#39;b&#39;; &#39;c&#39;; &#39;d&#39;; &#39;f&#39;; &#39;g&#39; ]
        | i -&gt; raise (BadNumber i))
      numbers
    |&gt; List.flatten
  in
  let possibilities = CharSet.of_list pos in
  CharMap.update char
    (function
      | None -&gt; Some possibilities
      | Some pos -&gt; Some (CharSet.inter pos possibilities))
    map

let rec construct map = function
  | [] -&gt; map
  | (pattern, numbers) :: rest -&gt;
      let chars = Core.String.to_list pattern in
      let m = List.fold_left (initial_guess numbers) map chars in
      construct m rest</code></pre>
<p>
First, I need to parse the values into something workable. I want to turn the
patterns into a map of sets. Each character in the patterns maps to a set
containing the possibilities of what that character could actually be, so for
the pattern <code class="inline">ab</code>, each character would point to <code class="inline">cf</code>, as they could be either
segment making up the 1.</p>
<p>
Once that’s done, just solve 🤷</p>
<p>
First, I need some code to actually check if the result I found is valid.</p>
<pre><code class="ocaml">let valid_patterns =
  [
    [ &#39;a&#39;; &#39;b&#39;; &#39;c&#39;; &#39;e&#39;; &#39;f&#39;; &#39;g&#39; ];
    [ &#39;c&#39;; &#39;f&#39; ];
    [ &#39;a&#39;; &#39;c&#39;; &#39;d&#39;; &#39;e&#39;; &#39;g&#39; ];
    [ &#39;a&#39;; &#39;c&#39;; &#39;d&#39;; &#39;f&#39;; &#39;g&#39; ];
    [ &#39;b&#39;; &#39;c&#39;; &#39;d&#39;; &#39;f&#39; ];
    [ &#39;a&#39;; &#39;b&#39;; &#39;d&#39;; &#39;f&#39;; &#39;g&#39; ];
    [ &#39;a&#39;; &#39;b&#39;; &#39;d&#39;; &#39;e&#39;; &#39;f&#39;; &#39;g&#39; ];
    [ &#39;a&#39;; &#39;c&#39;; &#39;f&#39; ];
    [ &#39;a&#39;; &#39;b&#39;; &#39;c&#39;; &#39;d&#39;; &#39;e&#39;; &#39;f&#39;; &#39;g&#39; ];
    [ &#39;a&#39;; &#39;b&#39;; &#39;c&#39;; &#39;d&#39;; &#39;f&#39;; &#39;g&#39; ];
  ]

let is_number pattern result =
  let num = List.map (fun x -&gt; CharMap.find x result) pattern in
  List.exists (fun n -&gt; List.for_all (fun x -&gt; List.mem x num) n) valid_patterns

let result map =
  CharMap.bindings map
  |&gt; List.map (fun (k, v) -&gt; (k, List.hd (CharSet.elements v)))
  |&gt; List.to_seq |&gt; CharMap.of_seq

let check_patterns patterns map =
  let r = result map in
  List.for_all (fun p -&gt; is_number p r) patterns

let solved patterns map =
  if
    CharMap.for_all (fun _ v -&gt; CharSet.cardinal v = 1) map
    &amp;&amp; check_patterns patterns map
  then Some (result map)
  else None</code></pre>
<p>
Here, each map needs to be pointing to a single character, <em>and</em> I check to make
sure each number is possible given the mapping I’ve found.</p>
<p>
Next, I need some code that actually comes up with a solution:</p>
<pre><code class="ocaml">let rec solver patterns map =
  match
    CharMap.bindings map |&gt; List.filter (fun (_, v) -&gt; CharSet.cardinal v &lt;&gt; 1)
  with
  | [] -&gt; solved patterns map
  | ms -&gt;
      let key, guesses =
        List.fold_left
          (fun (k1, g1) (k2, g2) -&gt;
            if
              CharSet.cardinal g1 &lt; CharSet.cardinal g2
              &amp;&amp; CharSet.cardinal g1 &lt;&gt; 1
            then (k1, g1)
            else (k2, g2))
          (List.hd ms) (List.tl ms)
      in
      List.find_map
        (fun c -&gt;
          let new_map =
            CharMap.mapi
              (fun k v -&gt;
                if k = key then CharSet.singleton c else CharSet.remove c v)
              map
          in
          match solver patterns new_map with None -&gt; None | Some m -&gt; Some m)
        (CharSet.elements guesses)</code></pre>
<p>
Okay, here we go. First, I only want all the “not solved” characters. If I don’t
have any “not solved” characters, I have a solution! I check if it is correct.</p>
<p>
If I’m not done yet… I find the “most solved” character. The one with the
least number of options.</p>
<p>
Once I pick one, for each of its possible solutions, I construct a state
assuming I am correct.</p>
<p>
I take that possible solution and pass it back into my solver function. This
continues until the first conditional is met and I check if I am right. If not,
I construct a state with the next possible solution. Eventually, I am right.</p>
<p>
The rest of the code is taking the solution, decoding the output, and finding
the final answer:</p>
<pre><code class="ocaml">let decode_code result code =
  let pattern = List.map (fun x -&gt; CharMap.find x result) code in
  let numbers = List.mapi (fun i n -&gt; (i, n)) valid_patterns in
  List.find_map
    (fun (i, n) -&gt;
      if
        List.length pattern = List.length n
        &amp;&amp; List.for_all (fun x -&gt; List.mem x n) pattern
      then Some i
      else None)
    numbers

let decode codes result =
  codes |&gt; List.map Core.String.to_list |&gt; List.map (decode_code result)

let compute patterns codes =
  let map = patterns |&gt; group |&gt; construct CharMap.empty in
  let p = List.map Core.String.to_list patterns in
  match solver p map with
  | None -&gt; [ None ]
  | Some result -&gt; decode codes result

let p2 =
  List.fold_left
    (fun s (patterns, codes) -&gt;
      let r = compute patterns codes in
      let n =
        List.map
          (function
            | None -&gt; raise (BadPattern &quot;BLAH&quot;)
            | Some i -&gt; char_of_int (i + zero))
          r
        |&gt; Core.String.of_char_list
      in
      int_of_string n + s)
    0 input
  |&gt; string_of_int</code></pre>
<p>
That’s day eight ✔️</p>
<h2>
Day 9</h2>
<p>
Today was slightly easier, thankfully. This isn’t being written 10 minutes to
midnight.</p>
<p>
It turns out those case are lava tubes. <a href="https://adventofcode.com/2021/day/9" title=""><em>yay</em></a>.</p>
<p>
The first problem is to find the lowest points of the caves, to avoid the smoke
easier. I must find all the points where each adjacent point is higher.</p>
<p>
Once parsing the output is out of the way, the solution is simple:</p>
<pre><code>type coords = int * int

module Coords = struct
  type t = coords

  let compare (x1, y1) (x2, y2) =
    if x1 &lt; x2 then -1
    else if x1 &gt; x2 then 1
    else if y1 &lt; y2 then -1
    else if y1 &gt; y2 then 1
    else 0
end

module TupleMap = Map.Make (Coords)

let parse =
  let width = List.hd input |&gt; List.length in
  let height = List.length input in
  let with_index =
    List.mapi (fun i r -&gt; (i, List.mapi (fun j c -&gt; (j, c)) r)) input
  in
  ( width,
    height,
    List.fold_left
      (fun m (i, r) -&gt;
        List.fold_left (fun n (j, c) -&gt; TupleMap.add (i, j) c n) m r)
      TupleMap.empty with_index )

let low_points (width, height, map) =
  TupleMap.filter
    (fun (i, j) c -&gt;
      let n = if i = 0 then 9 else TupleMap.find (i - 1, j) map in
      let s = if i = height - 1 then 9 else TupleMap.find (i + 1, j) map in
      let w = if j = 0 then 9 else TupleMap.find (i, j - 1) map in
      let e = if j = width - 1 then 9 else TupleMap.find (i, j + 1) map in
      c &lt; n &amp;&amp; c &lt; s &amp;&amp; c &lt; e &amp;&amp; c &lt; w)
    map

let p1 =
  let results = low_points parse in
  TupleMap.fold (fun _ c sum -&gt; c + 1 + sum) results 0 |&gt; string_of_int</code></pre>
<p>
I take the integers and put them into a map where the coordinate of the point
points to the height of the point. Then, I filter through all the points,
checking for bounds, and ensuring all adjacent points are higher. Once the lower
points are found, I calculate the “total risk value”.</p>
<p>
⭐ one done!</p>
<h3>
Part 2</h3>
<p>
Oh, so the low points make up basins. I think it’s pretty amazing how they
manage to create the input required for these problems. A basin is a group of
points bordered by the boundary or the highest point (a <code class="inline">9</code>).</p>
<p>
Good thing I have code that already finds the lowest points! I’m going to need a
set to better keep track of what is in the basin, but the rest didn’t take too
much to work out:</p>
<pre><code class="ocaml">module TupleSet = Set.Make (Coords)

let rec find_basin width height m (i, j) acc =
  if TupleMap.find (i, j) m = 9 then acc
  else if TupleSet.mem (i, j) acc then acc
  else
    let new_acc = TupleSet.add (i, j) acc in
    let n =
      if i &lt;&gt; 0 then find_basin width height m (i - 1, j) new_acc else new_acc
    in
    let s =
      if i + 1 &lt; height then find_basin width height m (i + 1, j) n else n
    in
    let w = if j &lt;&gt; 0 then find_basin width height m (i, j - 1) s else s in
    let e =
      if j + 1 &lt; width then find_basin width height m (i, j + 1) w else w
    in
    TupleSet.union n (TupleSet.union s (TupleSet.union w e))

let basins =
  let w, h, m = parse in
  let finder = find_basin w h m in
  let low = low_points (w, h, m) in
  TupleMap.mapi (fun (i, j) _ -&gt; finder (i, j) TupleSet.empty) low

let p2 =
  let results = basins in
  TupleMap.fold (fun _ v m -&gt; TupleSet.cardinal v :: m) results []
  |&gt; List.sort (fun x y -&gt; y - x)
  |&gt; List.filteri (fun i _ -&gt; i &lt; 3)
  |&gt; List.fold_left (fun x y -&gt; x * y) 1
  |&gt; string_of_int</code></pre>
<p>
For each of the lowest points, I recursively map out the area surrounding the
point, adding it to the set containing all the points of the basin. If I hit a
boundary or a ‘9’, I stop.</p>
<p>
Once all the basins are found, the solution is a matter of finding the 3
biggest, and finding the product of them.</p>
<p>
I think problems like this one are a lot of fun. It’s a great use of recursion,
and a set makes it easy to keep track of where I’ve visited.</p>
<p>
Solvers like in day 8 are fun, too, but it makes such a mess of code. I am sure
it could be cleaner somehow, but 10 minutes to midnight is not the time for
cleanup 😅</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/advent-of-code-2021-day-8-9</id>
    <title>Advent of Code 2021: Day 8 &amp; 9</title>
    <updated>2021-12-10T04:02:01+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<blockquote>
  <p>
A giant whale has decided your submarine is its next meal, and it’s much
faster than you are. There’s nowhere to run!  </p>
</blockquote>
<p>
Thanks to the help of some crabs, we’ll get <a href="https://adventofcode.com/2021/day/7" title="">past that whale</a>!</p>
<p>
This seems like a great job for simply brute-forcing the whole thing. I am sure
there is a way to utilize a <a href="https://www.khanacademy.org/computing/computer-science/algorithms/binary-search/a/binary-search" title="">binary search</a> to find the answer, but I’m also
sure I’m in no mood to figure it out. Part one is still pretty small:</p>
<pre><code class="ocaml">let p1_sol crabs =
  List.fold_left
    (fun min_fuel pos -&gt;
      let new_fuel =
        List.fold_left (fun x y -&gt; max y pos - min y pos + x) 0 crabs
      in
      if new_fuel &lt; min_fuel then new_fuel else min_fuel)
    Int.max_int crabs

let p1 =
  let sol = p1_sol input in
  Int.to_string sol</code></pre>
<p>
Once again I <code class="inline">fold_left</code> over all the crabs, calculating the fuel cost for the
rest of the crabs, and finding the smallest total.</p>
<p>
⭐ one done!</p>
<h2>
Part two</h2>
<p>
Part two seems trickier at first. The idea of adding up all those numbers is
supposed to scare you. We both know there is a formula for calculating a <a href="https://en.wikipedia.org/wiki/Summation" title="">sum of
numbers</a> though: <code class="inline">n * (n + 1) / 2</code></p>
<p>
That’s really it!</p>
<p>
The answer is the exact same as part one, but with the summation formula filled
in instead. I had to be a little more thorough and calculate the minimum for all
the possible positions, but no difference otherwise:</p>
<pre><code class="ocaml">let p2_sol positions crabs =
  List.fold_left
    (fun min_fuel pos -&gt;
      let new_fuel =
        List.fold_left
          (fun x y -&gt;
            let n = max y pos - min y pos in
            if n = 0 then x else (n * (n + 1) / 2) + x)
          0 crabs
      in
      if new_fuel &lt; min_fuel then new_fuel else min_fuel)
    Int.max_int positions

let p2 =
  let crabs = input in
  let min, max =
    List.fold_left
      (fun (x, y) z -&gt;
        let new_x = if z &lt; x then z else x in
        let new_y = if z &gt; y then z else y in
        (new_x, new_y))
      (Int.max_int, 0)
      crabs
  in
  let positions = List.init (max - min) (fun x -&gt; x + min) in
  let sol = p2_sol positions crabs in
  Int.to_string sol</code></pre>
<p>
I could have squeezed a bit more efficiency out of things if I had used
a binary search, but I didn’t really need it here.</p>
<p>
That’s it for today! I’m excited to see what tomorrow’s challenge will be!</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/advent-of-code-2021-day-7</id>
    <title>Advent of Code 2021: Day 7</title>
    <updated>2021-12-08T03:07:46+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
I’ve been busy so this is going to be a bit longer but also contain 3 whole
solutions!</p>
<h2>
Day four</h2>
<p>
Diving deeper and deep, we come across <a href="https://adventofcode.com/2021/day/4" title="">a giant squid</a>! To distract it, we
decide to play bingo.</p>
<p>
An important rule to this game of bingo is that diagonals <em>don’t count</em>, and
don’t need to be considered. I am given a set of calls and boards, and need to
figure out which board will win first.</p>
<p>
Step one is parsing the input. The first line contains the calls for the game,
and the rest of the file consists of separate boards. As I want to be able to
keep track if whether or not a number has been called, I make a type to hold
that information. Then, I split up the file to the different boards:</p>
<pre><code class="ocaml">exception Empty

type i = Marked of int | Unmarked of int

let add_to_board line = function
  | [] -&gt; [ [ line ] ]
  | last :: rest -&gt; (line :: last) :: rest

let parse_line line =
  String.split_on_char &#39; &#39; line
  |&gt; List.filter (fun s -&gt; s &lt;&gt; &quot;&quot;)
  |&gt; List.map (fun s -&gt; Unmarked (int_of_string s))

let input =
  match Core.In_channel.read_lines &quot;./priv/2021/D04&quot; with
  | [] -&gt; raise Empty
  | calls :: rest -&gt;
      let boards =
        List.fold_left
          (fun b l -&gt;
            match l with
            | &quot;&quot; | &quot;\n&quot; -&gt; [] :: b
            | line -&gt; add_to_board (parse_line line) b)
          [ [] ] rest
  |&gt; List.filter (fun x -&gt; x &lt;&gt; [])
      in
      let numbers = List.map int_of_string (String.split_on_char &#39;,&#39; calls) in
      (numbers, boards)</code></pre>
<p>
My type <code class="inline">i</code> indicates whether or not a number has been marked. Because ocaml
requires exhaustive pattern matching, I have to make sure my list of lines from
the file is not empty. Then, I pull the first line out with pattern matching
(noted as <code class="inline">calls</code> here), and fold over the rest of the list to construct the
boards. There are a few empty lines in there that need to be filtered out.
Finally, I split the calls on commas, and parse those strings into proper
numbers.</p>
<p>
Part one just requires I play the game on all the boards. There are some small
helper functions I need first:</p>
<pre><code class="ocaml">let check_wins board =
  let row_win =
    List.exists
      (fun row -&gt;
        List.for_all
          (fun m -&gt; match m with Marked _ -&gt; true | Unmarked _ -&gt; false)
          row)
      board
  in
  let column_win =
    List.exists
      (fun i -&gt;
        List.for_all
          (fun row -&gt;
            match List.nth row (i - 1) with Marked _ -&gt; true | Unmarked _ -&gt; false)
          board)
      (List.init (List.length (List.nth board 0)) (fun x -&gt; x + 1))
  in
  row_win || column_win

let mark i board =
  List.map
    (fun row -&gt;
      List.map
        (fun x -&gt; match x with Unmarked y when y = i -&gt; Marked y | y -&gt; y)
        row)
    board</code></pre>
<p>
<code class="inline">check_wins</code> checks to see if any row or column has been completely marked, and
<code class="inline">mark</code> updates the board to set a number to <code class="inline">Marked</code> if it is found.</p>
<p>
All that is left is to play and compute the score:</p>
<pre><code>let compute_score board call =
  let sum =
    List.fold_left
      (fun sum row -&gt;
        List.fold_left
          (fun s x -&gt; match x with Marked _ -&gt; s | Unmarked y -&gt; s + y)
          sum row)
      0 board
  in
  call * sum

let rec play boards = function
  | [] -&gt; -100
  | call :: rest -&gt; (
      let marks = mark call in
      let b = List.map marks boards in
      match List.find_opt check_wins b with
      | None -&gt; play b rest
      | Some board -&gt; compute_score board call)

let p1 =
  let calls, boards = input in
  play boards calls |&gt; string_of_int</code></pre>
<p>
<code class="inline">play</code> recursively iterates over the called numbers, marking boards until a
winner is found. It returns the score of <code class="inline">-100</code> if I run out of numbers make it
obvious (while still an integer) that something went wrong. While not the best
error handling method, it works for such a small script. For more complicated
problems later on, I plan on looking to <a href="https://keleshev.com/composable-error-handling-in-ocaml" title="">Vladimir Keleshev’s Composable Error
Handling in OCaml</a> for guidance.</p>
<p>
Once a winner is found, the score is computed. ⭐ one done!</p>
<h3>
Part two</h3>
<p>
Part two is a small extension to part one, which suggests that I should pick the
board that will win last to ensure the squid wins and won’t crush us for losing.
As such, it only requires some small extension.</p>
<pre><code class="ocaml">
let rec play boards = function
  | [] -&gt; -100
  | call :: rest -&gt; (
      let marks = mark call in
      let new_boards = List.map marks boards in
      match new_boards with
      | [] -&gt; -100
      | [b] -&gt; if check_wins b then compute_score b call else play [b] rest
      | boards -&gt; let losers = List.filter (fun b -&gt; not (check_wins b)) boards in
          play losers rest)


let p2 =
  let calls, boards = input in
  play boards calls |&gt; string_of_int
</code></pre>
<p>
Instead of stopping as soon as a winner is found, I continue until only one
board is left to win.</p>
<p>
That’s day four ✔️</p>
<h2>
Day 5</h2>
<p>
Every year involves at least one problem about interesting lines. Every one of
them is a pain to solve.</p>
<p>
This year, the submarine is <a href="https://adventofcode.com/2021/day/5" title="">avoiding large, opaque clouds</a> spewing out of
hydrothermal vents on the ocean floor. Fortunately for us, the vents exist in
extremely straight lines.</p>
<p>
I first attempted to do this the mathematically clever way using the
<a href="https://en.wikipedia.org/wiki/Determinant" title="">determinant</a> of the two lines and solving for their intersection point, if
any, but that turned into a total bust that I could not puzzle out and so I
shall speak no more of it.</p>
<p>
Instead, it was simply easier to walk the line segments and remember all the
points I’ve been.</p>
<p>
OCaml handles generic data structures such as maps and sets via a
<a href="https://dev.realworldocaml.org/functors.html" title=""><em>functor</em></a>, which is a function that takes and returns a module instead of
normal values. To make a set module, the functor <code class="inline">Set.Make</code> is used. <code class="inline">Set.Make</code>
takes a module that specifies a type, <code class="inline">t</code>, and a function to compare values,
<code class="inline">compare</code>. This is a module <em>type</em> named <code class="inline">OrderedType</code>, where <code class="inline">t</code> is the type to
order, and <code class="inline">compare</code> lets us order them. I set up a set to track the points I’ve
been as so:</p>
<pre><code class="ocaml">type point = Point of int * int

module PointSet = Set.Make (struct
  type t = point

  let compare (Point (x1, y1)) (Point (x2, y2)) =
    if x1 &lt; x2 then -1
    else if x1 = x2 then if y1 &lt; y2 then -1 else if y1 = y2 then 0 else 1
    else 1
end)</code></pre>
<p>
<code class="inline">compare</code> returns <code class="inline">-1</code> if the first point has a smaller <code class="inline">x</code> value, <code class="inline">1</code> if a larger
<code class="inline">x</code> value, and defers to the <code class="inline">y</code> value if equal. If both are equal, <code class="inline">0</code> is
returned. This is how the set knows if it already has the given point.</p>
<p>
I also need a line type to keep track of all my points:</p>
<pre><code class="ocaml">type line = Line of point * point</code></pre>
<p>
As the first problem only requires I deal with horizontal and vertical lines,
that should be quick to set up:</p>
<pre><code class="ocaml">let is_vertical (Line (Point (_, y1), Point (_, y2))) = y1 = y2

let is_horizontal (Line (Point (x1, _), Point (x2, _))) = x1 = x2

let is_p1 line = is_vertical line || is_horizontal line</code></pre>
<p>
All that’s left is to walk the lines:</p>
<pre><code class="ocaml">let walk_line acc (Line (Point (x1, y1), Point (x2, y2))) =
  let points =
    if x1 = x2 then
      List.init (abs (y2 - y1) + 1) (fun y -&gt; Point (x1, min y1 y2 + y))
    else
      List.init (abs (x2 - x1) + 1) (fun x -&gt; Point (min x1 x2 + x, y1))
  in
  List.fold_left
    (fun (s1, s2) point -&gt;
      if PointSet.mem point s1 then (s1, PointSet.add point s2)
      else (PointSet.add point s1, s2))
    acc points

let walk_lines lines =
  List.fold_left walk_line (PointSet.empty, PointSet.empty) lines

let p1 =
  let _, points = input |&gt; List.filter is_p1 |&gt; walk_lines in
  points |&gt; PointSet.elements |&gt; List.length |&gt; string_of_int</code></pre>
<p>
<code class="inline">walk_line</code> makes a list covering every point contained in the line, and then
adds them to the visited set. If the point is already in the visited set, it is
added to the final set, as it matches our criteria.</p>
<p>
<code class="inline">walk_lines</code> iterates over all the lines, until the final set of points is found.</p>
<p>
⭐ one done!</p>
<h3>
Part two</h3>
<p>
Part two, again, is only a small extension of part one. It demands we include
the diagonal lines to check as well. Simple enough to add to <code class="inline">walk_line</code></p>
<pre><code class="ocaml">let walk_line acc (Line (Point (x1, y1), Point (x2, y2))) =
  let points =
    if x1 = x2 then
      List.init (abs (y2 - y1) + 1) (fun y -&gt; Point (x1, min y1 y2 + y))
    else if y1 = y2 then
      List.init (abs (x2 - x1) + 1) (fun x -&gt; Point (min x1 x2 + x, y1))
    else
      List.init
        (abs (x2 - x1) + 1)
        (fun z -&gt;
          let x = if x1 &lt; x2 then x1 + z else x1 - z in
          let y = if y1 &lt; y2 then y1 + z else y1 - z in
          Point (x, y))
  in
  List.fold_left
    (fun (s1, s2) point -&gt;
      if PointSet.mem point s1 then (s1, PointSet.add point s2)
      else (PointSet.add point s1, s2))
    acc points</code></pre>
<p>
The <code class="inline">else</code> expression now knows how to follow along a diagonal! Then to just run
<code class="inline">walk_lines</code> on the whole dataset and count up the points:</p>
<pre><code class="ocaml">let p2 =
  let _, points = input |&gt; walk_lines in
  points |&gt; PointSet.elements |&gt; List.length |&gt; string_of_int</code></pre>
<p>
That’s day five ✔️</p>
<h2>
Day six</h2>
<p>
Day six requires we do some <a href="https://adventofcode.com/2021/day/6" title="">biological work</a> by counting fish.</p>
<p>
Part one is simple enough, so let’s write some code for it:</p>
<pre><code class="ocaml">let rec grow_fish old_fish new_fish = function
  | [] -&gt; List.rev_append old_fish new_fish
  | h :: rest -&gt;
      if h = 0 then grow_fish (6 :: old_fish) (8 :: new_fish) rest
      else grow_fish ((h - 1) :: old_fish) new_fish rest

let p1_sol input count =
  List.init count (fun x -&gt; x + 1)
  |&gt; List.fold_left (fun fish _ -&gt; grow_fish [] [] fish) input

let p1 =
  let sol = p1_sol input 80 |&gt; List.length in
  Int.to_string sol</code></pre>
<p>
For 80 iterations, I go through the list of fish, decrementing the days til
spawn. Once it hits 0, I bump it back up to 6 and add a new fish with a
countdown starting at 8. All that’s left is to count up the fish!</p>
<p>
⭐ one done!</p>
<h3>
Part two</h3>
<p>
I was hopeful I could just run my code for 256 days, but soon realized why it
was a “part two”: bottlenecks and stack overflows.</p>
<p>
The list was growing so much that my original solution to part one (not posted)
would blow up with a stack overflow. The one posted above is <a href="https://en.wikipedia.org/wiki/Tail_call" title="">tail-call
optimized</a>, as I thought it would be my only issue. Turns out, it was also
growing so much that <em>iterating</em> through the list for ever day took <em>ages</em>.</p>
<p>
Back to the drawing board.</p>
<p>
I had noticed a lot of the fish ended up on the same cycle. There were <em>several</em>
fish that each had 0 to 8 days left on their spawn timers, which got me
thinking… if I could group the fish, I wouldn’t have to add to the list and
instead just increment the count!</p>
<p>
I initially started off trying to make a map to handle this, but as I don’t
quite understand how ocaml’s maps worked, it was easier for me to use a list of
tuples instead. I also needed to be able to update both the key and the value,
so a tuple felt better.</p>
<pre><code class="ocaml">let update x up list = up (List.find_opt (fun (y, _) -&gt; x = y) list)

let dedup list =
  List.fold_left
    (fun deduped (x, z) -&gt;
      update x
        (function
          | None -&gt; (x, z) :: deduped
          | Some (_, y) -&gt; (x, y + z) :: List.filter (fun (a, _) -&gt; x &lt;&gt; a) deduped)
        deduped)
    [] list

let grow_fish_2 fishes _ =
  List.fold_left
    (fun fish (x, y) -&gt;
      match x with 0 -&gt; (6, y) :: (8, y) :: fish | z -&gt; (z - 1, y) :: fish)
    [] fishes
  |&gt; dedup

let p2_sol (input : int list) count =
  let fishes =
    List.fold_left
      (fun fishes x -&gt;
        update x
          (function
            | None -&gt; (x, 1) :: fishes
            | Some (_, y) -&gt;
                (x, y + 1) :: List.filter (fun (y, _) -&gt; x &lt;&gt; y) fishes)
          fishes)
      [] input
  in
  List.init count (fun x -&gt; x + 1)
  |&gt; List.fold_left grow_fish_2 fishes
  |&gt; List.fold_left (fun sum (_, x) -&gt; sum + x) 0</code></pre>
<p>
<code class="inline">update</code> replicates map’s <code class="inline">update</code> function, where you provide a function that
takes an option type. The option type either contains the value the key is
pointing to, or nothing, and you must handle both cases. <code class="inline">dedup</code> takes all the
elements and buckets and merges the matching ones together again.</p>
<p>
<code class="inline">grow_fish_2</code>, then, goes over the list of fish, decrementing the number of days
til they spawn. If they are 0, the number gets bumped back up to 6, <em>and</em> a new
tuple of fish is added. This tuple starts at 8, their spawn countdown, and the
same number of fish as was in the first bucket. Once that is complete, I <code class="inline">dedup</code>
the buckets, as it was easier to <code class="inline">dedup</code> the list once the fish spawning was
done.</p>
<p>
I repeat this for the 256 days to get… <code class="inline">1.73e12</code> fish!</p>
<p>
That’s a lot of fish!</p>
<p>
I’m trying to stay on top of these posts this year, but the weekends are hectic,
as usual. I hope to not have to cram 3 days of updates in one day again though!</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/advent-of-code-days-4-5-6</id>
    <title>Advent of Code: Days 4, 5, 6</title>
    <updated>2021-12-07T04:51:56+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
Okay, the submarine is moving, we can see where we’re going. Now to make
sure <a href="https://adventofcode.com/2021/day/3" title="">systems are ✔</a>.</p>
<p>
Today’s struggle in learning was motivation. Fridays are tricky that
way, sometimes it’s a mad rush to get everything done in time for
Saturday, others it’s just a slog to the weekend. Today was the latter.</p>
<p>
I found the first problem’s trickiest bit to be how to parse the list
properly. Only after eating dinner and not being distracted by hunger
did the solution become obvious.</p>
<h2>
Parsing blues</h2>
<p>
First, I make a bit type:</p>
<pre><code class="ocaml">(* bits are one or zero *)
type bit = One | Zero

(* parse a character into a bit *)
let bit_of_char c =
  match c with &#39;1&#39; -&gt; One | &#39;0&#39; -&gt; Zero | c -&gt; raise (BadBit c)

(* turn a bit into a string for combining later *)
let string_of_bit b =
  match b with
  | One -&gt; &quot;1&quot;
  | Zero -&gt; &quot;0&quot;

(* take a list of bits and turn that into a number *)
let int_of_bit r =
  List.fold_left (fun b x -&gt; b ^ (string_of_bit x)) &quot;0b&quot; r
  |&gt; int_of_string
</code></pre>
<p>
Next, I map the list of codes from the rows to the columns:</p>
<pre><code class="ocaml">let input =  Core.In_channel.read_lines &quot;./priv/2021/D03&quot;
                |&gt; List.map (fun row -&gt; List.map bit_of_char (Core.String.to_list row))

let p1_input =
  match input with
  | [] -&gt; raise (BadBit &#39;l&#39;)
  | hd :: t -&gt; List.fold_left (fun result row -&gt;
      List.map2 (fun r bit -&gt;  bit :: r) result row) (List.map (fun x -&gt; [x]) hd) t
</code></pre>
<p>
Ocaml has the lovely <code class="inline">map2</code> function to map 2 lists together. I inject
the first row, split into lists of single bits, to start the rows off.
Then, I fold over the rest of the rows, adding each character to the
list in the correct column. The end result:</p>
<pre><code>[1, 2, 3]         [1, 4, 7]
[4, 5, 6] becomes [2, 5, 8]
[7, 8, 9]         [3, 6, 9]</code></pre>
<p>
The rest of the problem is simple. Mark the most common bit in each
column, and multiply the resulting final numbers together:</p>
<pre><code class="ocaml">let counts row =
  List.fold_left
    (fun (one, zero) b -&gt;
      match b with One -&gt; (one + 1, zero) | Zero -&gt; (one, zero + 1))
    (0, 0) row

let greatest_bit (one, zero) = if one &gt;= zero then One else Zero

let p1_sol input =
  let g, e =
    List.fold_left
      (fun (g, e) row -&gt;
        let c = counts row in
        match greatest_bit c with
        | One -&gt; (g ^ &quot;1&quot;, e ^ &quot;0&quot;)
        | Zero -&gt; (g ^ &quot;0&quot;, e ^ &quot;1&quot;))
      (&quot;0b&quot;, &quot;0b&quot;) input
  in
  (int_of_string g, int_of_string e)

let p1 =
  let g, e = p1_sol p1_input in
  let sol = g * e in
  Int.to_string sol</code></pre>
<p>
⭐ one done!</p>
<h2>
Problem 2</h2>
<p>
Problem 2, while similar, certainly starts to raise the difficultly. I
fear for the weekend challenges now!</p>
<p>
In essence, I am seeking for a specific row. That row needs to match a
set of rules, where, for one, we chase the most common bit, and the
other, the least common. It took me a few re-reads before I understood
the problem at hand. This one is fun, in that there’s a good amount of
re-usable code between both seeking:</p>
<pre><code class="ocaml">let consider f input =
  let firsts = List.map (fun r -&gt; match r with
      | ([], _) -&gt; raise (BadBit &#39;l&#39;)
      | (h :: _, _) -&gt; h) input in
  let bit = greatest_bit (counts firsts) in
  List.filter (fun r -&gt; match r with
      | ([], _) -&gt; raise (BadBit &#39;l&#39;)
      | (h :: _, _) -&gt; f bit h) input
  |&gt; List.map (fun (r, i) -&gt; match r with
      | [] -&gt; raise (BadBit &#39;c&#39;)
      | _ :: t -&gt; (t, i))

let oxygen bit h = bit = h

let co2 bit h = bit &lt;&gt; h

let rec find crit input =
  match input with
  | [] -&gt; -1
  | [(_, x)] -&gt; x
  | list -&gt; let results = consider crit list in find crit results

let compute input crit =
  let i = List.mapi (fun x r -&gt; (r, x)) input in
  find crit i
  |&gt; List.nth input
  |&gt; int_of_bit

let p2_sol input =
  let co2_result = compute input co2 in
  let oxygen_result = compute input oxygen in
  string_of_int (co2_result * oxygen_result)

let p2 = p2_sol input</code></pre>
<p>
<code class="inline">find</code> is the main entry point into the interesting stuff. It
recursively seeks the index of the row that matches the specific
criteria. <code class="inline">consider</code> takes the criteria, puts together the first column
of numbers, and determines which rows make the cut. It also lops off the
considered column, so the recursive <code class="inline">find</code> call eventually goes through
all the columns. The criteria are encoded as <code class="inline">oxygen</code> (the most common
bit) and <code class="inline">co2</code> (the least common bit). Once the right index is found,
its full row is retrieved and parsed into a number to find the final
solution.</p>
<p>
This one I found the parsing to be the most painful part. Once I was
over that hurdle, it was smooth sailing. Eventually I hit a few bumps.
There’s an extra rule in part 2 where <code class="inline">One</code> wins tie breakers for the
most common bit that I missed, and it took some puzzling to realize I
<em>wasn’t</em> lopping off the column in the beginning. Once those two issues
were caught, the ⭐ was mine.</p>
<p>
Now if you’ll excuse me, Day 4 just unlocked, and I better see how much
of a crunch my weekend will be.</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/advent-of-code-2021-day-3</id>
    <title>Advent of Code 2021: Day 3</title>
    <updated>2021-12-04T05:12:41+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
Now that I know where I am going, I get to figure out how to <a href="https://adventofcode.com/2021/day/2" title="">pilot the
submarine!</a> The first puzzle is perfect for <code class="inline">List.fold_left</code>:</p>
<pre><code class="ocaml">let follow_instruction (x, y) (dir, num)   match dir with
  | &quot;up&quot; -&gt; (x, y - num)
  | &quot;down&quot; -&gt; (x, y + num)
  | &quot;forward&quot; -&gt; (x + num, y)
  | direction -&gt; raise (Direction direction)

let p1_sol input   let x, y = List.fold_left follow_instruction (0, 0) input in
  x * y</code></pre>
<p>
I just match on the direction I am going and increment the correct
direction.  All that’s left is to compute the answer (multiply the
coordinates together).</p>
<p>
If I just match on the four directions, <code class="inline">up</code>, <code class="inline">down</code>, <code class="inline">forward</code>, then
ocaml complains that the match is not fully matched. Its type system
does not allow for uncaught matches, which are dependent on the type of
the variable. Here, the uncaught matches are literally every string of
characters that isn’t one of the directions. The <em>correct</em> answer is to
parse these directions into a variant, a plain symbol-thing that is a
specific set of options: <code class="inline">Up | Down | Forward</code>, and lift this error up
to where I parse the line. I didn’t do that though, so I have to check
it here and throw if it is incorrect. As I feel <em>very</em> confident here
that it would not be, I think I am pretty safe.</p>
<p>
☆ one done!</p>
<h2>
Part 2</h2>
<p>
Ah! Turns out I was interpreting the instructions wrong. It isn’t
exactly up or down, but changing the aim of the submarine up or down.
This is a pretty simple adjustment, all I have to do is add the aim to
the result tuple to keep track of it:</p>
<pre><code class="ocaml">let follow_instruction_2 (x, y, a) (dir, num)   match dir with
  | &quot;up&quot; -&gt; (x, y, a - num)
  | &quot;down&quot; -&gt; (x, y, a + num)
  | &quot;forward&quot; -&gt; (x + num, y + (a * num), a)
  | direction -&gt; raise (Direction direction)

let p2_sol input   let x, y, _ = List.fold_left follow_instruction_2 (0, 0, 0) input in
  x * y</code></pre>
<p>
The same problem as above, I should be using variants. We can see though
that just adjusting the aim to handle the new up and down (adjust the
nose by the number) and forward (now including the submarine’s current
aim multiplied by how far forward). When I compute the value, because I
don’t use the aim, I use the <code class="inline">_</code> variable to note that the variable is
not used.</p>
<p>
Hopefully now the submarine is on the way to find those keys!</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/advent-of-code-2021-day-2</id>
    <title>Advent of Code 2021, Day 2</title>
    <updated>2021-12-03T03:14:57+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
Ah, it has begun! The <a href="https://adventofcode.com/2021/day/1" title="">story this year</a> is pretty good:</p>
<blockquote>
  <p>
You’re minding your own business on a ship at sea when the overboard alarm
goes off! You rush to see if you can help. Apparently, one of the Elves
tripped and accidentally sent the sleigh keys flying into the ocean!  </p>
</blockquote>
<p>
Of course, our first instinct is to climb into the handy to have submarine and
get to work! The puzzle input is a list of numbers, each measuring the depth of
the water. First, I need to calculate the (rough) rate of change by counting the
number of times the depth increases.</p>
<p>
This is a pretty simple job for some quick recursion!</p>
<pre><code class="ocaml">let rec p1_sol input count   match input with
  | []
  | [ _ ] -&gt; count
  | h1 :: h2 :: t -&gt;
      if h1 &lt; h2 then p1_sol (h2 :: t) (count + 1) else p1_sol (h2 :: t) count</code></pre>
<p>
Here, <code class="inline">input</code> is the list of numbers and <code class="inline">count</code> is how often it has increased.
I match on the full list to see if there are at least 2 elements, so I can
compare them. If the second is higher, I increment the count by one. I pass the
rest of the list, including the second element, back to my function to compare
it to the next element and so on until the list is processed, and all in one
pass!</p>
<p>
I find it interesting that recursive functions in ocaml must explicitly be
marked as recursive with the <code class="inline">rec</code> tag. This goes for mutually recursive
functions, too! They use <code class="inline">rec</code> and <code class="inline">and</code> to indicate that one may call the other
and vice versa. I am not sure why this is, but I assume it is to indicate to the
compiler that, while <code class="inline">p1_sol</code> doesn’t exist <em>yet</em>, it is currently being defined
and don’t worry too much.</p>
<p>
⭐ one done!</p>
<h2>
Problem 2</h2>
<p>
It turns out that the first result is too noisy, and that by taking the sum of
3 elements as a sliding window would help a lot more. This helps to understand
trends better in situations where individual data points vary wildly. This
requires a slight modification to the original solution, but not by much.</p>
<pre><code class="ocaml">let rec p2_sol input count   match input with
  | []
  | [ _ ]
  | [ _; _ ]
  | [ _; _; _ ] -&gt; count
  | h1 :: h2 :: h3 :: h4 :: t -&gt;
      if h1 + h2 + h3 &lt; h2 + h3 + h4 then
        p2_sol (h2 :: h3 :: h4 :: t) (count + 1)
      else p2_sol (h2 :: h3 :: h4 :: t) count</code></pre>
<p>
Instead of grabbing the first 2 elements, the first 4 are required. The
rest is the same. I sum the windows, compare them, and increment if
necessary. Only the first element is discarded, so the windows slide
smoothly over the list.</p>
<p>
While this might <em>seem</em> easy, I know the challenge is coming quickly. I think if
I was reviewing this code, I would have dropped the match statement and checked
the list’s length instead, to drop the similar matches. Although, I bet there is
a version of this typed such that the list is guaranteed to have 2 and 4
elements, similar to the non-empty list shown in Alexis King’s wonderful <a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/" title="">Parse,
don’t validate</a>. A challenge for another time, though.</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/advent-of-code-2021-day-1</id>
    <title>Advent of Code 2021: Day 1</title>
    <updated>2021-12-02T03:40:24+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
Writing posts can be a bit troublesome to set up, and my major posting season is
nearly here! Fortunately, I can customize emacs a bit to make this whole process
at least a bit more optimized.</p>
<h2>
Making New Posts</h2>
<p>
When making a new post, I set the <code class="inline">Reply-To</code> header to ensure that any further
discussion goes to the correct place, and also set the <code class="inline">X-Blog-Tags</code> header to
capture blog tagging. It looks a lot nicer to get them out of the subject line
and tucked away. The end result is below:</p>
<pre><code class="emacs-lisp">(defun afontaine/set-reply-to ()
  (save-excursion
    (message-add-header
     &quot;Reply-To: andrew@afontaine.ca,~afontaine/blog-discuss@lists.sr.ht\n&quot;)))

(defun afontaine/set-blog-tags (tags)
  (save-excursion
    (message-add-header
     (concat &quot;X-Blog-Tags: &quot; tags ))))

(defun afontaine/new-blog-post (tags)
  (interactive &quot;sBlog tags: &quot;)
  (let ((mu4e-compose-mode-hook &#39;(afontaine/set-reply-to)))
    (call-interactively #&#39;mu4e-compose-new)
    (afontaine/set-blog-tags tags)
    (message-goto-body)))</code></pre>
<p>
There are lot of examples of setting headers via <code class="inline">mu4e-compose-mode-hook</code> in
mu4e’s <a href="https://www.djcbsoftware.nl/code/mu/mu4e/Compose-hooks.html" title="">documentation</a>, so setting the <code class="inline">Reply-To</code> header was no issue.
Setting the tags, however, was a little trickier. As they change from post to
post, I wanted to be able to read them in when creating a post. Here, I looked
to documentation on emacs’ <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Text-from-Minibuffer.html" title=""><code class="inline">minibuffer</code></a> to understand how to read in a
string. While <code class="inline">read-string</code> looks to be the trick, the intro paragraph specifies
that I should be using the powers of the <code class="inline">interactive</code> function to fetch my
arguments instead.</p>
<p>
<a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Using-Interactive.html" title="">Using <code class="inline">interactive</code></a> specifies that if I want to get a string, I need to
pass in the <code class="inline">s</code> command, and that I can add a prompt directly after it. Thus,
passing in <code class="inline">&quot;sBlog tags: &quot;</code> allows me to send in blog tags as part of the
creation process. To pass those arguments through, I just call a normal function
instead of adding it to <code class="inline">mu4e-compose-mode-hook</code>, and then put the cursor right
at the body ready to go!</p>
<h2>
Writing Posts</h2>
<p>
I’m also tired of writing posts in the compose window. While I will draft longer
ones in a normal file and then send that off when it is ready, these shorter
posts that I can write pretty quickly don’t need all the extra process.</p>
<p>
Instead, I just want the compose window to know about markdown. It doesn’t, of
course, but I can open the body in a <em>new buffer</em> that does:</p>
<pre><code class="emacs-lisp">(defun afontaine/get-start ()
  (message-goto-body)
  (point))

(defun afontaine/get-end ()
  (message-goto-signature)
  (search-backward &quot;--&quot;)
  (goto-char (- (point) 1)))

(defun afontaine/edit-post-in-markdown ()
  (interactive)
  (let* ((start (afontaine/get-start))
         (end (afontaine/get-end))
         (buffer (edit-indirect-region start end)))
    (switch-to-buffer-other-window buffer)
    (markdown-mode)))</code></pre>
<p>
Using the<a href="https://melpa.org/#/edit-indirect" title=""><code class="inline">edit-indirect</code></a> library, I open the body of the message in a new
buffer, and enable <code class="inline">markdown-mode</code> in that, giving me all the syntax
highlighting and link inserting power I crave.</p>
<p>
To get the body, I need to figure out the region of text that is the message
body. Thankfully, emacs has some good functions to help out.</p>
<p>
<code class="inline">message-goto-body</code> moves my <code class="inline">point</code> (emacs for cursor) to the start of the
body. The end is a little trickier though. <code class="inline">message-goto-signature</code> puts the
point at the beginning of my signature (obviously), <em>below</em> the <code class="inline">--</code>, which I
don’t want to include. I search backwards for the <code class="inline">--</code>, and move the point back
to immediately before that, getting the whole of the body. I search from the end
to ensure I am at the <code class="inline">--</code>, and not an <code class="inline">---</code> (which is markdown for a horizontal
rule, or <code class="inline">&lt;hr&gt;</code> tag). This also ensures the function works well if I am editing
a draft email.</p>
<p>
Once I’m done writing, a quick <code class="inline">C-c C-c</code> puts my post into the message body, and
ready to send.</p>
<p>
For the most part, I think this works pretty well. I’ll see how the next month
goes, as I try to keep up posting with my advent of code adventures. I’m also
hopeful this will encourage me to post more, as it really streamlines the
process of setting up a new post. Emacs <em>really is</em> that easy to customize in
powerful ways.</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/streamlining-the-posting-process-with-emacs</id>
    <title>Streamlining the Posting Process with emacs</title>
    <updated>2021-12-01T02:49:30+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
This will be my fourth (😮) year doing the <a href="https://adventofcode.com" title="">Advent of Code</a> challenges!
The first three years, I have attempted the challenges in elixir. I was
new to elixir, and (while still an amateur) I’ve grown pretty
comfortable with the language. It was fun creating simple OTP processes
to handle “communication” between two “computers”, but I felt it was
time to strike out and learn something new!</p>
<h2>
Enter ReScript</h2>
<p>
I’ve been attempting to build a bot for <a href="https://screeps.com/" title="">screeps</a>, off and on, for a few
years now. For the unaware, screeps is an MMO RTS that is always
playing, and your way of ensuring your creeps continue to work while
away is by programming them in JavaScript.</p>
<p>
Now… I do JavaScript day in and day out for work, so that wouldn’t
have been very exciting. I had initially planned to build it out in
TypeScript, but that felt too much like normal JavaScript. Elm started
promising, but the more I looked into the ecosystem, the more I realized
it really wouldn’t work. <a href="https://elm-lang.org/" title="">Elm</a> seems best designed when working within a
browser, where it can run freely and unencumbered. Slapping screeps’
event loop on top of it (the game calls your main function every tick)
felt like throwing away some of the power of elm.</p>
<p>
Then, I came across <del>bucklescript</del> <del>reason</del> <a href="https://rescript-lang.org/" title="">ReScript</a>. ReScript is
an alternative syntax for <a href="https://ocaml.org/" title="">ocaml</a> to make it a little more JavaScript-y,
and a lot of tooling to make that syntax compile very nicely to
JavaScript. It had all the statically-typed functional goodness of elm,
but with a much more general purpose attitude. It was <em>perfect</em>. I
started out happy, until hitting wall after wall of JavaScript inter-op
problems. It turns out I may have bitten off more than I could chew. I
still come back to the screeps project every now and then, but I mostly
tinker for a few hours before forgetting about it.</p>
<h2>
Maybe… caramel?</h2>
<p>
It did get me thinking about how interesting a language ocaml is,
though. It’s got a lot of depth and history, and has inspired a lot of
other languages. I had remembered hearing something about <a href="https://nitter.net/leostera/status/1322304084662194177" title="">a language</a>
trying to bring ocaml to the BEAM, erlang’s (and elixir’s) virtual
machine. It looked to be a great candidate for this year!</p>
<p>
this past weekend to actually check out the language and make sure it
would work well within my existing advent of code infrastructure. I
already had lovely mix tasks for downloading puzzle input and running
solutions, so if Caramel would work with all that, I’d be pretty happy.</p>
<p>
It turns out that the maintainer of Caramel hasn’t had the ability to
build out a lot of the language. I understand! My own [library] withers
on a vine while I find the energy to work on it. I just don’t want to
struggle and fight and be missing features I would normally expect to be
there and so on and so on. Learning how ocaml works on top of figuring
out these problems is enough, and I don’t want to be frustrated with the
tooling, too. Maybe next year I’ll have enough of an idea of what I am
doing, and can help out!</p>
<p>
For now, it looks like the only solution is to turn to the original…</p>
<h2>
OCAML</h2>
<p>
So yeah, in a few day’s time I’ll be doing advent of code in ocaml. I
played around with it a bit this weekend to get to a level of
infrastructure similar to my mix tasks to get a taste of the language
(more to come on that if I am capable). I can download input and have
<em>something</em> set up to nicely run solutions, although I think that second
one could probably use a bit of work.</p>
<p>
For now? It works, and should be able to hit the ground running come
Dec. 1, and keep this updated on my progress.</p>
<p>
Any other advent of code fans out there? Any ocaml fans with tips? Let
me know!</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/preparing-for-advent-of-code-2021</id>
    <title>Preparing for Advent of Code 2021</title>
    <updated>2021-11-30T03:25:35+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
I’m working on a big refactoring of my one elixir library, <a href="https://hex.pm/packages/unleash" title=""><code class="inline">unleash</code></a>,
and one of the changes I’m working on is moving from using <a href="https://hexdocs.pm/elixir/typespecs.html#behaviours" title=""><code class="inline">behaviour</code>s</a>
and towards using <a href="https://hexdocs.pm/elixir/Protocol.html" title=""><code class="inline">protocol</code>s</a> instead, but this means parsing a bunch
of JSON objects into their appropriate structs. While <a href="https://hex.pm/packages/poison" title=""><code class="inline">Poison</code></a> can
already do this, I don’t want to be dependant on a single JSON library
(for now), and it doesn’t <em>quite</em> tackle the problem at hand, so I got
to work.</p>
<p>
After migrating two of the eight strategies to this new format, I saw <em>a
lot</em> of boilerplate, and got to work (learning to) writing a macro.</p>
<h2>
Oh no, Macro</h2>
<p>
The usage is simple:</p>
<pre><code class="elixir">defstrategy &quot;name&quot;, keys: 0, in: [], parameters: &quot;&quot;</code></pre>
<p>
Here <code class="inline">&quot;name&quot;</code> is the name of the strategy, and is utilized in parsing.
The rest is a keyword list that matches a struct definition. I need to
work in <em>a bit</em> of the ability to parse these parameters somehow, as
Unleash generally tends to send everything as a string, but that’s still
being puzzled out.</p>
<p>
And the magic is:</p>
<pre><code class="elixir">defmacro defstrategy(name, parameters) do

  # A little bit of early magic to parse the parameters into the AST for
  # a map with string keys.
  #
  # [keys: 0, in: []] -&gt; %{&quot;keys&quot; =&gt; arg0, &quot;in&quot; =&gt; arg1}
  #
  # This is used below in the function definition to make a function
  # that pattern matches on the expected shape.
  members =
    Enum.map(parameters, fn {k, _} -&gt; {Atom.to_string(k), Macro.var(k, __CALLER__.module)} end)
    |&gt; then(&amp;{:%{}, [], &amp;1})

  # Similar to the above, creates the AST of a map with atom keys, as
  # that is what is expected when creating a new struct
  #
  # [keys: 0, in: []] -&gt; %{keys: arg0, in: arg1}
  #
  # This is used as the parsing function body to map to a new struct!
  struct =
    Enum.map(parameters, fn {k, _} -&gt; {k, Macro.var(k, __CALLER__.module)} end)
    |&gt; then(&amp;{:%{}, [], &amp;1})

  quote do
    # Define a struct!
    defstruct unquote(parameters)

    # As explained above, expands to
    # def from_map!(%{name: &quot;name&quot;, parameters: %{&quot;keys&quot; =&gt; arg0, &quot;in&quot; =&gt; arg1}})
    def from_map!(%{name: unquote(name), parameters: unquote(members)}),
      # As explained above, expands to
      # do: struct!(__MODULE__, %{keys: arg0, in: arg1})
      do: struct!(__MODULE__, unquote(struct))

    # If it doesn&#39;t match, raise an argument error, as we crash early in elixir
    def from_map!(%{name: n}),
      do:
        raise(ArgumentError, message: &quot;tried to make a unquote(name) strategy, but got n&quot;)
  end
end</code></pre>
<p>
As I work on this, I might pull it out into its own library, as I think
it might make sense, especially as I add more functionality (optional
keys? parsing values further?). I also realize this has taken a lot of
inspiration from <em><a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/" title="">Parse, don’t validate</a></em> from Alexis King, and is an
<em>excellent</em> read, even if elixir is not staticly typed. It couples
nicely with the “let it crash” mentality of the BEAM ecosystem. If your
feature flag configuration is broken, I probably don’t know what you’re
trying to do.</p>
<p>
Anyway, just a little fun that I’ve been working on.</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/a-fun-little-elixir-macro</id>
    <title>A Fun Little Elixir Macro</title>
    <updated>2021-08-12T02:48:07+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
Alright, let’s get <em>technical.</em></p>
<h2>
Deployments: The Tools</h2>
<p>
As [previously mentioned], I use <a href="https://nixos.org/" title="">nix</a> for as much as possible, which
means using NixOS for as many machines as I can. For a while, I was
managing this VPS via <a href="https://github.com/NixOS/nixops" title="">NixOps</a>, which has the benefit of being able to
spin up new servers on many tools. It, however, has some downsides:</p>
<ul>
  <li>
state is saved <em>somewhere</em> within your <code class="inline">$HOME</code>,  </li>
  <li>
it’s going through a big rewrite, and  </li>
  <li>
it doesn’t use <a href="https://www.tweag.io/blog/2020-05-25-flakes/" title="">flakes</a> yet, which are cool.  </li>
</ul>
<p>
[previously mentioned]:
<a href="https://afontaine.dev/blog/why-is-my-life-declared-by-nix">https://afontaine.dev/blog/why-is-my-life-declared-by-nix</a></p>
<p>
Instead, I use a tool called <a href="https://github.com/serokell/deploy-rs" title=""><code class="inline">deploy-rs</code></a>, (a W.I.P. name according to
<a href="https://matrix.to/#/#deploy-rs:matrix.org" title="">their matrix channel</a>), which was built to use flakes from the start
and has no hidden state to manage, which means deploying from multiple
machines (and maybe even CD eventually) is <em>much</em> easier.</p>
<p>
As the configuration for this server is in a <a href="https://git.sr.ht/~afontaine/nix" title="">git repo</a>, I need to
manage secrets <em>somehow</em>. To accomplish this, I utilize <a href="https://github.com/Mic92/sops-nix" title=""><code class="inline">sops-nix</code></a>, a
tool that integrates <code class="inline">sops</code>, a GPG-based secrets management system made
by mozilla, and <a href="https://github.com/AGWA/git-crypt" title=""><code class="inline">git-crypt</code></a>, a GPG-based way of encrypting git repo
contents, for secrets that don’t work with <code class="inline">sops-nix</code>, which is few and
far between.</p>
<h2>
Deployments: The Configuration</h2>
<p>
The repository is already mentioned, the configuration for this server
is listed as the <a href="https://git.sr.ht/~afontaine/nix/tree/main/item/federator" title=""><code class="inline">federator</code></a>, and is pretty simple. It runs this site,
a <a href="https://pleroma.social/" title=""><code class="inline">pleroma</code></a> instance, a <a href="https://github.com/matrix-org/dendrite" title=""><code class="inline">dendrite</code></a> server, and <a href="https://wiki.znc.in/ZNC" title=""><code class="inline">znc</code></a>. I plan on
using IRC from matrix soon, but have not gotten around to it yet. For
the sake of speed, both pleroma and dendrite run in docker containers.
They are pre-built, and require minimal set up. Also when I initially
set this up, there were no NixOS modules for either. That may change in
the future.</p>
<p>
This site <em>does</em> have a NixOS module; however, it is not in
<code class="inline">nix/nixpkgs</code>. It is instead defined with its source code in the <a href="https://git.sr.ht/~afontaine/home/tree/f8f45072/item/flake.nix#L133" title="">flake</a>
file, which means I can update it as I develop things. A NixOS module is
a function that takes some inputs and produces an <code class="inline">attrset</code> (or <code class="inline">map</code>
for other language fans) that has 2 keys: <code class="inline">options</code> and <code class="inline">config</code>.
<code class="inline">options</code> are those that are set by users to configure the service, like
what port to listen to (<code class="inline">services.home-web.port</code>) or details on how to
connect to the database (<code class="inline">services.home-web.databaseUrlFile</code>). <code class="inline">config</code>,
generally, configures other NixOS modules based on the options set.
Here, I make sure the default user and group are created if they are
being used, as well as configure a SystemD service that knows how to
start the application, as well as one that understands how to run
database migrations.</p>
<p>
The flake also describes the deployment in a way <code class="inline">deploy-rs</code>
understands.</p>
<pre><code class="nix">      deploy.nodes = {
        federator = {
          hostname = &quot;afontaine.dev&quot;;
          profiles.system = {
            user = &quot;root&quot;;
            path = deploy.lib.x86_64-linux.activate.nixos
              self.nixosConfigurations.federator;
          };
        };
      };</code></pre>
<p>
<code class="inline">deploy.nodes</code> is a set of all the different machines I deploy to. Here,
there is only one: <code class="inline">federator</code>. Its configuration consists of its
hostname (used to <code class="inline">ssh</code> to it), and a set of nix profiles to deploy. The
<code class="inline">system</code> one is somewhat special in that it is the one used by NixOS for
system configuration, which is why it uses the special helper function
from <code class="inline">deploy-rs</code>: <code class="inline">activate.nixos</code>, along with the NixOS configuration
to deploy to the machine.</p>
<h3>
On Secrets</h3>
<p>
There are a couple configuration items that expect <em>files</em> instead of
<em>values</em>. This is because</p>
<ol>
  <li>
everything used by nix is placed in the <em>globally-readable</em> nix
store, and  </li>
  <li>
these values are secret and should not be <em>globally-readable</em>.  </li>
</ol>
<p>
Instead, we set them to the value created by <code class="inline">sops-nix</code>, which puts
secrets under <code class="inline">/run/secrets</code> and sets permissions to however you
configure it.</p>
<p>
There’s also this <a href="https://github.com/systemd/systemd/issues/15778" title="">SystemD Credentials</a> thing that looks interesting,
but I do not know how it works, and it won’t work on NixOS until SystemD
is <a href="https://github.com/NixOS/nixpkgs/pull/123476" title="">bumped to 248</a>.</p>
<h2>
Deployments: The deploying</h2>
<p>
All of this set up, and deploying just comes down to one command:
<code class="inline">deploy</code>.</p>
<p>
<a href="https://asciinema.org/a/mBRDWIalPeiL4VancBGhBKqNW">  <img src="https://asciinema.org/a/mBRDWIalPeiL4VancBGhBKqNW.svg" alt="deploy" title="">
</a></p>
<p>
That’s it! Things missing:</p>
<ul>
  <li>
Tests! NixOS has the ability to make tests out of all this code. Maybe
one day I’ll have them too.  </li>
  <li>
Updates! <code class="inline">nix flake update</code> will update all the inputs for my
machines, so when I push a new version of the blog, all it takes is a
command to ensure the latest version is pulled down.  </li>
  <li>
CI/CD! Again, maybe one day 😉  </li>
</ul>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/deploying-this-blog</id>
    <title>Deploying This Blog</title>
    <updated>2021-06-10T05:17:15+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
An excellent question! When trying to figure out my migration away from
my static site and towards a dynamic site, I wanted to keep the one
thing I truly loved from the static site: an excellent writing and
editing experience.</p>
<p>
As it so happens, at some point I decided to try out <a href="https://www.djcbsoftware.nl/code/mu/mu4e.html" title="">mu4e</a> as a mail
client and found that it makes dealing with email <em>so much easier</em> by
eliminating the hassle of the bad web UI presented by anything that
wasn’t <a href="https://en.wikipedia.org/wiki/Inbox_by_Gmail" title="">Inbox</a> (which, even then, still had its issues). The major
caveat being that I had to actually make use of custom filters and
folders to stay organized as well. Looking back, GMail’s automatic
categorization was holding me back from actually putting the work in to
make my email the way I wanted it to be.</p>
<p>
I’ve recently been making <a href="https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56711" title="">small</a> to GitLab’s email UX as
well, and I’m slowly working towards opening the floodgates and setting
my  notification level to “watching” for the main project in an effort
to dogfood our email workflows.</p>
<p>
All this to say: mu4e has fundamentally changed how I interact with
email. It has turned it from an annoying, slow click-based web app to an
amazingly quick, keyboard-based tool essential to my day-to-day.</p>
<p>
Part of that all means that the authoring of these posts can happen in
the same place all my <em>other</em> writing happens! After all, why leave
emacs when you don’t have to? All the customization around how I write
code now applies directly to how I write these blog posts. Now that the
core editing experience has been salvaged from the static site, the rest
can tumble from there.</p>
<h2>
Other Options</h2>
<p>
I did, of course, consider some other options before settling on emails.</p>
<ol>
  <li>
    <p>
A git-based CRM    </p>
    <p>
This didn’t work out because I fundamentally misunderstood how it
worked. What <em>I</em> wanted was a service that would take a git
repository of posts and publish them over an API. Instead, these seem
to be tools around writing and editing posts that save directly to a
git repository.    </p>
  </li>
  <li>
    <p>
Pushing a git repository to my blog    </p>
    <p>
If the above didn’t work out, maybe I could just push my posts
directly to the blog and have the blog read them on disk!
Unfortunately, I couldn’t find much in terms of <code class="inline">libgit</code> bindings for
elixir, and did <em>not</em> want to be the change I wanted to see in the
world on this (i.e. write them myself). This is a path that leads to
burning out on the project and not getting anything up, so that was
out.    </p>
  </li>
  <li>
    <p>
Give up    </p>
    <p>
I’ll be honest, it was tempting… but here we are!    </p>
  </li>
</ol>
<p>
In the end, there’s also a casual nature to writing an email I just
didn’t have when writing for the old blog. It’s also faster to publish a
post, with a quick check to ensure I have the markdown formatting
correct.</p>
<p>
So… yeah. That’s “why email”. Email feels personal, and it works, so
why not?</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/why-is-this-written-via-email</id>
    <title>Why is this written via email?</title>
    <updated>2021-04-26T01:43:42+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
If you’ve taken a peak at the <a href="https://git.sr.ht/~afontaine/home" title="">source</a> for this site, you might have
noticed a <a href="https://git.sr.ht/~afontaine/home/tree/main/item/flake.nix" title=""><code class="inline">flake.nix</code></a> file sitting squarely at the root of the
project. I’ve been using <a href="https://nixos.org/" title="">NixOS</a> on my home lab for about 5 years now,
although poorly until about 2 years ago, and for the most part I’ve
enjoyed my experience.</p>
<h2>
How did it start?</h2>
<p>
When I was initially playing around with Linux, <a href="https://ubuntu.com/" title="">Ubuntu</a> was my starting
point, as is often the case. It was thrilling to not boot into Windows,
but some other system. It was also pleasing to be able to (much easily)
complete my school work without sitting in the CompSci labs, instead
finishing them from the comfort of the <a href="https://www.su.ualberta.ca/businesses/roomatthetop/" title="">campus bar</a>. One of my friends
had some spare computer parts and set up a home server so we could play
Minecraft together, and his biggest complaints were around 2 things:</p>
<ol>
  <li>
configuring everything is a pain, and  </li>
  <li>
big upgrades break everything.  </li>
</ol>
<p>
When I finally got around to needing my own server, I explored the
distribution space, looking for distributions that tackled those two
points above all else, which, somehow, lead me to NixOS. What appealed
most to me was that configuration of most everything was handled in one
<code class="inline">configuration.nix</code> file and not several files scattered throughout the
<code class="inline">/etc</code> folder.</p>
<p>
Originally, I used NixOS very minimally. The most advanced feature I
utilized was to set up my own SystemD service, which ran
<code class="inline">docker-compose</code> in a specific folder. Not very nix-y, but we all have
to start somewhere.</p>
<h2>
How is it going?</h2>
<p>
Since then, my home server, laptop, desktop and VPS are all running
NixOS. My usage of nix has also expanded to encompass my dot files via
<a href="https://github.com/nix-community/home-manager" title="">home-manager</a>, manage secrets with <a href="https://github.com/Mic92/sops-nix" title="">sops-nix</a>, and configure my work
macbook via <a href="https://github.com/LnL7/nix-darwin" title="">nix-darwin</a>. I manage the VPS through the awesome
<a href="https://github.com/serokell/deploy-rs" title="">deploy-rs</a> tool, and deploy this site to it using <a href="https://www.tweag.io/blog/2020-05-25-flakes/" title="">flakes</a>, the concept
that really made everything click.</p>
<p>
Now it’s no issue at all to spin up a new service on my VPS (like this
blog!), or <a href="https://nix-community.github.io/home-manager/options.html" title="">add new programs</a> to my user configuration, or update my
desktop and laptop to be in sync with each other, configuration-wise. As
long as I remember to actually commit and push changes, pulling them onto
another machine is a breeze.</p>
<p>
Sure, there are some struggles when it comes to dealing with the
macbook, but nix is also a <em>programming language</em>, which means
expressions, conditionals, functions, and all the right tools to
separate what doesn’t work on the macbook with what does.</p>
<p>
I’ve found that Nix has helped me simplify my management of all my
computers, and if I could manage my fridge with it, I could.</p>
<hr class="thin">
<p>
Inspired and itching to try nix out? I recommend checking out:</p>
<ul>
  <li>
The <a href="https://nixos.org/" title="">nix site</a>,  </li>
  <li>
<a href="https://christine.website/" title="">Christine Dodrill’s blog</a>,  </li>
  <li>
<a href="https://www.tweag.io/blog/tags/nix" title="">Tweag’s blog</a>,  </li>
  <li>
and the super helpful <a href="https://discourse.nixos.org/" title="">nix discourse</a>!  </li>
</ul>
<p>
This was a pretty high-level overview, of “why nix”, with none of the
fun technical details, and while this didn’t get technical <em>at all</em>, I
think once I get into the swing of writing again, I’ll be getting more
technical in posts again.</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/why-is-my-life-declared-by-nix</id>
    <title>Why is my life declared by nix?</title>
    <updated>2021-04-11T23:03:59+00:00</updated>
  </entry>
  <entry>
    <content type="html"><![CDATA[<p>
This is it! My new home on the internet!</p>
<p>
I was tempted to find a spectacular “UNDER CONSTRUCTION” banner to put
up, but one of the ideas is that this place will <em>always</em> be “under
construction”.</p>
<p>
My <a href="https://www.afontaine.ca" title="">old blog</a> will remain up, and I’m sure I’ll eventually add something
there to direct people here, but right now I am more excited about
making sure this works before I direct them to an empty site.</p>
<h2>
What’s different?</h2>
<p>
I have big-ish plans for this blog, which meant building out something
custom. I was heavily inspired by <a href="https://microblog.pub/" title="">microblog.pub</a> and the <a href="https://git.jlel.se/jlelse/GoBlog" title="">GoBlog</a> by
<a href="https://jlelse.dev/projects" title="">Jan-Lukas Else</a> to create an actual little “home on the internet”.
Right now it is only blog posts, but there will eventually be posts from
my <a href="https://social.afontaine.dev/afontaine" title="">ActivityPub instance</a>, as well as <em>maybe</em> some sort of WebMention or
Gemini support.</p>
<p>
The biggest difference, though, is the way in which I write posts. This
was heavily inspired by <a href="https://hey.com/world/" title="">world@hey.com</a> and SourceHut, which is to say,
this is both a blog <em>and a newsletter</em>. Using the power of <a href="https://lists.sr.ht/" title="">lists.sr.ht</a>
webhooks, emails sent to <a href="https://lists.sr.ht/~afontaine/blog" title="">~afontaine/blog@lists.sr.ht</a> (<em>by me</em>) are
posted here, which means that <em>if you are so very keen on it</em>, you can
subscribe to it and get me delivered <em>straight</em> into your inbox, which
sounds kind of ridiculous, who wants that?</p>
<p>
A more interested benefit of the list-based system, though, is that
there is another list (mentioned below) that <em>you</em> can post to as a form
of discussion! Eventually, I want to embed those posts and replies below
in the form of comments, but this is very much the MVP for me to email
my thoughts into the internet.</p>
<p>
I want to talk more about things, but for now, this is enough. If you’re
interested in the project, you can find it <a href="https://sr.ht/~afontaine/home/" title="">on sourcehut</a>, though poorly
documented. I’ll accept <a href="https:/lists.sr.ht/~afontaine/home-devel" title="">contributions and patches</a> as well, but you’ll
need to <a href="https://git-send-email.io/" title="">set up <code class="inline">git sendemail</code></a> to get started. It, surprisingly, isn’t
<em>that</em> hard, but still a minor annoyance.</p>
<p>
Let me know what you think!</p>
]]></content>
    <author>
      <name>Andrew Fontaine &lt;andrew@afontaine.ca&gt;</name>
    </author>
    <id>https://afontaine.dev:80/blog/new-blog-style</id>
    <title>New Blog Style</title>
    <updated>2021-04-07T21:23:01+00:00</updated>
  </entry>
</feed>