<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>inv.alid.pw</title>
    <link>https://inv.alid.pw/</link>
    <description></description>
    <atom:link href="https://inv.alid.pw/rss.xml" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Mon, 27 Apr 2026 16:14:13 +0000</lastBuildDate>
    <item>
      <title>A smart e-paper display</title>
      <link>https://inv.alid.pw/posts/thyra/</link>
      <pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/thyra/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">A smart e-paper display</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/thyra/" itemprop="url">25 September
        2025</a></time>
          </header>
        
          <p>A picture is worth a thousand words, so here is the finished
          product:</p>
          <p><img src="/img/epd.jpg"
          alt="A 7-inch e-paper display, showing the current date and time, a summarised weather forecast, the next bin collection day and type, the current grid carbon intensity and a QR code (with fake details) for my home WiFi network." /></p>
          <p>This is an e-paper display, made by <a
          href="https://www.me.uk">RevK</a>, and sold on <a
          href="https://www.tindie.com/products/revk/75-e-paper-controller-24-leds-sd-card-slot/">Tindie</a>,
          which I have set up to show some useful stuff in my kitchen. To the
          extent that this post is a review, it’s a positive one: the display
          itself is of great quality, and the software running on the
          controller, while a little tricky to get to grips with, is flexible
          enough to serve all of my needs, with a fun side project to build
          along the way.</p>
          <p>This project started when my partner asked whether I could put
          something together that would use the UK grid operator’s <a
          href="https://carbon-intensity.github.io/api-definitions/#carbon-intensity-api-v2-0-0">Carbon
          Intensity API</a> to notify us (or her) when the grid was operating at
          its cleanest so we know when to run the washing machine or dishwasher.
          I spent a bit of time trying to figure out the <a
          href="https://developer.mozilla.org/en-US/docs/Web/API/Push_API">Web
          Push API</a> but never really got anywhere with it, and it got shelved
          until I saw various posts from <a
          href="https://toot.me.uk/@revk">RevK’s Mastodon</a> about the e-paper
          devices he’d been working on and I decided that would be a fun way to
          show the data. I also thought it’d be useful to show the upcoming bin
          collections on it too, especially as I saw there was a built-in module
          to do that in the controller (but more on that later).</p>
          <p>So $160 and 1 working day’s delivery later, I had the screen in my
          hands. The set-up experience was pretty smooth: once power is supplied
          by USB-C, the device hosts a WiFi network for you to connect to and
          then all configuration is done via a web interface it provides.</p>
          <p><img src="/img/epd-web.png"
          alt="A screenshot of the EPD’s web configuration interface. It shows buttons at the top for general configuration, and then 20 buttons for individual widgets. The first widget, configuring the date, is selected, showing settings for widget position, alignment, font size and date format." /></p>
          <p>The web interface takes a bit of getting used to, and a lot of
          reference to the <a
          href="https://github.com/revk/ESP32-EPD?tab=readme-ov-file#widgets">docs</a>
          to figure out which substitution variables and size parameters go
          where, but eventually I had things laid out and looking like I wanted
          them to.</p>
          <p>The next step was putting together a service<a href="#fn1"
          class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
          to bridge between the display and the Carbon Intensity API and council
          bin services so that it could display them. This amounts to providing
          some JSON endpoints which provide the necessary data. For the bins
          display, there’s a <a
          href="https://github.com/revk/ESP32-EPD?tab=readme-ov-file#bins">schema</a>
          in the docs, but the carbon intensity display uses the $API
          substitution variable so that is up to me.</p>
          <p>I wrote this service using <a
          href="https://elixir-lang.org/">Elixir</a>’s <a
          href="https://www.phoenixframework.org/">Phoenix</a> framework, and
          the source is available <a
          href="https://git.sr.ht/~jshholland/thyra">here</a>. It’s nothing too
          complicated, but it’s the first “production” service I’ve built in
          Elixir. I reimplemented the logic for scraping Lancaster City Council
          from the excellent <a
          href="https://github.com/robbrad/UKBinCollectionData/">UKBinCollectionData</a>
          repo. There’s also some caching so it doesn’t re-fetch the same info
          on every call to the endpoint when the bin collection dates aren’t
          going to change very often.</p>
          <p>And it all works beautifully! I included a <a
          href="https://git.sr.ht/~jshholland/thyra/tree/main/item/flake.nix#L38-95">NixOS
          module</a> in the flake for the service, so it was easy to deploy it
          to the Raspberry Pi sitting next to my WiFi router, and it’s been
          sitting there doing the job for a couple of months now.</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>I named it “thyra” from the Ancient Greek “θύρα”
          meaning “door”, i.e. “portal”.<a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Worstsort yet again: polymorphic recursion</title>
      <link>https://inv.alid.pw/posts/worstsort-polymorphic-recursion/</link>
      <pubDate>Sat, 05 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/worstsort-polymorphic-recursion/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Worstsort yet again: polymorphic
        recursion</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/worstsort-polymorphic-recursion/" itemprop="url">5
        July 2025</a></time>
          </header>
        
          <p>A long time ago, I wrote a <a
          href="/posts/worstsort-rust/">couple</a> of <a
          href="/posts/worstsort-revisited/">posts</a> about a maximally slow
          (but still non-pathological) sorting algorithm which I’d tried to port
          to Rust. It compiled fine, until I tried to write a test for it and it
          suddenly blew up a recursion limit when trying to compile it.
          Eventually I realised this was due to Rust’s usage of monomorphisation
          meaning that it couldn’t statically compile infinitely many different
          instances of the function each time we wanted a version for a more
          nested list type. I was somewhat happy with that explanation, but I
          was left a little confused about why <a
          href="https://byorgey.wordpress.com/2019/02/16/worstsort/">Brent
          Yorgey’s Haskell implementation</a> worked fine. I concluded:</p>
          <blockquote>
          <p>So, there are two key questions: why was this not a problem for
          Haskell, and is there a way to get round it in Rust? At the moment, I
          don’t know! I hope to get some free time to investigate this at some
          point, and I’ll definitely write up whatever I find on here.</p>
          </blockquote>
          <p>That day has, apparently, and by complete chance, finally come,
          when I stumbled upon the key phrase: “polymorphic recursion”.
          Wikipedia <a
          href="https://en.wikipedia.org/wiki/Polymorphic_recursion">defines</a>
          it as “a recursive parametrically polymorphic function where the type
          parameter changes with each recursive invocation made, instead of
          staying constant”. In the case of Worstsort, the generic type is
          changing with each call from <code>T</code> or <code>a</code> (in the
          Rust and Haskell respectively) to <code>&amp;mut [T]</code> or
          <code>[a]</code>. It’s actually mentioned in Brent Yorgey’s original
          post in an aside that I must have glossed over at the time, or not
          thought of it as a set term with a particular technical meaning. But
          the other day, somewhere, I encountered a link to a <a
          href="https://stackoverflow.com/questions/51093198/applications-of-polymorphic-recursion">StackOverflow
          question</a> (I forget where now) asking about polymorphic recursion
          in Rust and the penny dropped that this is the name of the property
          that’s missing from Rust. It seems to be an issue that a few people
          have run into: there’s an <a
          href="https://github.com/rust-lang/rust/issues/4287">issue</a> that’s
          been open for a while asking for better error messages (possibly even
          including the term!) when the compiler detects it, and there is a
          steady stream of other issues being marked as duplicates of it.</p>
          <p>My initial thoughts now I revisit this 6 years later is that
          there’s nothing intrinsic to Rust’s type system that would prevent
          this from being compiled, and it’s more an implementation artifact.
          However, it definitely feels against the spirit of Rust to wrap all
          the type information up somewhere behind indirection and let functions
          work on pointers to things. I wonder if it’d be possible to work
          around it at the programmer level somehow, although since it’d all
          have to be at run-time you’d be working entirely round the type
          checker. Another side project to look into at some point I
          suppose.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>KubeCon Europe 2025: days 2-3 (at last)</title>
      <link>https://inv.alid.pw/posts/kubecon-day-2-3/</link>
      <pubDate>Mon, 16 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/kubecon-day-2-3/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">KubeCon Europe 2025: days 2-3 (at
        last)</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/kubecon-day-2-3/" itemprop="url">16 June
        2025</a></time>
          </header>
        
          <p>I’ve (finally) finished writing my my notes from the remainder of
          KubeCon; see my <a href="../kubecon-day-1/">previous post</a> for some
          background and initial thoughts. This is a lot later than I’d like, I
          was pretty tired after each day in the end and then life and other
          work has taken over a little bit since then. Hopefully it’s not all
          too murky to make sense of my notes. At least by now, the <a
          href="https://www.youtube.com/playlist?list=PLj6h78yzYM2MP0QhYFK8HOb8UqgbIkLMc">videos</a>
          are up, so I can jog my memory as I go. I’ll add links to the
          recording of each talk, and also go back and do the same for my
          previous post.</p>
          <p>This’ll be a pretty long one, as a paragraph or two for all the
          sessions I attended adds up fast. My general summary is sadly a bit
          removed from my feelings at the time, but I’ll do my best to remember
          my feelings at the time.</p>
          <hr />
          <section id="Day-2" id="Day-2">
          <h2>Day 2</h2>
          <section id="Keynotes" id="Keynotes">
          <h3><a href="https://youtu.be/JqG1wey7-Ao">Keynotes</a></h3>
          <p>This was the first day we made it to the keynotes. Unfortunately,
          there were a few issues with the clicker and screens for the speakers
          today. Today’s keynotes were the “end-user showcase”, where “end-user”
          in CNCF jargon means “company which has deployed Kubernetes” (not
          “someone who visits a website served by Kubernetes”). As a result, I
          didn’t get as much from these keynotes as I did from the talks in
          general or the next day’s, especially as almost all of the end-users
          were operating on a vastly larger scale than we do.</p>
          <p>My notes from the flurry of end-users on stage are pretty brief, as
          each one only had a few minutes, and I had to take their (obviously
          sugar-coated) takes on Kubernetes tech at face value without being
          able to get into much detail.</p>
          <section id="HSBC" id="HSBC">
          <h4>HSBC</h4>
          <p>My only notes here are “stunning shirt” and “way bigger than
          anything we do”.</p>
          </section>
          <section id="Peptone" id="Peptone">
          <h4>Peptone</h4>
          <p>As they did for the whole conference, my ears metaphorically
          pricked up when I saw a research-y organisation appear on stage, in
          this case a biotech company modelling disordered proteins or something
          (biology was never my strongest science). My main takeaway from this
          one was that they found it easy to migrate from dev machines with
          local GPUs to using Nvidia cards in the DGX cloud.</p>
          </section>
          <section id="Spotify" id="Spotify">
          <h4>Spotify</h4>
          <p>This talk was focused on their Backstage “Internal Developer
          Platform”, which is a UI to let developers (and presumably SREs,
          platform engineers, devops engineers and whatever the trendy job title
          is these days) see what is going on across Kubernetes. It was
          interesting to hear how they had to balance company-internal needs and
          those coming from the open-source community as they built
          improvements.</p>
          </section>
          <section id="Apple" id="Apple">
          <h4>Apple</h4>
          <p>The first of many times that I saw Katie Gamanji on stage at this
          conference, today with her Apple hat on (rather than as part of the
          Technical Oversight Committee as she appeared later on). Her topic was
          about how Apple used gRPC to connect the Apple Intelligence system
          (running locally on iPhones/iPads/Macs) to private clusters.
          Surprisingly enough for an Apple project it was written in Swift, and
          as a result it was too hard to resist mentioning that it was Memory
          Safe (as opposed to all the other CNCF projects written in Go).</p>
          </section>
          <section id="End-User-Awards" id="End-User-Awards">
          <h4><a href="https://youtu.be/K3edF36HWYU">End User Awards</a></h4>
          <p>This was mostly a promotion for various engagement activities run
          by the CNCF for end users. It was the first time I’d heard
          “observability” being reduced to the <a
          href="https://en.wikipedia.org/wiki/Numeronym#Numerical_contractions">numeronym</a>
          “o11y”, which for some terrible reason the speaker pronounced as
          “olly”. Numeronyms in general have a slightly bad reputation, which
          might not be entirely deserved, but I don’t think there’s ever a
          reason not to pronounce them as the thing they abbreviate.</p>
          <p>Some other initiatives that seemed interesting were the Academic
          Accreditation Program to certify academic courses at universities and
          other educational institutes, and <a
          href="https://gitjobs.dev/">GitJobs.dev</a>, a jobs board promoting
          careers opportunities with time allocated to working on open source
          and upstream projects.</p>
          </section>
          <section id="CERN-Linux-Foundation-OpenInfra"
          id="CERN-Linux-Foundation-OpenInfra">
          <h4>CERN/Linux Foundation/OpenInfra</h4>
          <p>I thought the HSBC talk earlier was a big estate, but CERN’s system
          puts almost everything else to shame. The top level numbers for (I
          think) just the ATLAS project come to over 10,000 servers with several
          petabytes of RAM between them. They were dealing with petabytes of
          data in the early 2000s, and are now looking at exabytes.</p>
          </section>
          <section id="Michelin" id="Michelin">
          <h4><a href="https://youtu.be/lFaSEevdZvU">Michelin</a></h4>
          <p>This was another end-user example running on a scale much larger
          than our dozen-node, several-hundred-pod deployment. Still, the
          problem they were talking about, vendor migrations, is something that
          applies at all scales, and building a solution entirely on open-source
          technologies is a great way to remain vendor-agnostic.</p>
          </section>
          <section id="Red-Hat" id="Red-Hat">
          <h4><a href="https://youtu.be/W_EF1HnP4tU">Red Hat</a></h4>
          <p>It had been a while since anyone talked about AI, so it was about
          time for a run of talks about running AI models on Kubernetes. The
          trend is for pressures on cloud infrastructure and technology to push
          towards solutions based on agents and orchestration models working
          with smaller models, which in theory is a good fit for Kubernetes, but
          the problem is how to handle state, at a much larger and more dynamic
          way than traditional workloads have demanded.</p>
          </section>
          <section id="Panel-discussion" id="Panel-discussion">
          <h4><a href="https://youtu.be/rACTrbTnFqY">Panel discussion</a></h4>
          <p>The panel featured Joseph Sandoval from Adobe, Liz Rice from Cisco,
          and the return of Katie Gamanji of Apple to talk about the history of
          the CNCF around its tenth anniversary. The CNCF took credit for the
          convergence of the industry on Kubernetes as the standard
          orchestration engine, as a vendor-neutral foundation with ownership of
          the project. Focuses for the future include multi-cluster
          observability across providers; cost management, sustainability and
          hardware management; and secret management (which is definitely
          something I’d be interested to do better!).</p>
          </section>
          <section id="Solo-io" id="Solo-io">
          <h4><a href="https://youtu.be/-k1CdrRAGMM">Solo.io</a></h4>
          <p>This was pretty much just an advert for Solo.io’s sidecarless
          service mesh. I still don’t know what a service mesh is or why I’d use
          one. It also includes some Kgateway thing that lets you connect to LLM
          providers, because it had been too long since anyone had mentioned
          AI.</p>
          </section>
          <section id="Mirantis" id="Mirantis">
          <h4><a href="https://youtu.be/_47X1eKkiEs">Mirantis</a></h4>
          <p>This was more or less another advert, one much more focused on AI,
          showing how their new control plane is great for firing up LLM
          workloads. It included the amazing line “Kubernetes has the
          opportunity to win open source”. I wasn’t previously aware that open
          source was a competition you could win, but apparently Kubernetes can
          do it.</p>
          </section>
          <section id="NAV" id="NAV">
          <h4><a href="https://youtu.be/DWq8UWmcRQg">NAV</a></h4>
          <p>This was probably the keynote I found the most interesting, perhaps
          because the public sector is a lot closer to academia than industry
          is. They were presenting the PaaS they had built for the Norwegian
          government, built by the Norwegian welfare service. They had begun by
          creating a community for public-sector cloud users in Norway, with
          in-person meetups and a Slack. Then they built their “Nais” platform.
          In true public sector form, it’s a backronym from the word “nice”. NAV
          (the welfare service) in-sourced development of their services, built
          and open-sourced the Nais service and now has over 3000 open-source
          code repos. In 2024 the service did something like 3000 production
          deploys per week. They had a similar experience to us, finding the
          non-code stuff harder than writing code.</p>
          </section>
          </section>
          <section id="OTel-sucks" id="OTel-sucks">
          <h3><a href="https://youtu.be/QzStkLbA7Qk">OTel sucks!</a></h3>
          <p>I’ve subtitled this one “and so does the conference wifi”, since no
          amount of technical expertise on the event side will compete with
          13,000 geeks trying to use several devices each at the same time. I
          was hoping this would be something of an introduction to
          OpenTelemetry, which seemed to be everywhere. Monitoring and alerting
          is something I’ve wanted to improve at work and I was hopeful that
          OTel was something we could put to use on that front. The format used
          in this “X Sucks!” talk is to have a bunch of community members give
          (edited) complaints about X, then re-play the full video in which it
          is revealed that the complaints are actually strong points. My notes
          contain a lot more downsides than advantages, which is perhaps
          indicative of how this format can end up a bit back-slappy.</p>
          <p>The quote I’ve jotted down perhaps sums up OTel: “It is a lot”. The
          speaker counted up 13 distinct APIs and a huge number of SDKs for
          different languages. Autoinstrumentation can be a bit overzealous in
          collecting unnecessary data and overload the collection process. The
          one pro I’ve got is that the “stability of the semantic convention is
          taken seriously” which seems a little opaque. The semantic convention
          came up almost every time OTel was mentioned, and it’s clear that it’s
          a very important idea.</p>
          </section>
          <section id="Strengthening-Auth-in-Kubernetes"
          id="Strengthening-Auth-in-Kubernetes">
          <h3><a href="https://youtu.be/rVz-vIFGT4k">Strengthening Auth in
          Kubernetes</a></h3>
          <p>I’m not really sure why I decided to go to this session: perhaps I
          was hoping to understand better how to handle multiple users in one
          Flux cluster. In any case, I did pick up one or two interesting and
          useful things from this talk. I’ve split my notes into APIs which have
          “graduated” and those which are “upcoming”.</p>
          <p>In the graduated section, I have noted down a new way to pass CA
          roots into Pods, which is not something I see myself using any time
          soon (although we have occasionally run into issues before we migrated
          to LetsEncrypt with the certificate on our GitLab container registry
          expiring). There was also something about new authorisation<a
          href="#fn1" class="footnote-ref" id="fnref1"
          role="doc-noteref"><sup>1</sup></a> for the Kubelet API where it’s now
          possible to restrict things to the <code>/configz</code>,
          <code>/healthz</code> and/or <code>/pods</code> endpoints.</p>
          <p>The “upcoming” part had some things which were a bit more relevant.
          It turns out that if an image which requires authentication had
          already been downloaded, the Pod’s credentials aren’t checked. I was
          pretty surprised that hadn’t already been the case, but soon that
          little hole will be closed. I’ve also written down “Service Account
          pull credentials rather than separate secret options”. I’m not sure
          what this means, and I can’t find the point in the talk recording
          which prompted me to make this note. Hopefully it means something to
          someone.</p>
          </section>
          <section id="KubeCon-Family-Fortune" id="KubeCon-Family-Fortune">
          <h3><a href="https://youtu.be/2-fSMpCSYnw">KubeCon Family
          Fortune</a></h3>
          <p>Another “fun” presentation, taking the popular game show format
          (also known as “Family Feud”) to Kubernetes. I appreciated them
          framing it as “Tabs v Spaces”, although a serious opportunity was
          missed by putting Tabitha on the “Spaces” team, or at the very least
          not by pointing out this contradiction.</p>
          </section>
          <section
          id="Navigating-the-inevitable:-Kubernetes-Breaking-Changes-Behind-the-Scenes"
          id="Navigating-the-inevitable:-Kubernetes-Breaking-Changes-Behind-the-Scenes">
          <h3><a href="https://youtu.be/lQFUarM_GXo">Navigating the inevitable:
          Kubernetes Breaking Changes Behind the Scenes</a></h3>
          <p>This talk on how Kubernetes (or at least the core project) manages
          breaking changes definitely taught me a few interesting things. The
          speaker started by distinguishing two types of breaking change: those
          with and without a mitigation, where a mitigation is some sort of
          config change or similar that lets you still more or less use the
          feature in question. The Kubernetes project categorises them as Major
          Changes or Removals, which map more or less one-one onto the
          with/without mitigation dichotomy.</p>
          <p>Operationally, breaking changes in Kubernetes always go through a
          deprecation cycle, although there’s often not a lot of incentive to
          act on deprecations until the feature is finally removed or changed.
          As always, it’s a good idea to look at the changelog for both removals
          and deprecations when upgrading. A change in Kubernetes starts as a
          Kubernetes Enhancement Proposal (KEP), so if you really want to stay
          ahead of the game, then watching the KEPs is one way to do that.</p>
          <p>Another key aspect to be aware if is Kubernetes-hosted
          infrastructure, which has no particular guarantee or SLA. If you do
          rely on anything like that, it’s very important to keep an eye on the
          Kubernetes news channels and run a mirror if necessary. Two key news
          channels are the <a
          href="https://groups.google.com/g/kubernetes-announce?pli=1">kubernetes-announce
          mailing list</a> and <a href="https://lwkd.info/">Last Week in
          Kubernetes Development</a>.</p>
          </section>
          <section
          id="GPU-Sharing-at-CERN:-Cutting-the-Cake-Without-Losing-a-Slice"
          id="GPU-Sharing-at-CERN:-Cutting-the-Cake-Without-Losing-a-Slice">
          <h3><a href="https://youtu.be/_pgOuaYwvBQ">GPU Sharing at CERN:
          Cutting the Cake Without Losing a Slice!</a></h3>
          <p>A talk by CERN promised to be interesting, if again beyond our
          scale. This had a bit of a classic computer science bin-packing
          flavour to it, about optimising GPU usage between teams and workloads.
          Traditionally, a GPU would be assigned to one team, but would often be
          unused between training runs or similar. This would suggest a move
          towards a more centralised setup to reduce idle time. At that point
          you run the risk of demand outstripping supply, so GPU sharing is
          vital to effectively use your resources.</p>
          <p>There are a few different technical approaches to sharing a GPU
          across workloads. The simplest is time-slicing, a strategy which dates
          all the way back to the mainframes of old. It’s well-understood and
          straightforward, but has issues when it comes to memory-sharing and
          context switching. One alternative is known as Multi Process Service
          (MPS) where a control daemon process manages cooperative multitasking.
          This means that there is no context switching overhead, and also it’s
          impossible for one process to starve others.</p>
          <p>Another approach is Multi Instance GPU (MIG), which requires
          compatible GPUs which can be sliced into independent partitions. This
          is a nice idea in the abstract, but it’s a bit inflexible as you can’t
          readily re-partition the GPUs as workloads change and the
          configuration is per-node. This can be solved by the upcoming Dynamic
          Resource Allocation tooling (which was mentioned in a lot of
          talks).</p>
          <p>The speaker finished with some benchmarks, showing that the
          different types of workload can behave very differently on MPS vs
          timeslicing, so it’s important for a platform team to educate the
          users on which works best for their compute tasks.</p>
          </section>
          <section
          id="Image-Snapshotters-for-Efficient-Container-Execution-in-Particle-Physics"
          id="Image-Snapshotters-for-Efficient-Container-Execution-in-Particle-Physics">
          <h3><a href="https://youtu.be/Dc6S4vU9GiM">Image Snapshotters for
          Efficient Container Execution in Particle Physics</a></h3>
          <p>Another talk by CERN was my last one of day 2. They started with
          the stat that 85% of the bytes downloaded are not used by a container.
          Physicists’ containers often end up gigabytes in size in such a way
          that they can’t be slimmed down. This means that images have to wait a
          long time before the whole container is downloaded before they can
          start. One way to reduce this startup latency is lazy pulling, where
          the storage layer intelligently fetches only the bytes that the
          container actually needs, at the cost of some runtime performance.</p>
          <p>Lazy pulling requires some metadata indices to the container so
          that the runtime knows what bytes are needed for each request by the
          container. The main solution presented here was CUMFS, a FUSE-based
          filesystem developed at CERN. It’s a fully global lazy filesystem,
          which is generally mounted at <code>/cumfs</code> by nodes at CERN. It
          serves something like 4 billion files running to multiple petabytes
          (they said it had been proven up to 100 PB). They showed some every
          impressive looking graphs, but warned about using lots of small files,
          and the fly crawling across the lens of the projector was a little
          distracting.</p>
          <hr />
          </section>
          </section>
          <section id="Day-3" id="Day-3">
          <h2>Day 3</h2>
          <section id="Keynotes-1" id="Keynotes-1">
          <h3>Keynotes</h3>
          <section id="Google-Bytedance" id="Google-Bytedance">
          <h4><a href="https://youtu.be/BBqDpqATcI0">Google/Bytedance</a></h4>
          <p>This was basically an announcement for their new Inference Gateway
          for self-hosting LLMs (the first hint at something of a theme for the
          keynotes this morning). One issue is how LLM requests are quite
          variable and unpredictable in terms of input and output size. There
          are also issues where, for supply chain and hardware availability
          reasons, clusters might run a range of different GPUs. Overall,
          traditional microservice requests (small, predictable, cheap) are very
          different to LLM requests (large, variable, expensive), so the
          Inference Gateway provides more intelligent load balancing.</p>
          </section>
          <section id="Oracle-Red-Bull-Racing" id="Oracle-Red-Bull-Racing">
          <h4><a href="https://youtu.be/g7KIuv7KipE">Oracle/Red Bull
          Racing</a></h4>
          <p>This was a pretty content-free talk really, just Oracle making the
          most of sponsoring the F1 team. They spoke a little about how they
          were using AI for real time insights for race strategy, and also
          getting input on FIA regulatory desicions. They also managed to make
          it seem like they were rather ignorant of recent politics by saying
          that this was all happening “right here in the EU” on a stage in
          post-Brexit London.</p>
          </section>
          <section id="Panel:-cloud-native-in-telecoms"
          id="Panel:-cloud-native-in-telecoms">
          <h4><a href="https://youtu.be/qj9q_-S91L8">Panel: cloud native in
          telecoms</a></h4>
          <p>I’m not sure how informative this panel discussion was really. The
          main takeaways I had were that telcos tend to be reasonably
          conservative, with physical boxes wired together virtually. They spoke
          about an ambition to upgrade to 6G by some sort of rolling upgrade or
          operator subscription, which sounds pretty ambitious.</p>
          </section>
          <section
          id="Cutting-Through-the-Fog:-Clarifying-CRA-Compliance-in-Cloud-Native"
          id="Cutting-Through-the-Fog:-Clarifying-CRA-Compliance-in-Cloud-Native">
          <h4><a href="https://youtu.be/A1HGYh0Wz9U">Cutting Through the Fog:
          Clarifying CRA Compliance in Cloud Native</a></h4>
          <p>This was the first detail I’d heard about the Cyber Resiliance Act,
          upcoming EU legislation for “products with digital elements”. It’s
          unclear to me what a scientific institute working (generally) outside
          the EU, albeit often partnering with EU-based universities and
          research centres, has to worry about the CRA. Still, it is a
          codification of mostly good practices, but how that shakes out for
          open source projects rather than companies remains to be seen. One
          interesting aspect of this is the notion of “stewards” as an
          intermediate between maintainers and manufacturers, which is likely
          the role that the CNCF and Linux Foundation would assume.</p>
          </section>
          <section id="Lessons-Learned-in-LLM-Prompt-Security"
          id="Lessons-Learned-in-LLM-Prompt-Security">
          <h4><a href="https://youtu.be/UI-b-Odg39A">Lessons Learned in LLM
          Prompt Security</a></h4>
          <p>It had been a whole two talks since we last talked about LLMs, so
          it was time to bring them back up again. Despite being a sponsored
          keynote, I did find this one a little bit interesting, although more
          in the way of morbid fascination. If you are running an LLM to which
          users can submit queries, how can you make sure their prompts aren’t
          dangerous (whatever that means in your usage context)? The obvious
          way, if you are that deep into the hype cycle, is of course to run
          <em>another</em> LLM to classify prompts as “safe” or “not safe”<a
          href="#fn2" class="footnote-ref" id="fnref2"
          role="doc-noteref"><sup>2</sup></a>. However, as we saw in the earlier
          talk, LLM queries tend to be slow and expensive, which is not what you
          want when you are building a filter into your load balancer. More
          “advanced” techniques, such as text filtering(!), are required.</p>
          </section>
          <section id="221B-Cloud-Native-Street" id="221B-Cloud-Native-Street">
          <h4><a href="https://youtu.be/jUChVGvSB5g">221B Cloud Native
          Street</a></h4>
          <p>It’s Katie Gamanji again! This time, it was a presentation from the
          Technical Oversight Committee (TOC), giving their update on what
          they’d been up to. They explained what the CNCF project maturity
          levels meant and let us know where the Technical Advisory Group (TAG)
          reform was going. They also gave an update on the End User Technical
          Advisory Board, which is currently working on “Feedback Loops”,
          “Reference Architectures” and “Gaps”.</p>
          </section>
          <section id="Science-at-Light-Speed" id="Science-at-Light-Speed">
          <h4><a href="https://youtu.be/GyvARSG3_ws">Science at Light
          Speed</a></h4>
          <p>Another talk focused on science, but unfortunately again at a scale
          way beyond the few gigabytes a year we’ll be collecting. The <a
          href="https://www.skao.int/en">Square Kilometre Array</a> (SKA) is a
          radio telescope currently under construction in Australia and South
          Africa. It will produce something like 600 PB of data each year, and
          this presentation went into how you can possibly build infrastructure
          to handle that. The starting point will be local processing centres in
          the same country as the telescope and then distributed resources
          around the world.</p>
          <p>The project has 14 SKA Regional Centres (SRCs), which independently
          use whatever infrastructure they choose to provide a unified service
          layer, as much as possible with off-the-shelf tools. The speaker was
          from the Swiss SRC and explained how they used worker nodes from Swiss
          supercompute facilities. There was also a quick demo of using the
          network to access some data, and, as seems to be the case for every
          single data science demo, the example used was to cookie-cut a subset
          of the data out.</p>
          </section>
          </section>
          <section
          id="Ensuring-Quality-in-Kubernetes:-The-Graduation-Process-From-Alpha-To-GA"
          id="Ensuring-Quality-in-Kubernetes:-The-Graduation-Process-From-Alpha-To-GA">
          <h3><a href="https://youtu.be/d_9JNRkT7dg">Ensuring Quality in
          Kubernetes: The Graduation Process From Alpha To GA</a></h3>
          <p>This talk pairs with the other one I attended about the lifecycle
          of deprecations in Kubernetes, and describes how APIs go from alpha to
          beta to general availability, and a bit of describing what each step
          along that process means.</p>
          <p>Alpha APIs should work and not be buggy, although the interface is
          not necessarily stable yet. They emphasised the point that API
          stability is not just about syntax, but also semantics and
          behaviour.</p>
          <p>Alpha and beta APIs are disabled by default, and part of the
          consideration as they progress is the scalability and performance
          requirements. The testing requirements also increase as the feature
          moves towards GA. The talk finished with a bit of a discussion about
          the project’s strong policy about avoiding flaky tests, and how much
          work had been done to reach that standard.</p>
          </section>
          <section
          id="The-State-of-Prometheus-and-OpenTelemetry-Interoperability"
          id="The-State-of-Prometheus-and-OpenTelemetry-Interoperability">
          <h3><a href="https://youtu.be/JFS0lSfHtMI">The State of Prometheus and
          OpenTelemetry Interoperability</a></h3>
          <p>I got most of the sort of introductory overview of Prometheus and
          OTel I was hoping for out of this talk, even if it wasn’t intended as
          such. There was a lot of describing the philosophical differences
          between the two systems.</p>
          <p>The first difference is how Prometheus pulls data while OTel pushes
          it. Pulling data means that the instrumented service has to keep its
          metrics in memory for when it is queried, and doesn’t let you only
          submit data when it changes, which are two points in favour of
          push-based architecture. A key downside of pushing data is that your
          instrumentation finds it difficult to tell the difference between your
          app not existing and your app being down. I’ve scribbled down the
          following table to compare the use cases for the two:</p>
          <table>
          <caption></caption>
          <thead>
          <tr>
          <th style="text-align: center;">Prometheus</th>
          <th style="text-align: center;">OpenTelemetry</th>
          </tr>
          </thead>
          <tbody>
          <tr>
          <td style="text-align: center;">Time series database</td>
          <td style="text-align: center;">Instrumentation framework</td>
          </tr>
          <tr>
          <td style="text-align: center;">Monitoring and alerting</td>
          <td style="text-align: center;">Creation, collection, processing and
          export of metrics</td>
          </tr>
          </tbody>
          </table>
          <p>Another issue of interoperability is metric names: OTel supports
          the whole of Unicode, whereas (until version 3.0) Prometheus only
          supports alphanumerics, <code>_</code> and <code>-</code>.</p>
          <p>A goal of the Prometheus project is to be the best backend for
          OpenTelemetry. One way to bring the two together is to use versioned
          reads in Prometheus to access metrics which were renamed from the
          Prometheus naming style to the OTel one. OTel deltas can be converted
          to cumulative metrics, but resource attributes (like information about
          OS, architecture, process IDs or Docker) have taken a few iterations
          to translate into Prometheus:</p>
          <ul>
          <li><p>turn them all into labels, but this led to cardinality
          issues</p></li>
          <li><p>create a <code>target_info</code> metric which holds all the
          resource attributes and use PromQL JOINs to access them, but PromQL
          JOINs are very hard to use and form a barrier for many users</p></li>
          <li><p>let the user configure which resource attributes to turn into
          labels, but this is then an admin nightmare</p></li>
          </ul>
          <p>User research for the best solution is still ongoing.</p>
          <p>Finally, since we are using Parquet for storing time series in the
          current project at work, my ears pricked up when they mentioned a
          Parquet storage working group, even if it is still early days.</p>
          <hr />
          <p>And that’s it! After that last Prometheus/OTel talk we had to leave
          the conference to catch the train back to Lancaster. It had been an
          exhausting few days but I think I learned a lot about Kubernetes. It
          was also quite eye-opening to see a conference of that scale, drink
          all the coffee, eat all the cakes and meet lots of people. Maybe I’ll
          go again next time, and not take 3 months to write up all of my
          notes.</p>
          </section>
          </section>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>It always feels weird spelling “authorisation” in the
          British English way when it’s so frequently abbreviated to “authz”.<a
          href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          <li id="fn2"><p>What could possibly go wrong‽‽‽‽<a href="#fnref2"
          class="footnote-back" role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>KubeCon Europe 2025: day 1</title>
      <link>https://inv.alid.pw/posts/kubecon-day-1/</link>
      <pubDate>Wed, 02 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/kubecon-day-1/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">KubeCon Europe 2025: day 1</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/kubecon-day-1/" itemprop="url">2 April
        2025</a></time>
          </header>
        
          <p>This is a fairly non-structured log of my thoughts and notes from
          attending <a
          href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/">KubeCon
          Europe 2025</a><a href="#fn1" class="footnote-ref" id="fnref1"
          role="doc-noteref"><sup>1</sup></a>. I was lucky to be sponsored by
          work, so I made at least some attempt to get to talks and sessions
          which seemed relevant to that. Unfortunately getting to the ExCeL
          venue from Lancaster on the Wednesday morning meant that I missed the
          morning keynotes.</p>
          <p>I wasn’t sure what to expect from the event really: it was the same
          week that I returned from a month of leave (my attendance had been
          arranged while I was away by a “do you want to go” text), and it’s by
          far the largest tech conference I’ve been to. So my preparation (going
          through the <a
          href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/program/schedule/">schedule</a>
          and saving all the talks with a vaguely interesting title and/or
          abstract) was a bit limited, and I didn’t have as long as I’d have
          liked to consider what I really wanted to get out of it. The rough
          list of things I was keen to learn more about was:</p>
          <ul>
          <li>GitOps tooling around <a href="https://fluxcd.io/">Flux</a>,
          including secret management and the best way of managing both a
          production and staging cluster in a reasonably harmonious way</li>
          <li>The experience of other scientific institutions in using
          Kubernetes (for example some of the many talks on using GPUs in a
          cluster)</li>
          <li>Any other useful tools and knowledge I can pick up</li>
          <li>Having a go at the <a
          href="https://controlplaneio.github.io/kubecon-eu-2025-ctf/">CTF</a>
          as I’ve never taken part in one before</li>
          </ul>
          <p>I was less interested in some of the talks about scaling Kubernetes
          to huge deployments, as all the stuff we run is fairly small-scale,
          and didn’t really have much time for the LLM/AI stuff that filled up a
          huge portion of the schedule. It’s probably going to be pretty
          unavoidable throughout the event though.</p>
          <p>The rest of this post consists of mildly edited thoughts from my
          handwritten notes taken during the sessions I was in.</p>
          <section id="Explain-How-Kubernetes-Works-With-GPU-Like-I&#39;m-5"
          id="Explain-How-Kubernetes-Works-With-GPU-Like-I&#39;m-5">
          <h2>Explain How Kubernetes Works With GPU Like I’m 5</h2>
          <section id="Carlos-Santana-AWS" id="Carlos-Santana-AWS">
          <h3>Carlos Santana, AWS</h3>
          <p>The first talk we made it to was an introduction to the various
          layers involved in running GPUs on Kubernetes. The speaker broke down
          the layers from device driver, CUDA runtime, container toolkit to node
          and GPU feature discovery and the device plugin to handle scheduling
          and access to the compute resources. It was a good introduction to the
          various things that are needed to set up GPU-enabled workflows, but
          what caught me the most was a passing comment about how EKS hybrid
          nodes allowed an AWS-managed EKS cluster to include nodes running
          remotely (for example in a homelab) over a VPN like Wireguard.</p>
          </section>
          </section>
          <section id="Bringing-Agentic-AI-to-Cloud-Native---Introducing-kagent"
          id="Bringing-Agentic-AI-to-Cloud-Native---Introducing-kagent">
          <h2>Bringing Agentic AI to Cloud Native - Introducing kagent</h2>
          <section id="Christian-Posta-Solo-io" id="Christian-Posta-Solo-io">
          <h3>Christian Posta, Solo.io</h3>
          <p>I missed the start of this one as I was wandering around trying to
          find the room for the CTF intro, but after giving up on that until the
          later session I ended up watching this “sponsored demo” of an LLM
          attached to a Kubernetes cluster. The introduction that I missed
          presumably explained exactly what I was looking at, but it seemed to
          be a web interface for a chatbot that was connected to a Kubernetes
          cluster which could explain the state of resources in a namespace,
          preview and apply changes (yes, it did have <code>kubectl</code> and
          working credentials), as well as reading and summarising online
          documentation for the user. The speaker also made a big deal of its
          support for MCP, which apparently stands for the “Model Control
          Framework” for “domain-specific extensions”. I have no idea what that
          is, but I’m sure if you are into LLMs that is a good thing.</p>
          </section>
          </section>
          <section id="Booths---Clickhouse-Wiz" id="Booths---Clickhouse-Wiz">
          <h2>Booths - Clickhouse &amp; Wiz</h2>
          <p>Over the lunch break, we wandered around some of the booths in the
          exhibitor area. We had a look at the Clickhouse one, as it seems like
          it could be a better way to do some of the columnar querying needed in
          one of our projects than the current solution of a hand-rolled
          connection pool to a load of Parquet files in S3. They said their
          server was open-source, so perhaps it’s worth a bit of an experiment,
          especially as it can ingest Parquet files and query them from a client
          library.</p>
          <p>We also chatted to the people on the Wiz stand, mostly because we’d
          heard they had recently been acquired for an ungodly amount of money
          but didn’t really know much more than that. I’m not sure how much need
          or budget we have for compliance and security scanning, but they
          didn’t look completely horrified when we said “non-profit” or
          “scientific research” so perhaps they have pricing options that might
          be compatible with what we do.</p>
          </section>
          <section
          id="Poster---Enhancing-Research-and-Data-Delivery-With-the-Data-Delivery-System-DDS"
          id="Poster---Enhancing-Research-and-Data-Delivery-With-the-Data-Delivery-System-DDS">
          <h2>Poster - Enhancing Research and Data Delivery With the Data
          Delivery System (DDS)</h2>
          <section
          id="Álvaro-Revuelta-SciLifeLab-Data-Centre-Valentin-Georgiev-Uppsala-University"
          id="Álvaro-Revuelta-SciLifeLab-Data-Centre-Valentin-Georgiev-Uppsala-University">
          <h3>Álvaro Revuelta, SciLifeLab Data Centre &amp; Valentin Georgiev,
          Uppsala University</h3>
          <p>This was one of the things I thought would be the closest thing to
          the work we do in providing scientific data to other researchers. It
          turned out that it wasn’t really the same thing, more a tool for
          short-term sharing of datasets with known collaborators who have
          requested it specifically, rather than publishing ongoing data
          publicly for anyone to access.</p>
          </section>
          </section>
          <section id="An-Introduction-to-Capture-The-Flag"
          id="An-Introduction-to-Capture-The-Flag">
          <h2>An Introduction to Capture The Flag</h2>
          <section id="Andy-Martin-Kevin-Ward-ControlPlane"
          id="Andy-Martin-Kevin-Ward-ControlPlane">
          <h3>Andy Martin &amp; Kevin Ward, ControlPlane</h3>
          <p>Having successfully found the right room, there was a short
          introduction from the team running the CTF at KubeCon this year, in
          which they provided an overview of how it worked, one hint<a
          href="#fn2" class="footnote-ref" id="fnref2"
          role="doc-noteref"><sup>2</sup></a> and then some background music for
          a roomful of people trying to break into an imaginary Kubernetes
          cluster in a scenario used at a previous conference. I initially felt
          like I wasn’t making much headway, and was aware of the time ticking
          away until the next talk I wanted to go to, before I suddenly found
          the first flag just before I had to pack up and go back downstairs. I
          guess that’s how these things often go. I learned a lot more about
          Hashicorp Vault than I was expecting to and I look forward to having a
          bash at the “real thing” tomorrow.</p>
          </section>
          </section>
          <section id="The-Life-or-Death-of-a-Kubernetes-Request-2025-Edition"
          id="The-Life-or-Death-of-a-Kubernetes-Request-2025-Edition">
          <h2>The Life (or Death) of a Kubernetes Request, 2025 Edition</h2>
          <section id="Abu-Kashem-Red-Hat-Inc-Stefan-Schimanski-Upbound"
          id="Abu-Kashem-Red-Hat-Inc-Stefan-Schimanski-Upbound">
          <h3>Abu Kashem, Red Hat Inc. &amp; Stefan Schimanski, Upbound</h3>
          <p>This talk was framed as the answer to a hypothetical interview
          question of “what happens when you create a new resource with
          <code>kubectl
          apply -f job.yaml</code>?”. It gave a good tour of what happens inside
          the request handler in the apiserver, mostly covering the various
          validations, timeouts and audit logs that are added, as well as what
          “creating a new resource” actually entails in the registry and etcd.
          There were a lot of details that I’m unlikely to remember, but it’s
          almost certainly useful to have a sense of what’s going on in there,
          as well as some trivia like the differences between kinds and
          resources and what is going on with different apiVersions.</p>
          </section>
          </section>
          <section id="Flux-Ecosystem-Evolution" id="Flux-Ecosystem-Evolution">
          <h2>Flux Ecosystem Evolution</h2>
          <section id="Stefan-Prodan-ControlPlane-Sanskar-Jaiswal-Kong"
          id="Stefan-Prodan-ControlPlane-Sanskar-Jaiswal-Kong">
          <h3>Stefan Prodan, ControlPlane &amp; Sanskar Jaiswal, Kong</h3>
          <p>Again I missed the start of this talk having accidentally walked to
          the wrong end of the conference centre to find the room. Luckily, I
          don’t think I missed too much and was able to figure out that Flagger
          is a system for doing canary rollouts that we are unlikely to ever use
          at our scale. It’s not something I’ve ever looked into in detail, and
          while I’m sure it’s obvious to people who do do this sort of thing,
          the idea of progressively rolling a new version out automatically as
          long as the metrics look good is not something I’d considered
          before.</p>
          <p>The main thing I was interested in from this talk was Flux,
          something we definitely do use. There were a lot of exciting-sounding
          new features discussed, mostly enabled by the Flux Operator. Ephemeral
          environments for PRs/MRs is something I’ve thought about before for
          when we are reviewing changes, and it seems like these should be
          fairly straightforward to set up with the operator, as well as making
          Flux component upgrades a lot easier than re-running the bootstrap to
          update the component manifests in the git repository. Even the
          presenter said that it was scary and easy to blow up your own cluster
          before!</p>
          </section>
          </section>
          <section
          id="The-Ultimate-Container-Challenge:-An-Interactive-Trivia-Game-on-OCI-Podman-Docker"
          id="The-Ultimate-Container-Challenge:-An-Interactive-Trivia-Game-on-OCI-Podman-Docker">
          <h2>The Ultimate Container Challenge: An Interactive Trivia Game on
          OCI, Podman, Docker…</h2>
          <section id="Aurélie-Vache-OVHCloud-Sherine-Khoury-Red-Hat"
          id="Aurélie-Vache-OVHCloud-Sherine-Khoury-Red-Hat">
          <h3>Aurélie Vache, OVHCloud &amp; Sherine Khoury, Red Hat</h3>
          <p>It was definitely by now time for the “fun” talks, starting with
          this interactive quiz about Docker and OCI containers. For a moment
          before the questions got too hard I made it onto the top 5
          leaderboard, but then we got onto the things I’d actually come along
          to learn about. It was a good format to have the audience answer a
          question, then give the answer and a live demo to explain it even
          more. I was also very impressed with whatever technology they were
          using to handle typing the demo commands into the terminal, as it
          clearly was actually doing the work live but also seemed to grab the
          hashes out of the command output for use in later commands.</p>
          </section>
          </section>
          <section
          id="Museum-of-Weird-Bugs:-Our-Favorites-From-8-Years-of-Service-Mesh-Debugging"
          id="Museum-of-Weird-Bugs:-Our-Favorites-From-8-Years-of-Service-Mesh-Debugging">
          <h2>Museum of Weird Bugs: Our Favorites From 8 Years of Service Mesh
          Debugging</h2>
          <section id="Alex-Leong-Buoyant" id="Alex-Leong-Buoyant">
          <h3>Alex Leong, Buoyant</h3>
          <p>This one was a bit more of a punt, as I didn’t really know what a
          Service Mesh was or how you’d debug one, but I always enjoy hearing
          war stories about this sort of thing. The morals of the two bugs
          presented are almost just about relevant to some of the things I do,
          and are probably general enough to think about: make sure you aren’t
          calling blocking functions in places that blocking would lead to
          deadlock/client service denial, and be careful with different versions
          of CRDs. I’d also not heard of HTTP2 flow control before, which is
          something good to be aware of before I encounter some weird bug caused
          by it in the future.</p>
          </section>
          </section>
          <section id="Clash-Loop-Back-Off" id="Clash-Loop-Back-Off">
          <h2>Clash Loop Back Off</h2>
          <p>The final session of the day was a fun game-show type system, which
          challenged two Kubernetes experts to solve a problem (from a shortlist
          of 3 where they didn’t know which would be picked) competitively live
          on stage. They had to provision a cluster, install a stateful
          workflow, back it up, delete it and then restore from the backup, all
          within 25 minutes and while being entertaining on stage. I had grabbed
          some dinner to eat while it was going on, and I really should have
          cashed in my first beer token as it was very light-hearted. A fun way
          to finish off the day.</p>
          <hr />
          <p>That was my first day at KubeCon. I feel like I made it through
          more talks than I was expecting: I often find that regardless of how
          interesting the content of the talk is, unless the speaker is
          extremely engaging (by which I really just mean upbeat and
          hyperactive) I often find it hard not to drift off while sitting and
          listening. Pehaps having a notebook and pen to hand, even if I’m not
          compulsively taking full notes, wards off that sort of drowsiness, or
          maybe I just had enough coffee to keep me going.</p>
          <p>Tomorrow we’ll be there in good time to see all the morning
          keynotes. The container quiz I saw towards the end was in the main
          auditorium, which was frankly outrageously large. If it’s close to
          being full then that will be far too many people in one place. Now,
          time to press publish and get some sleep…</p>
          </section>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>If you are reading this in the future, the link may
          not be to the 2025 event that I attended; if I realise I’ll update it
          to a permalink.<a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          <li id="fn2"><p>“Try running <code>kubectl auth can-i --list</code> to
          see what credentials you have”<a href="#fnref2" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Even more on git scratch branches: using Jujutsu</title>
      <link>https://inv.alid.pw/posts/jujutsu-scratch/</link>
      <pubDate>Tue, 21 May 2024 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/jujutsu-scratch/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Even more on git scratch branches:
        using Jujutsu</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/jujutsu-scratch/" itemprop="url">21 May
        2024</a></time>
          </header>
        
          <p>This is the third post in an impromptu series:</p>
          <ol type="1">
          <li><a href="/posts/git-scratch-branch">Use a scratch branch in
          git</a></li>
          <li><a href="/posts/stgit-scratch">More on git scratch branches: using
          stgit</a></li>
          </ol>
          <p>It seems the main topic of this blog is now git scratch branches
          and ways to manage them, although the main prompt for this one is
          discovering someone else had <a
          href="https://qword.net/2023/10/22/the-use-and-abuse-of-the-dev-branch">exactly
          the same idea</a>, as I found from a <a
          href="https://reasonablypolymorphic.com/blog/jj-strategy/index.html">blog
          post extolling Jujutsu</a>.</p>
          <p>I don’t have much to add to the posts from qword and Sandy, beyond
          the fact that <a href="https://martinvonz.github.io/jj/">Jujutsu</a>
          really is the perfect tool to make this workflow straightforward. The
          default change selection logic in <code>jj rebase</code> means that 9
          times out of 10 it’s enough just to run <code>jj rebase -d
          master</code> to get everything up to date with the master branch, and
          the Jujutsu workflow as a whole really is a great experience.</p>
          <p>So go forth, use Jujutsu to manage your dev branch, and hopefully
          I’ll never have to write another post on this, and you can have the
          traditional “I rewrote my blogging engine from scratch again” post
          that I’ve been <a
          href="https://git.sr.ht/~jshholland/inv.alid.pw/commit/49e87e3bb66f9c01bfff8fd277b7408e524c4ef2">owing</a>
          for a month or two now.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>More on git scratch branches: using stgit</title>
      <link>https://inv.alid.pw/posts/stgit-scratch/</link>
      <pubDate>Fri, 16 Apr 2021 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/stgit-scratch/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">More on git scratch branches: using
        stgit</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/stgit-scratch/" itemprop="url">16 April
        2021</a></time>
          </header>
        
          <p>I wrote <a href="/posts/git-scratch-branch/">a short post</a> last
          year about a useful workflow for preserving temporary changes in git
          by using a scratch branch. Since then, I’ve come across <a
          href="https://stacked-git.github.io/">stgit</a>, which can be used in
          much the same way, but with a few little bells and whistles on
          top.</p>
          <p>Let’s run through a quick example to show how it works. Let’s say I
          want to play around with the cool new programming language <a
          href="https://ziglang.org">Zig</a> and I want to build the compiler
          myself. The first step is to grab a source code checkout:</p>
          <pre><code>$ git clone https://github.com/ziglang/zig
        Cloning into &#39;zig&#39;...
        remote: Enumerating objects: 123298, done.
        remote: Counting objects: 100% (938/938), done.
        remote: Compressing objects: 100% (445/445), done.
        remote: Total 123298 (delta 594), reused 768 (delta 492), pack-reused 122360
        Receiving objects: 100% (123298/123298), 111.79 MiB | 6.10 MiB/s, done.
        Resolving deltas: 100% (91169/91169), done.
        $ cd zig
        </code></pre>
          <p>Now, according to the <a
          href="https://github.com/ziglang/zig/wiki/Building-Zig-From-Source#option-a-use-your-system-installed-build-tools">instructions</a>
          we’ll need to have CMake, GCC or clang and the LLVM development
          libraries to build the Zig compiler. On <a
          href="https://nixos.org/">NixOS</a> it’s usual to avoid installing
          things like this system-wide but instead use a file called
          <code>shell.nix</code> to specify your project-specific dependencies.
          So here’s the one ready for Zig (don’t worry if you don’t understand
          the Nix code, it’s the stgit workflow I really want to show off):</p>
          <pre><code>$ cat &gt; shell.nix &lt;&lt; EOF
        { pkgs ? import &lt;nixpkgs&gt; {} }:
        pkgs.mkShell {
          buildInputs = [ pkgs.cmake ] ++ (with pkgs.llvmPackages_12; [ clang-unwrapped llvm lld ]);
        }
        EOF
        $ nix-shell
        </code></pre>
          <p>Now we’re in a shell with all the build dependencies, and we can go
          ahead with the
          <code>mkdir build &amp;&amp; cd build &amp;&amp; cmake .. &amp;&amp; make install</code>
          steps from the Zig build instructions<a href="#fn1"
          class="footnote-ref" id="fnref1"
          role="doc-noteref"><sup>1</sup></a>.</p>
          <p>But now what do we do with that <code>shell.nix</code> file?</p>
          <pre><code>$ git status
        On branch master
        Your branch is up to date with &#39;origin/master&#39;.
        
        Untracked files:
          (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)
                shell.nix
        
        nothing added to commit but untracked files present (use &quot;git add&quot; to track)
        </code></pre>
          <p>We don’t really want to add it to the permanent git history, since
          it’s just a temporary file that is only useful to us. But the other
          options of just leaving it there untracked or adding it to
          <code>.git/info/exclude</code> are unsatisfactory as well: before I
          started using scratch branches and stgit, I often accidentally deleted
          my <code>shell.nix</code> files which were sometimes quite annoying to
          have to recreate when I needed to pin specific dependency versions and
          so on.</p>
          <p>But now we can use stgit to take care of it!</p>
          <pre><code>$ stg init # stgit needs to store some metadata about the branch
        $ stg new -m &#39;add nix config&#39;
        Now at patch &quot;add-nix-config&quot;
        $ stg add shell.nix
        $ stg refresh
        Now at patch &quot;add-nix-config&quot;
        </code></pre>
          <p>This little dance creates a new commit adding our
          <code>shell.nix</code> managed by stgit. You can <code>stg pop</code>
          it to unapply, <code>stg push</code><a href="#fn2"
          class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
          to reapply, and <code>stg pull</code> to do a <code>git pull</code>
          and reapply the patch back on top. The main <a
          href="https://stacked-git.github.io/guides/">stgit documentation</a>
          is helpful to explain all the possible operations.</p>
          <p>This solves all our problems! We have basically recreated the
          scratch branch from before, but now we have pre-made tools to apply,
          un-apply and generally play around with it. The only problem is that
          it’s really easy to accidentally push your changes back to the
          upstream branch.</p>
          <p>Let’s have another example. Say I’m sold on the stgit workflow, I
          have a patch at the bottom of my stack adding some local build tweaks
          and, on top of that, a patch that I’ve just finished working on that I
          want to push upstream.</p>
          <pre><code>$ cd /some/other/project
        $ stg series # show all my patches
        + add-nix-config
        &gt; fix-that-bug
        </code></pre>
          <p>Now I can use <code>stg commit</code> to turn my stgit patch into a
          real immutable git commit that stgit isn’t going to mess around with
          any more:</p>
          <pre><code>$ stg commit fix-that-bug
        Popped fix-that-bug -- add-nix-config
        Pushing patch &quot;fix-that-bug&quot; ... done
        Committed 1 patch
        Pushing patch &quot;add-nix-config ... done
        Now at patch &quot;add-nix-config&quot;
        </code></pre>
          <p>And now what we <em>should</em> do before <code>git push</code>ing
          is <code>stg pop -a</code> to make sure that we don’t push
          <code>add-nix-config</code> or any other local stgit patches upstream.
          Sadly it’s all too easy to forget that, and since stgit updates the
          current branch to point at the current patch, just doing
          <code>git push</code> here will include the commit representing the
          <code>add-nix-config</code> patch.</p>
          <p>The way to prevent this is through git’s hook system. Save this as
          <code>pre-push</code><a href="#fn3" class="footnote-ref" id="fnref3"
          role="doc-noteref"><sup>3</sup></a> (make sure it’s executable):</p>
          <pre><code>#!/bin/bash
        # An example hook script to verify what is about to be pushed.  Called by &quot;git
        # push&quot; after it has checked the remote status, but before anything has been
        # pushed.  If this script exits with a non-zero status nothing will be pushed.
        #
        # This hook is called with the following parameters:
        #
        # $1 -- Name of the remote to which the push is being done
        # $2 -- URL to which the push is being done
        #
        # If pushing without using a named remote those arguments will be equal.
        #
        # Information about the commits which are being pushed is supplied as lines to
        # the standard input in the form:
        #
        #   &lt;local ref&gt; &lt;local sha1&gt; &lt;remote ref&gt; &lt;remote sha1&gt;
        
        remote=&quot;$1&quot;
        url=&quot;$2&quot;
        
        z40=0000000000000000000000000000000000000000
        
        while read local_ref local_sha remote_ref remote_sha
        do
            if [ &quot;$local_sha&quot; = $z40 ]
            then
                # Handle delete
                :
            else
                # verify we are on a stgit-controlled branch
                git show-ref --verify --quiet &quot;${local_ref}.stgit&quot; || continue
                if [ $(stg series --count --applied) -gt 0 ]
                then
                    echo &gt;&amp;2 &quot;Unapplied stgit patch found, not pushing&quot;
                    exit 1
                fi
            fi
        done
        
        exit 0
        </code></pre>
          <p>Now we can’t accidentally<a href="#fn4" class="footnote-ref"
          id="fnref4" role="doc-noteref"><sup>4</sup></a> shoot ourselves in the
          foot:</p>
          <pre><code>$ git push
        Unapplied stgit patch found, not pushing
        error: failed to push some refs to &lt;remote&gt;
        </code></pre>
          <p>Happy stacking!</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>At the time of writing, Zig depends on the
          newly-released LLVM 12 toolchain, but this hasn’t made it into the
          nixos-unstable channel yet, so this probably won’t work on your actual
          NixOS machine.<a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          <li id="fn2"><p>an unfortunate naming overlap between pushing onto a
          stack and pushing a git repo<a href="#fnref2" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          <li id="fn3"><p>A somewhat orthogonal but also useful tip here so that
          you don’t have to manually add this to every repository is to
          configure git’s <code>core.hooksDir</code> to something like
          <code>~/.githooks</code> and put it there.<a href="#fnref3"
          class="footnote-back" role="doc-backlink">↩︎</a></p></li>
          <li id="fn4"><p>You can always pass <code>--no-verify</code> if you
          want to bypass the hook.<a href="#fnref4" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Setting up a dev environment for PostgreSQL with nixos-container</title>
      <link>https://inv.alid.pw/posts/nixos-container-postgres/</link>
      <pubDate>Sun, 12 Jul 2020 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/nixos-container-postgres/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Setting up a dev environment for
        PostgreSQL with nixos-container</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/nixos-container-postgres/" itemprop="url">12
        July 2020</a></time>
          </header>
        
          <p>I’ve been using <a href="https://nixos.org/">NixOS</a> for about a
          month now, and one of my favourite aspects is using <a
          href="https://github.com/target/lorri">lorri</a> and <a
          href="https://direnv.net/">direnv</a> to avoid cluttering up my user
          or system environments with packages I only need for one specific
          project. However, they don’t work quite as well when you need access
          to a <em>service</em> like PostgreSQL, since all they can do is
          install packages to an isolated environment, not run a whole RDBMS in
          the background.</p>
          <p>For that, I have found using <code>nixos-container</code> works
          very well. It’s documented in the <a
          href="https://nixos.org/nixos/manual/#ch-containers">NixOS manual</a>.
          We’ll be using it in ‘imperative mode’, since editing the system
          configuration is the exact thing we don’t want to do. You will need
          <code>sudo</code>/<code>root</code> access to start containers, and
          I’ll assume you have lorri and direnv set up (e.g. via
          <code>services.lorri.enable = true</code> in your home-manager
          config).</p>
          <p>We’ll make a directory to work in, and get started in the standard
          lorri way:</p>
          <pre><code>$ mkdir foo &amp;&amp; cd foo
        $ lorri init
        Jul 11 21:23:48.117 INFO wrote file, path: ./shell.nix
        Jul 11 21:23:48.117 INFO wrote file, path: ./.envrc
        Jul 11 21:23:48.117 INFO done
        direnv: error /home/josh/c/foo/.envrc is blocked. Run `direnv allow` to approve its content
        $ direnv allow .
        Jul 11 21:24:10.826 INFO lorri has not completed an evaluation for this project yet, expr: /home/josh/c/foo/shell.nix
        direnv: export +IN_NIX_SHELL
        </code></pre>
          <p>Now we can edit our <code>shell.nix</code> to install PostgreSQL to
          access it as a client:</p>
          <pre><code># shell.nix
        { pkgs ? import &lt;nixpkgs&gt; {} }:
        
        pkgs.mkShell {
          buildInputs = [
            pkgs.postgresql
          ];
        }
        </code></pre>
          <p>Save that and lorri will start installing it in the background.</p>
          <p>Now, we can define our container, by providing its configuration in
          a file. I have called it <code>container.nix</code>, but I don’t think
          there’s a standard name for it like there is for
          <code>shell.nix</code>. Here it is:</p>
          <pre><code># container.nix
        { pkgs, ... }:
        
        {
          system.stateVersion = &quot;20.09&quot;;
        
          networking.firewall.allowedTCPPorts = [ 5432 ];
        
          services.postgresql = {
            enable = true;
            enableTCPIP = true;
            extraPlugins = with pkgs.postgresql.pkgs; [ postgis ];
            authentication = &quot;host all all 10.233.0.0/16 trust&quot;;
        
            ensureDatabases = [ &quot;foo&quot; ];
            ensureUsers = [{
              name = &quot;foo&quot;;
              ensurePermissions.&quot;DATABASE foo&quot; = &quot;ALL PRIVILEGES&quot;;
            }];
          };
        }
        </code></pre>
          <p>It’s important to make sure the firewall opens the port so that we
          can actually access PostgreSQL, and I’ve also installed the postgis
          extension for geospatial tools. The <code>authentication</code> line
          means that any user on any container can authenticate as any user with
          no checking: fine for development purposes, but obviously be careful
          not to expose this to the internet! Finally, we set up a user and a
          database to do our work in.</p>
          <p>Now, we can actually create and start the container using the
          <code>nixos-container</code> tool itself. This is the only step that
          requires admin rights.</p>
          <pre><code>$ sudo nixos-container create foo --config-file container.nix
        $ sudo nixos-container start foo
        </code></pre>
          <p>By now, lorri should have finished installing PostgreSQL into your
          local environment, so once <code>nixos-container</code> has finished
          running, you should be able to access the new database inside the
          container:</p>
          <pre><code>$ psql -U foo -h $(nixos-container show-ip foo) foo
        psql (11.8)
        Type &quot;help&quot; for help.
        
        foo=&gt; \l
                                          List of databases
           Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
        -----------+----------+----------+-------------+-------------+-----------------------
         foo       | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres         +
                   |          |          |             |             | postgres=CTc/postgres+
                   |          |          |             |             | foo=CTc/postgres
         postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
         template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
                   |          |          |             |             | postgres=CTc/postgres
         template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
                   |          |          |             |             | postgres=CTc/postgres
        (4 rows)
        </code></pre>
          <p>And there we go! We have a container that we can access from the
          command line, or from an app, and we didn’t need to install PostgreSQL
          globally. We can even have multiple containers like this for different
          projects, and they’ll all use the same Nix store for binaries but have
          completely isolated working environments.</p>
          <p>The <code>nixos-container</code> tool itself is a fairly thin
          wrapper around <code>systemd</code> (the containers themselves work
          via <code>systemd-nspawn</code>). The containers won’t auto-start, and
          you have to use systemctl to make that happen:</p>
          <pre><code>$ sudo systemctl enable container@foo.service
        </code></pre>
          <p>As a final flourish, we can save having to type in the user, host
          IP and database with very little effort, since we’re already using
          direnv and most tools can take their PostgreSQL configuration from
          some standard environment variables. We just have to add them to our
          <code>.envrc</code> file, and then re-allow it.</p>
          <pre><code>$ cat .envrc
        PGHOST=$(nixos-container show-ip foo)
        PGUSER=foo
        PGDATABASE=foo
        export PGHOST PGUSER PGDATABASE
        
        eval &quot;$(lorri direnv)&quot;
        $ direnv allow .
        $ psql
        psql (11.8)
        Type &quot;help&quot; for help.
        
        foo=&gt;
        </code></pre>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Use a scratch branch in git</title>
      <link>https://inv.alid.pw/posts/git-scratch-branch/</link>
      <pubDate>Tue, 23 Jun 2020 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/git-scratch-branch/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Use a scratch branch in git</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/git-scratch-branch/" itemprop="url">23
        June 2020</a></time>
          </header>
        
          <p>git is the de facto standard for version control in 2020, and has
          held that position for some time. However, it holds a reputation of
          being difficult to use, and its toolkit-based design leaves a huge
          amount of room for different workflows. Here’s one that I’ve found
          useful recently:</p>
          <pre><code>git checkout -b scratch
        </code></pre>
          <p>That’s it! Well, to begin with at least. You’ll probably have to
          rebase it whenever you pull. But what is this branch for? It’s a
          general staging area, like a souped up <code>git stash</code>. Stashes
          are easy to create and apply, but they are also easy to lose and hard
          to share between computers. With a scratch branch, you can create as
          many staging commits as you want and push them to other computers if
          you need to. And once something’s been committed into git, it’s very
          very hard to lose it unless you are trying to.</p>
          <p>What’s this useful for? I had to apply a few tweaks to a work
          project’s build system to get it to build on <a
          href="https://nixos.org/">NixOS</a>, and I’m not sure if they are more
          generally applicable. But I want to keep them around for my personal
          use, so into my scratch branch they go. If later on I want to share
          them with my co-workers, I can just <code>git
          rebase -i</code> to tidy them up a bit, merge them into the main
          branch and push. Or I can just leave them there forever. It doesn’t
          matter!</p>
          <p>Stuff that’s only relevant to your own idiosyncratic setup
          shouldn’t be left sitting there uncommitted, at risk of causing merge
          conflicts or accidentally being squashed by a checkout: put it safely
          into your scratch branch and you can keep track of it with the full
          power of git as you need to. You can even have multiple scratch
          branches! Lightweight branches<a href="#fn1" class="footnote-ref"
          id="fnref1" role="doc-noteref"><sup>1</sup></a> are one of git’s most
          revolutionary features, and it’s easy to forget that you can use them
          in such a way.</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p><em>really</em> lightweight: a branch is just a file
          in <code>$GIT_DIR/refs/heads/&lt;name&gt;</code> containing a commit
          reference which all the git commands know how to manipulate. Try
          running <code>cat
          .git/refs/heads/master</code>.<a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Hakyll + sourcehut = ☺</title>
      <link>https://inv.alid.pw/posts/hakyll-sourcehut/</link>
      <pubDate>Wed, 29 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/hakyll-sourcehut/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Hakyll + sourcehut = ☺</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/hakyll-sourcehut/" itemprop="url">29 April
        2020</a></time>
          </header>
        
          <p>This blog is now automatically deployed by pushing to its source
          repository at <a href="https://sourcehut.org/">sourcehut</a>! Here are
          the steps I took to convert it from a manual rsync to a job run by <a
          href="https://builds.sr.ht/">builds.sr.ht</a> after each push to its
          git repository.</p>
          <p>The first step is to create an SSH key so that the build service
          can access the filesystem on the VPS hosting my blog. Obviously we
          can’t use a passphrase since we need it to connect without any human
          intervention. Easy enough with the usual command:</p>
          <pre><code>desktop $ ssh-keygen -t ed25519 -f srht
        </code></pre>
          <p>Then to the <a href="https://builds.sr.ht/secrets">secrets page</a>
          on sourcehut and upload the content of the <code>srht</code> file (NOT
          <code>srht.pub</code>) as a new secret with the type ‘SSH Key’ and a
          reasonable description. We’ll need to make a note of the UUID that got
          assigned; for me, it was
          <code>2959238e-ea6f-4276-9441-cdc71b933f73</code>.</p>
          <p>The next step is to set up the user that we will connect as from
          the sourcehut builds service. We’ll also need to make sure the
          ownership and permissions on the webroot are properly set up.</p>
          <pre><code>server # WEBROOT=/srv/inv.alid.pw
        server # adduser --system srht
        server # chsh -s /bin/sh srht
        server # chown -R srht:adm &quot;$WEBROOT&quot;
        server # chmod -R ug=rwX,o=rX &quot;$WEBROOT&quot;
        server # find $WEBROOT -type d -exec g+s {} +
        </code></pre>
          <p>I like to have files like this writable by an admin group so that I
          can delete stuff without having to be <code>root</code> myself, and
          the last command sets the setgid bit on all the directories so that
          newly-created files continue to belong to that group. That’s personal
          preference though: in the end, as long as the <code>srht</code> user
          can write there (and nowhere else) then everything should work just
          fine.</p>
          <p>We’ll also need to authorise the SSH key we generated to log in as
          the <code>srht</code> user, and we can restrict it to only run
          <code>rsync</code> at the same time. Take the content of the
          <code>srht.pub</code> file we generated earlier, and add it to
          <code>~srht/.ssh/authorized_keys</code>, along with the options to
          lock it down to rsync:</p>
          <pre><code>restrict,command=&quot;rrsync /srv/inv.alid.pw&quot; ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4E9kTv92l1NY1DgqXTnkHJWglVW+Laz6mQELviXzGI srht deployment
        </code></pre>
          <p><code>rrsync</code> is not a typo: it’s a script that comes with
          the rsync package (in Ubuntu, it’s installed to
          <code>/usr/share/doc/rsync/scripts/rrsync.gz</code>, so you’ll have to
          decompress it and copy it somewhere that shows up in the
          <code>srht</code> user’s <code>PATH</code>) that means logging in with
          the given SSH key can only run rsync in the specified directory.</p>
          <p>And that’s it for the server-side configuration! Now, we just have
          to fill in the <code>.build.yml</code> file to tell the sourcehut
          builders how to do all the deployment. Here it is, all in one go:</p>
          <pre><code>image: archlinux
        packages:
          - stack
          - rsync
        sources:
          - https://git.sr.ht/~jshholland/inv.alid.pw
        environment:
          user: srht
          webhost: procyon.chrys.alid.pw
          hostkey: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKemAh9xHg0lQBhwzVp9UemuSgaDqVC5Mwa+CmnXijP8
        secrets:
          - 2959238e-ea6f-4276-9441-cdc71b933f73
        tasks:
          - build: |
              cd inv.alid.pw
              stack install
              $HOME/.local/bin/site build
          - deploy: |
              mkdir -p $HOME/.ssh
              echo &quot;$webhost $hostkey&quot; &gt; $HOME/.ssh/known_hosts
              cd inv.alid.pw
              rsync -rlptzz --delete _site/ ${user}@${webhost}:
        </code></pre>
          <p>This ties everything together in two steps: first we compile the
          <code>site</code> binary that generates the website structure in
          <code>_site</code>, then, in the deploy task, we set up SSH and rsync
          the files into place. That’s it! We just have to save this into our
          repo and everything will just happen automagically when we push new
          commits.</p>
          <p>One issue I have at the moment (and probably the reason I’m only
          finishing this now, when I first started trying to set this up <a
          href="https://squ.alid.pw/notice/9oy8rW15BYFhsYMaES">back in
          November</a>) is that it takes a <em>long</em> time for the build
          server to download and compile all the Haskell dependencies,
          particularly Pandoc. In the long term, a half-hour delay to publishing
          isn’t that bad, but it’s a little annoying. Next on my list is to try
          building this with NixOS (instead of Stack) to see if the binary
          caching provided there speeds things up a bit.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for November 2019</title>
      <link>https://inv.alid.pw/posts/links-nov-2019/</link>
      <pubDate>Fri, 01 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-nov-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for November 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-nov-2019/" itemprop="url">1 November
        2019</a></time>
          </header>
        
          <p>I missed posting an October links post, so here is a ‘bumper’
          edition, with lots of clickbait titles because I need that
          engagement.</p>
          <p><a
          href="https://randomascii.wordpress.com/2019/09/08/taskbar-latency-and-kernel-calls/">‘Explorer
          takes 700 ms to put up a task-bar context menu.’</a> The reason is
          frankly terrifying, and makes me feel a lot better about all of the
          dumb code that I write.</p>
          <p>A beautiful interactive graphical <a
          href="http://www.jezzamon.com/fourier/">introduction to Fourier
          transforms</a>. Now you too can make your own colossal mess of
          epicycles that draws a phallus!</p>
          <p>How programming languages should report string length and the
          relative fairness of text encodings for different languages: <a
          href="https://hsivonen.fi/string-length/">much more than you wanted to
          know</a>.</p>
          <p>The expected time to check whether a list is sorted may not be <a
          href="http://blog.nodenexus.com/2016/10/29/average-array-issorted-performance/">what
          you expect</a>.</p>
          <p>It turns out that 1970s-era <code>/etc/passwd</code> files are no
          match for modern hardware, and it is therefore possible to crack <a
          href="https://leahneukirchen.org/blog/archive/2019/10/ken-thompson-s-unix-password.html">Ken
          Thompson’s password</a>.</p>
          <p><a href="https://en.wikipedia.org/wiki/Joanna_Southcott">Joanna
          Southcott</a> was an 18th-century English woman who claimed to be the
          Woman of the Apocalypse and subsequently was allegedly pregnant with
          the Messiah (although the baby never actually appeared). She left a
          box of sealed prophecies and in the 1920s there was a major public
          campaign for it to be opened. The most interesting part is that she
          still has <a href="http://panaceatrust.org/">followers</a> (despite
          her prophecy of the end of the world in 2004 manifestly not being
          fulfilled), although they have understandably downplayed the weird
          millenarianism.</p>
          <blockquote>
          <p>‘Mordor’s dead cities, craggy mountains haunted by giant
          demon-spiders, black deserts, dark towers, and fiery chasms certainly
          intimidated foreign visitors, much like the National Mall in
          Washington, D.C.’</p>
          </blockquote>
          <p>An <a
          href="https://foreignpolicy.com/2019/10/21/trump-administration-mordor-failed-hegemon-tolkien/">analogy</a>
          between the Trump administration and the reign of the Dark Lord
          Sauron.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Dear Mr Walker</title>
      <link>https://inv.alid.pw/posts/dear-mr-walker/</link>
      <pubDate>Tue, 03 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/dear-mr-walker/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Dear Mr Walker</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/dear-mr-walker/" itemprop="url">3
        September 2019</a></time>
          </header>
        
          <p>Once again the House of Commons has infuriated me sufficiently that
          I felt the need to contact my MP. Once again, I am publishing my
          correspondence in the hope that it normalises people beyond the
          stereotypical ‘green ink brigade’ to <a
          href="https://www.writetothem.com/">write to them</a>.</p>
          <p>I am (for the moment) in Worcester, so it’s a different MP (and a
          different party) to last time, but that means little.</p>
          <blockquote>
          <p>Dear Robin Walker,</p>
          <p>I am writing this as I watch the debate on Oliver Letwin’s motion
          for Parliament to debate a bill preventing a no-deal Brexit. I voted
          to remain, but I am happy to acknowledge the result of the referendum,
          and would accept a soft Brexit, perhaps along the Norway model or some
          sort of customs union. No deal would be a disaster on many fronts: the
          unsolvability of the Irish border question, the possibility of food
          medicine shortages (pertinent to myself as an insulin-dependent
          diabetic) and the economic impact. It must be avoided.</p>
          <p>The decision of your party’s Government to prorogue Parliament is a
          dangerous precedent to set, and hearing the Leader of the House of
          Commons discuss the mandate and sovereignty of the House he sits in is
          what spurs me to write this to you now. We live in a representative
          democracy, not a direct one, and I wish you, as my representative, to
          take my views into serious consideration. I urge you to do what you
          can to avert the worst-case scenario of a no-deal Brexit.</p>
          <p>Yours sincerely,</p>
          <p>Joshua Holland</p>
          </blockquote>
          <p>Again I have forgotten to mention recent protests. Perhaps I will
          have the opportunity to vote against him soon anyway; who can possibly
          say in such times.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for September 2019</title>
      <link>https://inv.alid.pw/posts/links-sep-2019/</link>
      <pubDate>Tue, 03 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-sep-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for September 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-sep-2019/" itemprop="url">3
        September 2019</a></time>
          </header>
        
          <p>Mark Dominus points out that the Classical <a
          href="https://blog.plover.com/book/myth/princess-andromeda.html">Princess
          Andromeda</a>, rescued by Perseus from Cetus, was in fact an
          Aethiopian princess, and therefore extremely unlikely to be the white
          maiden often depicted in Western art. On the other hand, Wikipedia <a
          href="https://en.wikipedia.org/wiki/Andromeda_(mythology)#Ethnicities_of_Andromeda">points
          out</a> that Aethiopia (or more properly Αἰθιοπία, deriving from
          ‘sun-burnt’) is distinct from modern Ethiopia, and is a general
          designation for ‘the land of dark people’, which could be anything
          from modern Ethiopia to India or Indonesia.</p>
          <p>Without further comment: <a
          href="https://github.com/boyEstrogen/Anime-Girls-Holding-Programming-Books/">Anime
          Girls Holding Programming Books</a>.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for August 2019</title>
      <link>https://inv.alid.pw/posts/links-aug-2019/</link>
      <pubDate>Tue, 06 Aug 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-aug-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for August 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-aug-2019/" itemprop="url">6 August
        2019</a></time>
          </header>
        
          <p>Again I’m a few days late with these links. I hope nobody has been
          kept up all night worrying.</p>
          <p>The Fediverse is a network of mostly-compatible software that got a
          big spike a couple of years ago as part of a Twitter backlash; the
          software that runs <a href="https://squ.alid.pw/josh">my instance</a>,
          recently hit its <a
          href="https://blog.soykaf.com/post/pleroma-1.0/">1.0 release</a>.</p>
          <p>GPG/PGP has long been derided for its complete failure to penetrate
          the mainstream. This is mostly due to its terrible UX, bending over
          backwards to support old crypto, and trying to be jack of all trades,
          master of none, as explained in this <a
          href="https://latacora.micro.blog/2019/07/16/the-pgp-problem.html">excellent
          blog post</a>. Some of the recommended alternatives are better than
          others. <a href="https://github.com/warner/magic-wormhole">Magic
          Wormhole</a>, new to me, seems like an extremely useful tool to have
          in one’s back pocket.</p>
          <p><a
          href="https://golem.ph.utexas.edu/category/2012/01/vorsicht_funktor.html">‘Caution!
          Functor! Keep 2m back.’</a> A common response to category theory.</p>
          <p><a href="https://en.wikipedia.org/wiki/General_Butt_Naked">General
          Butt Naked</a> sounds like he should come from a Far Cry game or
          something, but was actually a horrifying Liberian warlord who claimed
          to have killed over 20,000 people and fought nude because he believed
          it would protect him from bullets. However, in 1996 he converted to
          Christianity after a vision of Christ told him to repent and his since
          become a preacher, even at one point expressing his willingness to be
          tried at the Hague. While this might give hope that anyone can be
          reformed, he still claims that he was under Satanic influence during
          his rampages, which probably takes something away from it.</p>
          <p>In 1809, a man made a bet that he could make any house in London
          into the most talked about address in a week. The result was the <a
          href="https://en.wikipedia.org/wiki/Berners_Street_hoax">Berners
          Street hoax</a>, in which he requested more or less every tradesman in
          London come to 57 Berners Street to provide their services to a Mrs
          Tottenham. Even the Lord Mayor of London turned up!</p>
          <p>A slightly less famous English mayor is that <a
          href="https://en.wikipedia.org/wiki/Mayor_of_High_Wycombe">of High
          Wycombe</a>. This is a shame, because due to some historically
          corrupt, drunken and generally useless incumbents, each outgoing mayor
          is ‘tolled out’ by the ringing of the city bells, and subsequently
          weighed to ensure that they have not gained any weight at the
          taxpayers’ expense.</p>
          <p>Today’s feel-good story to end: the world of <a
          href="https://www.theguardian.com/lifeandstyle/2019/jul/19/experience-my-dog-is-a-champion-surfer">competitive
          dog surfing</a>.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for July 2019</title>
      <link>https://inv.alid.pw/posts/links-jul-2019/</link>
      <pubDate>Wed, 03 Jul 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-jul-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for July 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-jul-2019/" itemprop="url">3 July
        2019</a></time>
          </header>
        
          <p>If anyone has been wondering what Tom DeLonge has been up to since
          he left Blink-182 in 2014, it turns out he founded the <a
          href="https://coi.tothestarsacademy.com/">To The Stars Academy of Arts
          and Science</a>, which mostly seems to focus on collecting UFO videos
          and images. Unfortunately, a 2018 <a
          href="https://www.sec.gov/Archives/edgar/data/1710274/000114420418050766/tv503167_1sa.htm">SEC
          report</a> stated that it ‘has incurred losses from operations and has
          an accumulated deficit at June 30, 2018 of $37,432,000. These factors
          raise doubt about the Company’s ability to continue as a going
          concern’, so I guess someone else will have to save us from the alien
          menace or the secret US government spy planes or whatever these UFOs
          really are.</p>
          <p>IRC/Slack/Discord replacement/competitor Matrix has <a
          href="https://matrix.org/blog/2019/06/11/introducing-matrix-1-0-and-the-matrix-org-foundation/">released
          as 1.0</a>. I think I want this to work, since IRC has problems, and
          have had a rambly draft on the matter for quite a while. But see also
          Drew DeVault on why the <a
          href="https://drewdevault.com/2019/07/01/Absence-of-features-in-IRC.html">lack
          of features in IRC is a feature</a>.</p>
          <p><a href="">‘Sega Toylet’</a> is frankly an amazing brand name,
          although I’m not sure whether it should really exist as a commercial
          product. At least there is no Sonic tie-in (yet?).</p>
          <p>A fascinating but sad feature on the likely fate of <a
          href="https://www.theatlantic.com/magazine/archive/2019/07/mh370-malaysia-airlines/590653/">Malaysia
          Airlines Flight MH370</a> from pilot-turned-journalist William
          Langewiesche.</p>
          <p>After many years of resistance, I recently started using an
          adblocker, due to articles like <a
          href="https://lockwood.dev/advertising/2019/06/07/adtech-sucks.html">these</a>
          <a
          href="https://lockwood.dev/advertising/2019/06/14/adtech-sucks-this-time-its-personal-ids.html">two</a>
          from an ex-adtech worker. Back in 2015, <a
          href="https://idlewords.com/2015/11/the_advertising_bubble.htm">Idle
          Words</a> predicted the bursting of the adtech bubble, and I’m now
          trying to avoid using services that rely on advertising for their
          business model. My preference for free software (self-hosted or
          otherwise) followed by an upfront paid service puts me in mind of <a
          href="">David R Maciver’s excellent <em>How to write good
          software</em></a>, which I more-or-less entirely agree with.</p>
          <p>In the frontier days of the Western US from the 1890s to 1930s, the
          unpredictability of mining towns springing up or going bust meant that
          it was hard for churches to be established. The solution that some
          came up with was the <a
          href="https://en.wikipedia.org/wiki/Railroad_chapel_car">railroad
          chapel car</a>: simply take a regular train carriage, add an altar and
          some pews, put it on a train to wherever the people are, then leave it
          in a siding until the mine runs dry and cart it off somewhere
          else.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for June 2019</title>
      <link>https://inv.alid.pw/posts/links-jun-2019/</link>
      <pubDate>Sat, 01 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-jun-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for June 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-jun-2019/" itemprop="url">1 June
        2019</a></time>
          </header>
        
          <blockquote>
          <p>Theorem 1: Determining the outcome of a game of Magic: The
          Gathering in which all remaining moves are forced is undecidable.</p>
          <p>An example 60-card deck that is capable of executing this
          construction on the first turn of the game and which is legal in the
          competitive Legacy format can be seen in Table III.</p>
          </blockquote>
          <p><a href="https://arxiv.org/pdf/1904.09828.pdf">Yet another fun
          Turing-completeness proof</a>; the undecidability is of course via a
          reduction to the Halting Problem.</p>
          <p>Since apparently these links posts are just ‘Things that shouldn’t
          be TC but are’, another Turing-complete game is <a
          href="https://www.twitlonger.com/show/n_1sqrh1m">Baba is You</a>
          (which I haven’t played yet, but all reviews indicate that it is very
          good).</p>
          <p>Things <a
          href="https://www.businessfast.co.uk/why-life-in-the-uk-feels-better-than-ever/">aren’t
          as bad</a> as you think (at least in the UK).</p>
          <p>Relatedly(?), an Essex man has set the record for the <a
          href="https://www.theguardian.com/world/2019/may/13/essex-businessman-sets-first-tuk-tuk-land-speed-record">land
          speed record in a tuk-tuk</a>.</p>
          <p>The <a
          href="https://en.wikipedia.org/wiki/Voynich_manuscript">Voynich
          manuscript</a> has (once again) allegedly been <a
          href="https://www.tandfonline.com/doi/full/10.1080/02639904.2019.1599566">deciphered</a>,
          although it seems unlikely to be correct. <a
          href="https://arstechnica.com/science/2019/05/no-someone-hasnt-cracked-the-code-of-the-mysterious-voynich-manuscript/">Ars
          Technica</a> and <a
          href="https://languagelog.ldc.upenn.edu/nll/?p=42749">Language Log</a>
          analyse this most recent attempt.</p>
          <p><a href="https://thepersistenceofchaos.com/">The Persistence of
          Chaos</a> is an art piece consisting of an airgapped 2008 laptop
          ‘running 6 pieces of malware that have caused financial damages
          totaling $95B’. It was auctioned off for $1.345M.</p>
          <p>This <a
          href="https://www.youtube.com/channel/UCij19II32Olbu8_vghmYNCA">YouTube
          channel</a> uploads <a
          href="https://www.youtube.com/watch?v=yaTCzCQFFiY">videos</a> of dogs
          being groomed and it is the most relaxing thing I have found in the
          last few years.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Children, parents and adults</title>
      <link>https://inv.alid.pw/posts/children-parents-adults/</link>
      <pubDate>Sat, 11 May 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/children-parents-adults/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Children, parents and adults</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/children-parents-adults/" itemprop="url">11
        May 2019</a></time>
          </header>
        
          <p>I mostly learned to drive from my dad, but after I passed my test I
          did a Pass Plus course subsidised by the local council. It covered
          things like motorway driving and handling unusual weather, but it was
          also interesting to learn from another instructor.</p>
          <p>One thing this new instructor told me was that there are three
          different types of drivers: children, parents and adults. Of course
          the names don’t relate to the actual age or familial situation of the
          drivers, but their approach to the road. Recently I’ve realised that
          it’s a useful mental taxonomy to have in other situations as well.</p>
          <p>Children are in a rush to get wherever it is they are going, with
          no concern for those around them: the boy racers trying to impress the
          girl in the passenger seat, the elderly people who really shouldn’t
          still be driving, and all the people who have had one too many drink
          trying to get home from the pub. Obviously this is not something to
          emulate.</p>
          <p>The parents focus above all on worrying about the children. They
          are most susceptible to road rage, and will often pay less attention
          to their own driving than tutting at the driver who just overtook on
          the inside at 85 mph. They know better than the children, but not
          better enough just to take care of themselves.</p>
          <p>This leaves the adults as the model to strive for: safe and
          sensible drivers in their own right, who allow the children a wide
          enough berth to grow up without our oversight (and without crashing
          into us!).</p>
          <p>This is something that a lot of philosophies over the ages have
          suggested: the <a
          href="https://en.wikipedia.org/wiki/Stoicism">Stoics</a> of ancient
          Greece would see a lot in common, and Niebuhr’s famous Serenity Prayer
          also gestures in the same direction:</p>
          <blockquote>
          <p>God, grant me the serenity to accept the things I cannot
          change,<br />
          Courage to change the things I can,<br />
          And wisdom to know the difference.</p>
          </blockquote>
          <p>But this is a framing I’ve never heard from anywhere else, and it’s
          one that’s stuck in my mind for a long time. I hope it’s useful for
          someone else as well.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for May 2019</title>
      <link>https://inv.alid.pw/posts/links-may-2019/</link>
      <pubDate>Wed, 01 May 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-may-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for May 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-may-2019/" itemprop="url">1 May
        2019</a></time>
          </header>
        
          <p>The New Yorker reports on the fascinating <a
          href="https://www.newyorker.com/magazine/2019/04/08/the-day-the-dinosaurs-died">discovery</a>
          of a site which may preserve the day of the Chixculub impact, often
          blamed for the K-T extinction. Of course there are criticisms and
          doubts, but I’m sure that this is an important site regardless.</p>
          <p>What does that famous black hole picture actually represent? Matt
          Strassler <a
          href="https://profmattstrassler.com/2019/04/09/a-non-experts-guide-to-a-black-holes-silhouette/">explains</a>.</p>
          <p><a href="https://www.youtube.com/watch?v=5TFDG-y-EHs">This</a> (<a
          href="http://radar.spacebar.org/f/a/weblog/comment/1/1168">non-video
          link</a>) is one of the most perverse uses of a computer I have ever
          seen. The insane mind behind it, <a href="http://tom7.org/">Tom 7</a>,
          has also produced a number of other mind-melting projects, including a
          <a href="http://tom7.org/abc/">C compiler which produces executables
          consisting only of ASCII printable bytes</a>.</p>
          <p>Super Tux Kart, a totally original game that is in no way inspired
          by any other kart racing games, which I used to play when I first got
          into Linux about 10 years ago, is apparently still being developed and
          just had its <a
          href="http://blog.supertuxkart.net/2019/04/supertuxkart-10-release.html">1.0
          release</a> which includes netplay.</p>
          <p>Slate Star Codex <a
          href="https://slatestarcodex.com/2019/04/22/1960-the-year-the-singularity-was-cancelled/">recounts</a>
          the theories of human population modeller Heinz von Foerster’s 1960
          paper and postulates mechanisms around the interactions of population
          growth, technological progress and the economy. The real interplay is
          no doubt far too complicated for us to understand, but this seems like
          a reasonable approximation.</p>
          <p><a
          href="https://twitter.com/DataPup_/status/1121104622641451009">Lashon
          Hara</a> is the proscribed Jewish concept of ‘Evil Tongue’ (link via
          <a
          href="https://notebook.drmaciver.com/posts/2019-04-26-07:48.html">David
          MacIver</a>). Especially in the context of modern social media,
          mindfulness about what one is saying and, more importantly, what
          purpose saying it serves is vital, especially since we haven’t really
          internalised the dynamics of a massive public discourse arena.</p>
          <p>Readers may have heard of the 3750-year-old Babylonian <a
          href="https://en.wikipedia.org/wiki/Complaint_tablet_to_Ea-nasir">tablet</a>
          complaining of a copper merchant’s inferior quality ingots and rude
          treatment of his messenger. What is less well-known is that (perhaps
          inevitably) this has led to a certain amount of <a
          href="https://archiveofourown.org/works/9008380?view_adult=true">slash
          fiction</a> (NSFW text) being written about Ea-nasir and Nanni. AO3
          has no fewer than <a
          href="https://archiveofourown.org/tags/Mesopotamian%20RPF/works">6
          other stories</a> inspired by this tablet. (This one via <a
          href="https://blog.plover.com/book/best-fanfic-this-month.html">Mark
          Dominus</a>.)</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for April 2019</title>
      <link>https://inv.alid.pw/posts/links-apr-2019/</link>
      <pubDate>Mon, 01 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-apr-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for April 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-apr-2019/" itemprop="url">1 April
        2019</a></time>
          </header>
        
          <p>These links were collected over March, so I will presumably be a
          month late with the various internet tomfoolery associated with this
          post’s publication date.</p>
          <p><a
          href="https://en.wikipedia.org/wiki/Berkson&#39;s_paradox">Berkson’s
          paradox</a> is a counterintuitive result which most often manifests as
          falsely observing a negative correlation between independent variables
          when one mistakenly only sees cases when at least one of them occurs.
          Wikipedia’s example: ‘For example, a person may observe from their
          experience that fast food restaurants in their area which serve good
          hamburgers tend to serve bad fries and vice versa; but because they
          would likely not eat anywhere where both were bad, they fail to allow
          for the large number of restaurants in this category which would
          weaken or even flip the correlation.’ Probably a useful concept to
          have a handle for.</p>
          <p><a href="https://twitter.com/ColinTheMathmo">Colin Wright</a> is
          mostly famous for inventing the juggling notation known as ‘siteswap’,
          but was in fact a maths PhD supervised by Béla Bollabás at Cambridge.
          He has a blog full of interesting puzzles and others, including a
          series of twists on the classical ‘rope around the Earth’ problem. <a
          href="https://www.solipsys.co.uk/new/TheOtherWrappingTheEarthProblem.html">This
          one</a> is my favourite.</p>
          <p>During the Second World War, the US was developing a revolutionary
          new method of incendiary bomb delivery: <a
          href="https://en.wikipedia.org/wiki/Bat_bomb">hibernating bats</a>. It
          was only cancelled because the Manhattan project was progressing more
          quickly. I can only wonder at the world in which incendiary bat bombs
          were the threat on which the Cold War was built instead of nuclear
          weapons.</p>
          <p><a
          href="https://jameshfisher.com/2019/03/08/why-cant-i-set-the-font-size-of-a-visited-link">Why
          can’t font size be set on <code>a:visited</code>?</a> Surprising
          things that have to be done in the name of privacy.</p>
          <p>OpenType font shaping is <a
          href="https://litherum.blogspot.com/2019/03/addition-font.html">Turing
          complete</a>, although this requires a custom HarfBuzz build to
          increase the recursion limit past 6.</p>
          <p>Also Turing complete is <a
          href="https://www.cl.cam.ac.uk/~sd601/papers/mov.pdf">the x86
          instruction set, but using only <code>mov</code></a>. I am once again
          reminded that Turing-completeness is not a high bar.</p>
          <p><a
          href="https://www.eugenewei.com/blog/2019/2/19/status-as-a-service">Long
          post on Status as a Service</a>, and how social capital is the real
          motive behind people’s behaviour on social networks.</p>
          <p><a
          href="https://www.nytimes.com/2019/02/12/magazine/climeworks-business-climate-change.html">NYT
          article on a carbon dioxide scrubbing startup.</a> Encouraging ideas,
          but seems energetically implausible. <a
          href="https://johncarlosbaez.wordpress.com/2019/03/02/negative-carbon-emissions/">John
          Baez</a> writes about similar ideas.</p>
          <p>‘Why are you reading about <a
          href="https://www.roadlessrevolution.com/2019/02/why-giant-airships-could-be-trillion.html">airships</a>?’
          ‘Because airships are cool.’ Back-of-the-envelope calculations
          (admittedly by an airship blog) suggest that giant cargo airships
          could be a trillion dollar industry (the calculations are rough enough
          that what we mean by that doesn’t matter: could be market cap,
          revenue, value of assets…). They offer a previously nonexistent
          low-cost, medium speed transport method that is agnostic of land or
          sea. From the point of view of carbon, they are encouraging in that
          they only require energy to go forwards, although drag is a big
          concern and hydrogen is fairly expensive to produce.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Dear Dr Whitehead</title>
      <link>https://inv.alid.pw/posts/dear-dr-whitehead/</link>
      <pubDate>Tue, 26 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/dear-dr-whitehead/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Dear Dr Whitehead</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/dear-dr-whitehead/" itemprop="url">26
        March 2019</a></time>
          </header>
        
          <p>After the House of Commons <a
          href="https://www.bbc.co.uk/news/uk-politics-47701591">voted</a> last
          night for ‘indicative votes’, there has probably never been a better
          time to <a href="https://www.writetothem.com/">write to your MP</a>,
          regardless of your opinions on Brexit or the Government’s handling of
          it. Representative democracy works best when the representatives know
          what their constituents want, and they can only do that if we tell
          them. Below is what I wrote: feel free to critique or use it as
          inspiration for your own correspondence.</p>
          <blockquote>
          <p>Dear Dr Whitehead,</p>
          <p>I am pleased to see that you voted in favour of both the Beckett
          and Letwin amendments last night, and am writing to you today with my
          views on how Parliament should take control of the Brexit process. I
          am also pleased to see the posts on your website which align largely
          with my views on a People’s Vote to break the parliamentary deadlock
          and, if that happens, campaigning to revoke Article 50 and remain in
          the EU.</p>
          <p>People should be allowed, and even encouraged, to change their mind
          when presented with new evidence, and when the referendum nearly three
          years ago was so close, it seems perverse to call it undemocratic not
          to ask the people of this country what they think now that the
          difficulty of leaving the EU has been demonstrated (although the
          incompetence of the May Government has probably exaggerated it
          somewhat).</p>
          <p>I remain in favour if not of outright revocation of retaining the
          closest ties with our European neighbours possible; whether that is
          means ‘Norway-plus’, customs union or something else I am not familiar
          enough with the options to say. I would also hope for some form of
          compromise solution, something that the Government has so far been
          unable to deliver with their entirely inflexible red lines.</p>
          <p>Yours sincerely,</p>
          <p>Joshua Holland</p>
          </blockquote>
          <p>Having now sent and re-read it, I’m slightly annoyed that I forgot
          to mention the <a
          href="https://www.bbc.co.uk/news/uk-politics-47678763">People’s
          March</a> and the <a
          href="https://odileeds.org/projects/petitions/241584">petition</a>,
          but maybe it’s better to keep things short and to the point. I can
          only now hope that Parliament can finally get things unstuck and make
          some forward progress.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Worstsort revisited: Is Haskell's type system stronger?</title>
      <link>https://inv.alid.pw/posts/worstsort-revisited/</link>
      <pubDate>Thu, 14 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/worstsort-revisited/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Worstsort revisited: Is Haskell’s
        type system stronger?</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/worstsort-revisited/" itemprop="url">14
        March 2019</a></time>
          </header>
        
          <p><a href="/posts/worstsort-rust">My recent post</a> about worstsort
          has a problem: the code doesn’t actually work at all. I first had
          issues when I was rejigging it to fit the API of the <a
          href="https://crates.io/crates/sorting">sorting</a> crate, and then
          when adding tests. <a
          href="https://nest.pijul.com/jshholland/worstsort:master/9412043f2654c51317">The
          latest code</a> on Pijul Nest has the tests, so you can download it
          and play along at home:</p>
          <pre><code>$ cargo build
           Compiling worstsort v0.1.0 (/home/josh/r/worstsort)
            Finished dev [unoptimized + debuginfo] target(s) in 0.21s
        $ cargo test
           Compiling worstsort v0.1.0 (/home/josh/r/worstsort)
        error: reached the recursion limit while instantiating `badsort::&lt;s
        td::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Ve
        c&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec:
        :Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::v
        ec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std
        ::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;
        std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::V
        ec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec
        ::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::
        vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;st
        d::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec
        &lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::
        Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::ve
        c::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;std:
        :vec::Vec&lt;std::vec::Vec&lt;std::vec::Vec&lt;i32&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
        &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;`
          --&gt; src/lib.rs:30:1
           |
        30 | / pub fn badsort&lt;T: Ord + Clone&gt;(k: usize, l: &amp;mut [T]) {
        31 | |     if k == 0 {
        32 | |         bubblesort(l);
        33 | |     } else {
        ...  |
        37 | |     }
        38 | | }
           | |_^
        
        error: aborting due to previous error
        
        error: Could not compile `worstsort`.
        
        To learn more, run the command again with --verbose.
        </code></pre>
          <p>That’s quite an error! I posted this problem on <a
          href="https://stackoverflow.com/questions/54943698/recursion-limit-when-instantiating-unused-rust-type">Stack
          Overflow</a> and got some interesting replies.</p>
          <p>To explain what’s going on, remember how <a
          href="https://doc.rust-lang.org/book/ch10-01-syntax.html">Rust
          generics</a> work. The key idea is <em>monomorphisation</em>: the
          compiler generates specialised code essentially by copy-and-pasting
          for every type a generic function is called with<a href="#fn1"
          class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.
          Let’s do this by hand. If we aren’t compiling in testing mode,
          <code>badsort</code> is never called, so the compiler doesn’t have to
          generate any code for it. In <code>tests::badsort_zero</code>, the
          type <code>T</code> is instantiated as <code>Vec&lt;i32&gt;</code>, so
          the compiler has to produce code for <code>badsort_veci32</code>. As
          it does that, it encounters another call to <code>badsort</code>, but
          this time it’s on the <em>permutations</em> of the list, so
          <code>T</code> is now <code>Vec&lt;Vec&lt;i32&gt;&gt;</code>. This
          means it has to generate <code>badsort_vecveci32</code>, and then from
          there it will keep going forever.</p>
          <p>So, there are two key questions: why was this <em>not</em> a
          problem for Haskell, and is there a way to get round it in Rust? At
          the moment, I don’t know! I hope to get some free time to investigate
          this at some point, and I’ll definitely write up whatever I find on
          here.</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>I’m glossing over trait bounds since they aren’t
          relevant for this problem.<a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Links for March 2019</title>
      <link>https://inv.alid.pw/posts/links-mar-2019/</link>
      <pubDate>Fri, 01 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/links-mar-2019/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Links for March 2019</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/links-mar-2019/" itemprop="url">1 March
        2019</a></time>
          </header>
        
          <p>This is the first monthly-ish collection of interesting links I
          have read online, with some thoughts about each one. There aren’t as
          many as there might usually be in this one because I only started
          collecting them this week.</p>
          <p>David R. MacIver writes about ‘<a
          href="https://notebook.drmaciver.com/posts/2019-02-27-12:03.html">the
          Core Problem with Democracy</a>’. Under some (unrealistic?)
          independence assumptions, a vote on ‘A and B’ may fail, even if most
          of the population individually believe A and B. I wonder how related
          this is to <a
          href="https://en.wikipedia.org/wiki/Simpson%27s_paradox">Simpson’s
          paradox</a>. The conclusion includes the interesting observation that
          democracy often conflates values (‘how should the world look?’) and
          judgement (‘how do we make the world look that way?’). Robin Hanson’s
          ‘<a href="http://mason.gmu.edu/~rhanson/futarchy.html">futarchy</a>’
          responds to this distinction, and so does Scott Alexander’s fictional
          <a
          href="https://slatestarcodex.com/2013/05/06/raikoth-laws-language-and-society/">Shining
          Garden</a>.</p>
          <p>Today’s ‘don’t believe anything you read on the internet’ article:
          <a
          href="https://gizmodo.com/the-fake-sex-doctor-who-conned-the-media-into-publicizi-1832711205">Gizmodo</a>
          exposes ‘Dr.’ David Sendler, whose studies have led to articles in
          places from Forbes to <a href="https://www.savagelovecast.com/">Savage
          Lovecast</a>, as a ‘serial fabulist’. I’m not sure whether the
          widespread media coverage he has attracted or the possibility that he
          is fraudulently seeing (potentially very vulnerable) patients is more
          concerning. The way he talks about his upcoming study on suicide, on
          subjects he found by searching social media(!), are particularly
          alarming.</p>
          <p><a href="https://commento.io/">Commento</a> is a Disqus-like
          commenting platform which emphasises privacy and speed. A paid hosted
          version is available, but it’s <a
          href="https://gitlab.com/commento/commento">open-source</a> and so
          self-hosting is an option (and now operational on this site, after
          much faffing with probably pointless Content-Security-Policy options).
          I hadn’t enabled comments here before because I don’t particularly
          trust a service like Disqus, and other solutions are a pain with a
          statically generated site. The one hesitation I had before installing
          Commento is being slightly distrustful of requiring Javascript, which
          was previously only ‘necessary’ to view rendered MathJax, which
          somewhat gracefully degrades to the raw TeX code. Also, in 2019, it
          doesn’t seem too onerous to require JS for something non-essential
          like comments.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Worstsort in Rust</title>
      <link>https://inv.alid.pw/posts/worstsort-rust/</link>
      <pubDate>Thu, 28 Feb 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/worstsort-rust/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Worstsort in Rust</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/worstsort-rust/" itemprop="url">28
        February 2019</a></time>
          </header>
        
          <p><a href="https://byorgey.wordpress.com/2019/02/16/worstsort/">Brent
          Yorgey</a> shares a fun 2012 <a
          href="https://sites.math.northwestern.edu/~mlerma/papers/inefficient_algorithms.pdf">paper</a>
          by Miguel A. Lerma about the worst possible<a href="#fn1"
          class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
          sorting algorithm, along with a cute Haskell implementation. The
          algorithm depends on a function
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo>:</mo><mi>ℕ</mi><mo>→</mo><mi>ℕ</mi></mrow><annotation encoding="application/x-tex">f:
          \mathbb{N} \to \mathbb{N}</annotation></semantics></math> and runs in
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Ω</mi><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Omega(f(n))</annotation></semantics></math>
          time; in other words, we can take at least as long as <em>any</em>
          computable function (in fact, much much longer).</p>
          <p>Naturally I felt compelled to write up <a
          href="https://nest.pijul.com/jshholland/worstsort">an
          implementation</a> in my new favourite language, <a
          href="https://www.rust-lang.org/">Rust</a>. It’s not quite as slick as
          the Haskell one, partly because I didn’t ‘cheat’ and use a standard
          library implementation of <code>permutations</code> and chose to
          follow the paper more closely in using Bubblesort rather than
          insertion sort, but mostly because Rust is more verbose with things
          like curly brackets than Haskell and doesn’t allow point-free
          style.</p>
          <p>Here’s the business part of the code:</p>
          <div class="sourceCode" id="cb1"><pre
          class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> badsort<span class="op">&lt;</span>T<span class="op">:</span> <span class="bu">Ord</span> <span class="op">+</span> <span class="bu">Clone</span><span class="op">&gt;</span>(k<span class="op">:</span> <span class="dt">usize</span><span class="op">,</span> l<span class="op">:</span> <span class="op">&amp;</span><span class="kw">mut</span> [T]) <span class="op">{</span></span>
        <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> k <span class="op">==</span> <span class="dv">0</span> <span class="op">{</span></span>
        <span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>        bubblesort(l)<span class="op">;</span></span>
        <span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
        <span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> <span class="kw">mut</span> p <span class="op">=</span> permutations(l)<span class="op">;</span></span>
        <span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        badsort(k <span class="op">-</span> <span class="dv">1</span><span class="op">,</span> <span class="op">&amp;</span><span class="kw">mut</span> p)<span class="op">;</span></span>
        <span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        l<span class="op">.</span>clone_from_slice(<span class="op">&amp;</span>p[<span class="dv">0</span>])<span class="op">;</span></span>
        <span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
        <span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
        <span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
        <span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> worstsort<span class="op">&lt;</span>T<span class="op">,</span> F<span class="op">&gt;</span>(l<span class="op">:</span> <span class="op">&amp;</span><span class="kw">mut</span> [T]<span class="op">,</span> f<span class="op">:</span> F)</span>
        <span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">where</span></span>
        <span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    T<span class="op">:</span> <span class="bu">Ord</span> <span class="op">+</span> <span class="bu">Clone</span><span class="op">,</span></span>
        <span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    F<span class="op">:</span> <span class="bu">FnOnce</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">,</span></span>
        <span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
        <span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    badsort(f(l<span class="op">.</span>len())<span class="op">,</span> l)<span class="op">;</span></span>
        <span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
          <p><code>worstsort</code> runs in
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Ω</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><msup><mi>!</mi><mrow><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow></msup><msup><mo stretchy="false" form="postfix">)</mo><mn>2</mn></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Omega((n!^{(f(n))})^2)</annotation></semantics></math>
          time, where
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><msup><mi>!</mi><mrow><mo stretchy="false" form="prefix">(</mo><mi>k</mi><mo stretchy="false" form="postfix">)</mo></mrow></msup></mrow><annotation encoding="application/x-tex">n!^{(k)}</annotation></semantics></math>
          abbreviates taking the factorial
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math>
          times. Pretty impressive for just 15 lines, about half of which is
          boilerplate!</p>
          <p>I should probably submit this as a PR to the <a
          href="https://crates.io/crates/sorting">sorting</a> crate…</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>non-pathological: we aren’t interested in algorithms
          which just loop pointlessly<a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Trying out Pijul</title>
      <link>https://inv.alid.pw/posts/trying-pijul/</link>
      <pubDate>Wed, 23 Jan 2019 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/trying-pijul/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Trying out Pijul</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/trying-pijul/" itemprop="url">23 January
        2019</a></time>
          </header>
        
          <p><a href="https://pijul.org/">Pijul</a> is a version control system.
          So what? Everyone just uses <a href="https://git-scm.com/">git</a>
          nowadays, right? Well, I personally already use git, <a
          href="https://www.mercurial-scm.org/">Mercurial</a> (because its model
          of pull/update makes more sense to me) and svn (because sometimes it’s
          just not worth it). So a fourth VCS is hardly a major marginal
          cost.</p>
          <p>Besides, Pijul is interesting in a lot of ways. Git and Mercurial
          work very hard to pretend that patches are the basic unit, but in
          reality they store snapshots of files. In Pijul, patches really are
          fundamental; it is based on ‘patch theory’, pioneered by <a
          href="http://darcs.net/">Darcs</a>, another obscure VCS I’ve flirted
          with in the past. As one may expect from a Haskell project, patch
          theory is an application of category theory to a software engineering
          problem. This isn’t just abstract nonsense for the sake of fulfilling
          Haskeller stereotypes: patch theory is more intuitive (which is why
          other systems fake it in the UI), and makes both <a
          href="https://pijul.org/faq/#cherrypicking">cherry-picking</a> and <a
          href="https://tahoe-lafs.org/~zooko/badmerge/simple.html">merges</a>
          easier.</p>
          <p>Pijul has not (at the time of writing) had a 1.0 release yet, but
          it’s <a
          href="https://nest.pijul.com/pijul_org/pijul">self-hosting</a>;
          impressively so, with its own ‘<a
          href="https://nest.pijul.com/">Nest</a>’ GitHub-alike that’s
          remarkably feature complete for such a young project. The
          documentation, like that of many similar hobbyist FOSS projects, is a
          little bit lacking—parts are out of date and it’s spread across a
          manual, README files and replies on the Discourse forum—but I’ve seen
          worse and a little reference to the source combined with educated
          guesswork seems to have been sufficient so far.</p>
          <p>The main use I have in mind in particular for Pijul is to control
          my various dotfiles: configuration for i3, emacs, zsh, etc. At the
          moment they use <a href="https://github.com/RichiH/vcsh">vcsh</a>
          which is horrendous overkill to the point where I never remember to
          commit or push anything. The other problem I have is maintaining
          parallel configuration across various different computers. For
          example, I want wifi and battery status indicators on my laptop, but
          not on my desktop. I haven’t found a satisfactory way to keep these
          parts of the configuration separate while syncing unrelated changes
          between the computers. I believe that it should be a lot smoother with
          patch theory. A new feature of the latest 0.11 release, partial
          clones, may well also be useful.</p>
          <p>There are a lot of features missing: ignore files come immediately
          to mind, as running <code>pijul status</code> in my home directory
          shows a <strong>lot</strong> of junk I don’t want in the VCS. As far
          as I can tell, it’s also impossible to see the contents of a patch, or
          show diffs in <code>pijul
          log</code> output. And the docs are quite unclear on a lot of
          important questions. How do branches work? There are <a
          href="https://discourse.pijul.org/t/a-composable-pijul-user-interface-brainstorm/100/7">some</a>
          <a
          href="https://discourse.pijul.org/t/spontaneous-non-branching-vs-tree-style-branches/47">discussions</a>
          in the forums, but I can’t tell what’s ideas to be implemented, what’s
          newcomers asking questions and what’s how it actually works. I’ll post
          my issues into the forum, and I hope that I’ll be able to help
          transfer the answers into the official docs.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Three ways to check whether a file is ASCII-only</title>
      <link>https://inv.alid.pw/posts/file-ascii/</link>
      <pubDate>Fri, 19 Oct 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/file-ascii/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Three ways to check whether a file is
        ASCII-only</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/file-ascii/" itemprop="url">19 October
        2018</a></time>
          </header>
        
          <p>I have a 5k line LaTeX file, and I wasn’t sure whether it contained
          any non-ASCII characters. I’m using LuaLaTeX to compile it, which
          supports UTF-8, so just running pdfLaTeX on it is not a solution, and
          it would be nice to have a method that works on any text file.</p>
          <p>The first tool any seasoned Unix admin reaches for to answer the
          question ‘Does a particular character occur in a text file?’ is, of
          course, <code>grep</code>. The man pages don’t list a built-in
          character class right away for ASCII characters, so a tiny bit of
          ingenuity is required. <a
          href="https://stackoverflow.com/questions/3001177/how-do-i-grep-for-all-non-ascii-characters">This
          Stack Overflow answer</a> gives a command which almost works (in my
          testing it found the ‘ï’ of ‘naïve’ but missed the ‘ń’ in a Polish
          name), but it’s easily modified into the following:</p>
          <pre><code>grep -P &#39;[^\x00-\x7f]&#39; myfile.tex
        </code></pre>
          <p>Having the full scope of Perl-compatible regexes available means we
          could use the (slightly more memorable) <code>[^[:ascii:]]</code>.</p>
          <p>The second is a less well-known part of the standard Unix toolbox,
          <code>iconv</code>. Its primary purpose is to convert between text
          encodings, but we can abuse it to detect non-ASCII characters by
          asking it to convert our file into ASCII and seeing if it gives any
          errors:</p>
          <pre><code>iconv -t ASCII myfile.tex &gt; /dev/null
        </code></pre>
          <p>Finally, trusty old <code>file</code> will tell us the encoding
          used, and is probably the easiest one to remember:</p>
          <pre><code>file myfile.tex
        </code></pre>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>More on slide rules and complex multiplication</title>
      <link>https://inv.alid.pw/posts/more-slide-rules/</link>
      <pubDate>Fri, 07 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/more-slide-rules/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">More on slide rules and complex
        multiplication</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/more-slide-rules/" itemprop="url">7
        September 2018</a></time>
          </header>
        
          <p>Mathematical YouTube channel 3Blue1Brown recently released a <a
          href="https://www.youtube.com/watch?v=d4EgbgTm0Bg">video</a> about
          quaternions, a 4-dimensional extension of the complex numbers now
          mostly used in 3d graphics and other areas. In the spirit of <a
          href="https://en.wikipedia.org/wiki/Flatland">Edwin A. Abbott</a>, the
          video builds up to explaining 4d rotations to a 3-dimensional audience
          by analogy to the step from one dimension to two.</p>
          <p>I’d certainly recommend watching the video, as the visualisations
          are as excellent as they usually are. One of the first ones we see is
          to explain complex multiplication to a one-dimensional Linelander,
          starting at <a href="https://youtu.be/d4EgbgTm0Bg?t=312">5:12</a>.
          Seeing it immediately made me think of how multiplication is performed
          on a slide rule.</p>
          <p>Let’s start by going over in detail the process to multiply two
          numbers, say 2 and 4, with a slide rule. To begin with, here are the
          two scales that we care about:</p>
          <p><img src="/img/sliderule-mult-1.jpg" /></p>
          <p>They are graduated with exactly the same scale, and all of the
          values line up. This starting position can be thought of as the
          process ‘multiply by 1’. Since in this example we want to multiply by
          2, we slide the movable middle section (scale C) until the 1 lines up
          with 2 on the lower section (scale D).</p>
          <p><img src="/img/sliderule-mult-2.jpg" /></p>
          <p>Now the rule represents the operation ‘multiply by 2’. We can
          already see everything lines up as you’d expect: already visible is
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>×</mo><mn>1.5</mn><mo>=</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">2
          \times 1.5 = 3</annotation></semantics></math>, and it’s just a matter
          of looking further along to read off the answer
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>×</mo><mn>4</mn><mo>=</mo><mn>8</mn></mrow><annotation encoding="application/x-tex">2 \times 4 = 8</annotation></semantics></math>.</p>
          <p><img src="/img/sliderule-mult-3.jpg" /></p>
          <p>Compare this to the animation in the video. Instead of two adjacent
          linear scales representing the real line, we have two overlapping
          coordinate systems for the complex plane. To multiply by
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>+</mo><mn>3</mn><mi>i</mi></mrow><annotation encoding="application/x-tex">2 + 3i</annotation></semantics></math>,
          we move the point 1 on the first grid to the point
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>+</mo><mn>3</mn><mi>i</mi></mrow><annotation encoding="application/x-tex">2 + 3i</annotation></semantics></math>
          on the second by stetching and rotating it. Then we can read off the
          product
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo>+</mo><mn>3</mn><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo>−</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(2 + 3i)(1-i)</annotation></semantics></math>
          by finding the point on the second grid where
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>−</mo><mi>i</mi></mrow><annotation encoding="application/x-tex">1 -
          i</annotation></semantics></math> ended up.</p>
          <p>This process is so similar to how we do it on the slide rule that
          it really makes me wonder how to build a physical implementation: a
          complex-valued slide rule. I’m not very practically minded, but I
          wonder whether there’s something you can do with <a
          href="https://en.wikipedia.org/wiki/Pantograph">pantograph
          linkages</a> like you get in a <a
          href="https://en.wikipedia.org/wiki/Hoberman_sphere">Hoberman
          sphere</a>…</p>
          <p>After a little bit of online searching, I found that of course
          complex-valued slide rules have been <a
          href="http://www.quadibloc.com/math/sr03.htm">around</a> <a
          href="https://sites.google.com/site/calculatinghistory/home/complex-number-slide-rules">for</a>
          a <a href="http://cs.smu.ca/~dawson/ComplexSlideRule.html">while</a>.
          The idea of stretching is avoided in a real-valued slide rule by
          logarithms, and it’s perfectly possible to replicate this in the
          complex case. All of the examples in the links use the full-blown
          complex logarithm function; they tend to be cylindrical to handle the
          rotations gracefully. I particularly recommend looking at the <a
          href="http://cs.smu.ca/~dawson/images2.html#CXSR">ray-traced image</a>
          from the third above link. The gently but precisely curving lines and
          the way the transparent part overlaps the fixed cylinder are both
          fascinatingly beautiful to look at.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Slide rules</title>
      <link>https://inv.alid.pw/posts/slide-rules/</link>
      <pubDate>Thu, 30 Aug 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/slide-rules/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Slide rules</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/slide-rules/" itemprop="url">30 August
        2018</a></time>
          </header>
        
          <p>A couple of weeks ago, I was in Oxford for a wedding, and spent a
          hungover rainy Sunday visiting some of the city’s museums. I’ve been
          to the <a href="https://www.oumnh.ox.ac.uk/">Natural History
          Museum</a> and the <a href="https://www.prm.ox.ac.uk/">Pitt Rivers</a>
          a lot, although it would probably take decades to see everything in
          there. The Settlers exhibition was particularly interesting, as I’ve
          always found the story of the peopling of Britain over the millennia
          fascinating, and the presentation of archaeological, historical and
          genetic information was really well done.</p>
          <p>One I hadn’t visited before is the <a
          href="http://www.mhs.ox.ac.uk/">Museum of the History of Science</a>.
          It’s perhaps a little light on information you would call ‘the History
          of Science’, and I don’t think they ever went so far as to explain how
          to <strong>use</strong> any of the many astrolabes, but the collection
          on display is really astounding. Clocks, medical equipment, old
          electrical demonstrations and toys, surveying instruments, and more
          are all in there, along with slide rules.</p>
          <p>I think I first encountered a slide rule at school while doing my A
          levels, as one of the collection of odds and ends the maths department
          kept lying around. It didn’t really make much of an impression then,
          but seeing them again in the museum in Oxford really sparked something
          in me, and I ended up ordering a couple from eBay when I got back
          home. After a week of delays due to <a
          href="https://twitter.com/jshholland/status/1031576935342723072">courier
          bullshit</a>, I was in possession of two Faber-Castell slide rules,
          models 2/82 and 2/83.</p>
          <p><img src="/img/sliderules.jpg" alt="Slide rules in cases" /> <img
          src="/img/sliderule_mileskm.jpg"
          alt="Close up of slide rule model number" /></p>
          <p>These slide rules can perform multiplication, division,
          exponentiation, logarithms, and trigonometric functions, with
          shortcuts for common operations like squaring, square roots and powers
          of ten. It’s also straightforward to multiply and divide lots of
          numbers without having to find intermediate results. Surprisingly,
          it’s not readily possible to do addition or subtraction: the only way
          is to use a formula like
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>+</mo><mi>y</mi><mo>=</mo><mi>x</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo>+</mo><mfrac><mi>y</mi><mi>x</mi></mfrac><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">x + y = x(1 + \frac{y}{x})</annotation></semantics></math>
          to do it by multiplication and division.</p>
          <p>The key mathematical fact exploited by slide rules is
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>log</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mrow><mi>log</mi><mo>&#8289;</mo></mrow><mi>x</mi><mo>+</mo><mrow><mi>log</mi><mo>&#8289;</mo></mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">\log (xy) =
          \log x + \log y</annotation></semantics></math>, converting
          multiplication into addition implemented by chaining log scales next
          to each other. The scales are graduated from 1 to 10, so the user has
          to keep track of the order of magnitude. It’s pretty easy to work to 3
          or 4 significant figures. The model 2/83 also has what is effectively
          a double-length scale on the back, allowing more precise calculations
          to be done at the relatively low cost of having to keep track of which
          side the result should be read off.</p>
          <p>In an age of ubiquitous electronic calculators in the form of
          mobile phones and computers, what is the point of a slide rule?
          Practically speaking, not really very much. If nothing else, I
          personally rarely have to do any calculations which would require one.
          One minor feature is shown in the second picture above, where the
          slide rule is set up to quickly convert between miles and kilometres
          on the pair of scales just above the red pair in the middle. The 1 on
          the lower (CF) scale is aligned with 1.609 on the upper (DF) scale,
          and so any kilometre value on DF can be read off in miles on CF, and
          vice versa. I’ve also used this to set up currency exchange rates, and
          it’s really handy to be able to convert any value at a glance without
          having to change any settings or input a new number.</p>
          <p>But, more intriguingly, there is something very satisfying about
          the really visceral way you can see the numbers fit together on a
          slide rule. It’s something that has always really grabbed me about
          mathematics: everything is exactly in the place it has to be, breaks
          down precisely how it needs to, and we can <strong>prove</strong> it
          in black and white.</p>
          <p>It’s one thing to know multiplication tables purely as figures.
          It’s quite another to see them all line up in front of you, and to see
          how changing the factor makes a different set of numbers line up. And
          then you can compare the half, double and triple length scales
          (corresponding to square roots, squares and cubes) with the base
          scales and the reversed scales (for multiplicative inverses). There’s
          something missed by knowing only algebraically that
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>sin</mi><mo>&#8289;</mo></mrow><mi>x</mi><mo>=</mo><mrow><mi>cos</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><msup><mn>90</mn><mo>∘</mo></msup><mo>−</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\sin x = \cos
          (90^\circ - x)</annotation></semantics></math> without seeing the
          trigonometric scales for sine and cosine condensed onto one scale read
          either way. I think my mathematical education was lesser for never
          having had a slide rule in my hands when I was first learning the
          concepts. The slide rule offers a physical intuition that is
          completely absent in other methods of teaching.</p>
          <p>Another advantage of the slide rule is possibly also a
          disadvantage. With a slide rule like these ones, the user has to be
          familiar with what they are doing. There are (or were) slide rules
          specialised to work out things like gunnery angles and so on which
          didn’t need a mathematical background, but all-purpose slide rules are
          clearly a lot harder to use than an electronic calculator. I
          personally enjoy a little mental arithmetic and algebra practice, but
          for a normal person, it’s far more effort than modern technology
          requires.</p>
          <p>So it’s not really much of a surprise that they more or less died
          out in the 1970s, with the rise of the microprocessor and electronic
          calculator for engineering and scientific calculation. Still, I’ll
          enjoy keeping them around and doing the odd calculation on them. And,
          when the upcoming nuclear apocalypse wipes out all electronic devices,
          I’ll have the last laugh still being able to multiply and divide to
          four significant figures.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Googling dates</title>
      <link>https://inv.alid.pw/posts/googling-dates/</link>
      <pubDate>Thu, 07 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/googling-dates/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Googling dates</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/googling-dates/" itemprop="url">7 June
        2018</a></time>
          </header>
        
          <div class="author-note">
          <p>Author’s note: I wrote this a while ago, but decided that I wanted
          to look up and add some statistics before publishing it. That’s
          probably never going to happen, so here is the post as it stands.</p>
          </div>
          <p>I’ve started reading Jon Ronson’s <strong>So You’ve Been Publicly
          Shamed</strong>, which has been on my list for a while after I’ve
          enjoyed much of his other work. In the fourth chapter, he quotes
          Justine Sacco, whose somewhat racist tweet went viral while she was on
          an 11-hour flight, as saying ‘it’s not like I can date, because we
          google everyone we might date’. Now, I’m not particularly interested
          in the morals of what happened to Justine Sacco and her tweet (though
          I might have some thoughts for a later post after I finish the book),
          but this sentence caught my attention. The idea of looking online to
          see if some romantic interest had a shady past of off-colour jokes on
          social media would never occur to me.</p>
          <p>I’m certainly not so naïve to be unaware that people do this. But
          what makes me different? The two things that first come to mind are
          nationality and gender. I am an English man, and Justine Sacco is a
          South African-American woman. It would be very surprising if we had an
          identical experience of dating. Still, gender perhaps is less likely:
          Sacco is talking about her potential partners, not herself, and if she
          is interested in men, then that includes me. So it is more likely down
          to culture or simply personality differences<a href="#fn1"
          class="footnote-ref" id="fnref1"
          role="doc-noteref"><sup>1</sup></a>.</p>
          <p>Bemoaning the Americani{s/z}ation of British culture is one of many
          celebrated national pastimes, and by no means is the world of romance
          exempt from trans-Atlantic influence, perhaps significantly due to
          American-based websites. Still, we are different {to/from/than} our
          cousins across the pond and obviously so will be our behavio{u}r with
          respect to relationships.</p>
          <p>British people are stereotypically more reserved and respectful of
          status differences than Americans. We still enjoy gossip behind
          people’s backs, but social class is often given away through speech
          and mannerisms, obviating much of a need to research someone’s
          background. I don’t have much concrete to back this up, but it doesn’t
          feel too difficult to justify myself using national tendencies in this
          way.</p>
          <p>On the other hand, my justification of the previous paragraph feels
          a little like a just-so story, and I suspect that I could come up with
          an equally convincing argument in the other direction had my initial
          intuition been different. What I am best qualified to talk about is of
          course my own experience. How much do I pry into people’s online
          presence before I go on a date with them?</p>
          <p>Clearly if I already know a person then this whole discussion is
          academic, so we are probably talking about someone I’ve just met, most
          likely through online dating. The content of a profile description is
          a starting point (interestingly unique to online dating, absent if you
          meet in a pub, at a concert or somewhere similar). If I’m particularly
          interested, then I might look up their social media accounts, although
          in search of more posts, more pictures and more personality rather
          than a life history. I tend to hold off sending actual friend requests
          until we’ve met a few times and established some actual in-person
          chemistry.</p>
          <p>But why do I take this approach, and why isn’t researching all this
          information appealing to me? Fundamentally, I think it comes down to
          three things. Firstly, it simply feels like an intrusion. This
          possibly comes from my British reservedness and natural introversion,
          but I don’t particularly like the idea of someone googling me, and
          therefore I reciprocally choose not to do it to others. Mostly it’s
          probably not a significant problem, since people can control to some
          extent what is publicly associated with them, but I prefer to err on
          the side of caution. Secondly, and somewhat relatedly, the simple act
          of finding out about each other is a major part of the point and fun
          of dating people. I could google someone and find their name on a list
          of graduates of some university, or I could listen to them talk about
          what they studied, hear why they find that interesting, where the best
          pubs are in that city and what memorable stories happened in them.</p>
          <p>And finally, I think the most important part of a person is how
          they think and act now, not five years ago. I hold willingness to
          forgive as a cardinal virtue, and knowledge of some past crime only
          matters to me as a prior for that person doing it again. If they can
          convince me that they repent of whatever grevious sin is hiding in
          their past, then I will not hold it against them. I don’t mean to
          imply that someone’s past is completely insignificant: of course
          personal history has a huge effect on the present self. But we are not
          our mistakes. What matters is our ability to accept them and their
          consequences, to learn from them and to avoid making them all over
          again.</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p>Although perhaps she is falling prey to the <a
          href="https://wiki.lesswrong.com/wiki/Typical_mind_fallacy">typical
          mind fallacy</a>, a common trap where people assume that others reason
          in the same way as themselves. I can imagine that a woman who could
          reasonably feel more vulnerable to predatory partners than a man would
          might want to be more confident of a date’s background.<a
          href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Shined or shone?</title>
      <link>https://inv.alid.pw/posts/shined-shone/</link>
      <pubDate>Wed, 11 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/shined-shone/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Shined or shone?</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/shined-shone/" itemprop="url">11 April
        2018</a></time>
          </header>
        
          <p>Reading <a
          href="http://slatestarcodex.com/2018/04/10/why-dcs-low-graduation-rates/">Slate
          Star Codex</a> today, a sentence in a quote jumped out at me:</p>
          <blockquote>
          <p>The changes … shined a national spotlight</p>
          </blockquote>
          <p>In particular, the usage of ‘shined’ over ‘shone’ seemed very
          unnatural to me. As a result of doing a little research on this, both
          words have now completely <a
          href="https://en.wikipedia.org/wiki/Semantic_satiation">lost any
          meaning</a>. I hope that someone reads this blog post so it was all
          worth it.</p>
          <p>My first stop was the entry on Wiktionary, which lists both
          ‘shined’ and ‘shone’ as equally acceptable simple past or participle
          forms. I didn’t think that this was quite right, so I continued my
          digging. A search for ‘shined or shone’ revealed the usual mass of
          grammar blogs. The top result was <a
          href="http://grammarist.com/usage/shined-shone/">Grammarist</a>, which
          has a very short entry saying that historically, ‘shone’ was for
          something emitting light, and ‘shined’ was for polishing something,
          although in modern usage this is less strictly adhered to. Most other
          results had a similar, although not quite the same, transitive vs
          intransitive distinction. One even mentioned a mnemonic ‘rhyme’:
          ‘shone stands alone’.</p>
          <p>I put ‘rhyme’ in scare quotes there because in my (British English
          RP) accent it doesn’t rhyme at all: ‘shone’ as in ‘gone’ and ‘alone’
          as in ‘moan’. This reinforces my initial intuition that there is some
          British vs American difference here. Inspired by my favourite blog
          about such differences, <a
          href="https://separatedbyacommonlanguage.blogspot.co.uk/2014/02/shone-shined-and-digression-re.html">Separated
          by a Common Language</a>, whose post on this I only thought to search
          for after doing all this other research myself, I looked up the two
          words in a <a href="https://corpus.byu.edu/glowbe/">corpus</a>:</p>
          <p><img src="/img/shined.png" alt="GloWbE search for shined" /> <img
          src="/img/shone.png" alt="GloWbE search for shone" /></p>
          <p>And there we have it: ‘shone’ is proportionally much more common in
          British (and Commonwealth) English than it is in American. Now you
          should go read that <a
          href="https://separatedbyacommonlanguage.blogspot.co.uk/2014/02/shone-shined-and-digression-re.html">SbaCL</a>
          post because it’s written by someone who actually studies this stuff
          for a living.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Why write?</title>
      <link>https://inv.alid.pw/posts/why-write/</link>
      <pubDate>Wed, 21 Mar 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/why-write/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Why write?</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/why-write/" itemprop="url">21 March
        2018</a></time>
          </header>
        
          <p>Why, when I rebuilt this website, did I include a blog portion
          fairly front-and-centre? In 2018, it seems that everyone just <a
          href="https://twitter.com/jshholland">shoots an unfiltered stream of
          consciousness onto the internet</a> or <strong>maybe</strong> has a
          Medium account for slightly more fully-baked ideas. Sure, there are a
          few blogs still around, but they mostly seem to be historical
          artefacts left over from a bygone age.</p>
          <p>I’ve never been a prolific blogger or writer of anything much in
          particular. At school, essay subjects were my least favourite, and
          after my English GCSE, the most words I put together in one go were in
          my UCAS personal statement. Over my undergraduate degree I ended up
          writing more, as higher level maths leads to more involved proofs
          needing more explanation, but it’s a very different style to general
          prose.</p>
          <p>On the other hand, from a young age I was a prolific reader. I
          think I mostly inherited this from my mother, but it became an
          important part of my personality growing up. I wasn’t fussy: novels,
          short stories, popular science books, random magazines lying around
          the house. My reading habit has waxed and waned over the years, but I
          was always aware of the existence of people who put words together for
          a living.</p>
          <p>Now I’m a PhD student, and for the first time I have to write
          journal papers and eventually (though a lot sooner than I like to
          think about) a full thesis. The most consistent piece of writing
          advice I’ve seen is simply to write as much as possible and not care
          that the first x thousand words will suck. So one reason is definitely
          to get to the the point of being able to explain complex topics
          clearly and engagingly, at least to expert audiences.</p>
          <p>With that said, merely practising the art of writing isn’t the only
          motivating factor. I haven’t come up with a title or tagline for this
          website mostly to leave myself the freedom to write what I, and
          hopefully others, find interesting. Granted, so far that’s been <a
          href="/posts/kleisli-lifting-distributive/">weird parts of category
          theory</a> and <a href="/posts/hakyll-clean-urls-feeds/">overcoming
          very specific technical issues in little-used software</a>, but I have
          some thoughts about the broader world of modern society and technology
          that I want to get to very soon. In fact, this post is at least the
          start of unravelling all those issues.</p>
          <p>Another aspect is to <a
          href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">rubber-duck</a>
          my life in some sense. It’s a common experience to start asking some
          question (technical or otherwise) and realise that the act of
          structuring it into words makes the solution clearer, and I hope to be
          able to apply this to real-life situations I find myself in, ideally
          where I can come up with some novel or useful observation. I don’t
          have anything particular in mind in this genre yet, but it’s something
          that I want to leave myself open to.</p>
          <p>And finally, I may eventually have some political or philosophical
          opinions I want to clarify and share. This builds on my previous
          point, as the aim is to not only rubber-duck myself into some sort of
          coherent thinking, but also force myself to do the research. I’m a big
          believer in intellectual humility, and there’s a lot that I freely
          admit I don’t know enough about to have even a private opinion of.</p>
          <p>So this post will stand, at least for now, as my justification for
          this exercise in putting words on the internet. As always, if you have
          any comments, feedback or anything else to say to me, I’d welcome it
          via email, Twitter, carrier pigeon or any other means of contact you
          have.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Hakyll clean URLs and feeds</title>
      <link>https://inv.alid.pw/posts/hakyll-clean-urls-feeds/</link>
      <pubDate>Sun, 18 Mar 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/hakyll-clean-urls-feeds/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Hakyll clean URLs and feeds</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/hakyll-clean-urls-feeds/" itemprop="url">18
        March 2018</a></time>
          </header>
        
          <p>I’ve just finished adding <a href="/atom.xml">Atom</a> and <a
          href="/rss.xml">RSS</a> feeds to this website. While Hakyll provides
          (excellent) <a
          href="https://jaspervdj.be/hakyll/tutorials/05-snapshots-feeds.html">built-in
          support</a> for feeds, the way I’ve set up clean URLs to avoid
          <code>.html</code> suffixes everywhere (inspired by/ripped off from <a
          href="https://www.rohanjain.in/hakyll-clean-urls/">Rohan Jain</a>)
          initially didn’t quite work right with it, so I’ll document how I
          fixed this below.</p>
          <p>In the original method, clean URLs are implemented in two parts:
          first <code>cleanRoute</code> routes <code>foo.md</code> to
          <code>foo/index.html</code>, and then <code>cleanIndexUrls</code>
          rewrites internal links to remove all the <code>index.html</code>
          suffixes; see the post for more details. Up to now, this worked well
          enough, but when the feeds are generated, <code>index.html</code> is
          left in the links, and on closer inspection, it’s missing the point
          somehow. Hakyll URLs are generated via the <code>url</code> field
          attached to <code>defaultContext</code>, which eventually comes from
          the following:</p>
          <pre><code>urlField :: String -&gt; Context a
        urlField key = field key $
            fmap (maybe empty toUrl) . getRoute . itemIdentifier
        </code></pre>
          <p>So we can see that it all comes down to the <code>Route</code> of
          the item. In the case of <code>cleanRoute</code>, this is going to
          include the <code>index.html</code>. Rather than including this in the
          URLs and then stripping them out later with
          <code>cleanIndexUrls</code>, it seems much cleaner to redefine the
          <code>url</code> field in the context to something more canonically
          correct. Thus:</p>
          <pre><code>cleanUrlField :: String -&gt; Context a
        cleanUrlField key = field key $
          fmap (maybe empty (cleanIndex . toUrl)) .
          getRoute .
          itemIdentifier
        
        myContext :: Context String
        myContext =
          cleanUrlField &quot;url&quot; &lt;&gt;
          defaultContext
        </code></pre>
          <p>With this change, we don’t need to run <code>cleanIndexUrls</code>
          any more, and the feed generator code picks up the correct URL to
          place in the Atom and RSS feeds. You can see the full
          <code>site.hs</code> file with these changes <a
          href="https://github.com/jshholland/inv.alid.pw/blob/e79075b032b412b101b5cecbeb706fef13771e74/site.hs">here</a>.</p>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>Lifting monads to Kleisli categories with distributive laws</title>
      <link>https://inv.alid.pw/posts/kleisli-lifting-distributive/</link>
      <pubDate>Wed, 07 Mar 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/kleisli-lifting-distributive/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">Lifting monads to Kleisli categories
        with distributive laws</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/kleisli-lifting-distributive/" itemprop="url">7
        March 2018</a></time>
          </header>
        
          <p>It seems my first non-trivial post on my new website is going to be
          something fairly technical and likely not of any interest to anyone in
          particular. However, it’s related to something I’m working on at the
          moment, and a little perfunctory searching seems to indicate that
          there’s some sort of hole in the literature here, at least as far as
          my understanding goes. This is partly also a means to justify my
          faffing about to get MathJax working on this site. I assume
          familiarity with functors and natural transformations, but not much
          category theory beyond that.</p>
          <p>A monad (on some category
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>𝒞</mi><annotation encoding="application/x-tex">\mathcal{C}</annotation></semantics></math>),
          historically also known as a triple, consists of three pieces of
          data:</p>
          <ol type="1">
          <li>a functor
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo>:</mo><mi>𝒞</mi><mo>→</mo><mi>𝒞</mi></mrow><annotation encoding="application/x-tex">T : \mathcal{C} \rightarrow \mathcal{C}</annotation></semantics></math>;</li>
          <li>a natural transformation
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo>=</mo><msup><mi>η</mi><mi>T</mi></msup><mo>:</mo><mn>1</mn><mo>→</mo><mi>T</mi></mrow><annotation encoding="application/x-tex">\eta = \eta^T : 1 \rightarrow T</annotation></semantics></math>
          called the <strong>unit</strong>; and</li>
          <li>a natural transformation
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo>=</mo><msup><mi>μ</mi><mi>T</mi></msup><mo>:</mo><mi>T</mi><mi>T</mi><mo>→</mo><mi>T</mi></mrow><annotation encoding="application/x-tex">\mu = \mu^T: TT \rightarrow T</annotation></semantics></math>
          called <strong>multiplication</strong></li>
          </ol>
          <p>such that
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo>∘</mo><mi>T</mi><mi>μ</mi><mo>=</mo><mi>μ</mi><mo>∘</mo><mi>μ</mi><mi>T</mi></mrow><annotation encoding="application/x-tex">\mu \circ T\mu = \mu \circ \mu T</annotation></semantics></math>
          (associativity) and
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo>∘</mo><mi>T</mi><mi>η</mi><mo>=</mo><mi>μ</mi><mo>∘</mo><mi>η</mi><mi>T</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">
          \mu \circ T \eta = \mu \circ \eta T = 1</annotation></semantics></math>
          (unit law), famously summarised as ‘a monad is a monoid in the
          category of endofunctors’<a href="#fn1" class="footnote-ref"
          id="fnref1" role="doc-noteref"><sup>1</sup></a>. Given a monad
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>,
          we may form its <strong>Kleisli category</strong>
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝐊</mi><mi>𝐥</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>T</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathbf{Kl}(T)</annotation></semantics></math>,
          which has the same objects as the underlying category and where an
          arrow
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mo>↛</mo><mi>Y</mi></mrow><annotation encoding="application/x-tex">X \nrightarrow Y</annotation></semantics></math>
          is a
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>𝒞</mi><annotation encoding="application/x-tex">
          \mathcal{C}</annotation></semantics></math>-arrow
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mo>→</mo><mi>T</mi><mi>Y</mi></mrow><annotation encoding="application/x-tex">X \rightarrow TY</annotation></semantics></math>.
          I’ll use this different notation for Kleisli arrows because it’s
          important to keep straight the distinction between them and arrows in
          the underlying category. The identities are given by the unit maps
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>η</mi><mi>X</mi></msub><annotation encoding="application/x-tex">\eta_X</annotation></semantics></math>
          and composition of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo>:</mo><mi>X</mi><mo>↛</mo><mi>Y</mi></mrow><annotation encoding="application/x-tex">f: X \nrightarrow Y</annotation></semantics></math>
          and
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo>:</mo><mi>Y</mi><mo>↛</mo><mi>Z</mi></mrow><annotation encoding="application/x-tex">g: Y \nrightarrow Z</annotation></semantics></math>
          uses the multiplication:</p>
          <p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mover><mo>→</mo><mi>f</mi></mover><mi>T</mi><mi>Y</mi><mover><mo>→</mo><mrow><mi>T</mi><mi>g</mi></mrow></mover><mi>T</mi><mi>T</mi><mi>Z</mi><mover><mo>→</mo><msub><mi>μ</mi><mi>Z</mi></msub></mover><mi>T</mi><mi>Z</mi></mrow><annotation encoding="application/x-tex"> X \xrightarrow{f} TY \xrightarrow{Tg} TTZ \xrightarrow{\mu_Z} TZ </annotation></semantics></math></p>
          <p>This construction is well-known from its use in functional
          programming to model effects.</p>
          <p>Distributive laws come up a lot in the world of string diagrams and
          SMTs, where we use them to combine two theories together subject to
          some laws governing their interaction. The most familiar example of a
          distributive law is multiplication over addition:</p>
          <p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo>+</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mi>b</mi><mo>+</mo><mi>a</mi><mi>c</mi></mrow><annotation encoding="application/x-tex"> a(b + c) = ab + ac </annotation></semantics></math></p>
          <p><a
          href="http://www.tac.mta.ca/tac/reprints/articles/18/tr18abs.html">Beck</a>
          (p95) extended the notion to monads, defining a law distributing a
          monad
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>S</mi><annotation encoding="application/x-tex">S</annotation></semantics></math>
          over a monad
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>
          to be a natural transformation
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>λ</mi><mo>:</mo><mi>S</mi><mi>T</mi><mo>→</mo><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">\lambda: ST \rightarrow TS</annotation></semantics></math>
          satisfying certain coherence laws. In the paper, he in fact gives a
          way to recover the multiplication/addition law back from this
          construction, which is pretty cool.</p>
          <p>The main theorem related to distributive laws of monads is the
          equivalence of</p>
          <ol type="1">
          <li>a distributive law of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>S</mi><annotation encoding="application/x-tex">S</annotation></semantics></math>
          over
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>;</li>
          <li>a coherent multiplication on
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">TS</annotation></semantics></math>;</li>
          <li>a lifting of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>
          to the category of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>S</mi><annotation encoding="application/x-tex">S</annotation></semantics></math>-algebras
          (which I haven’t introduced, since it isn’t really relevant to this
          post); and</li>
          <li>a lifting of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>S</mi><annotation encoding="application/x-tex">S</annotation></semantics></math>
          to the Kleisli category of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>.</li>
          </ol>
          <p>Now, this certainly is true, but this is where the hole appears.
          Beck’s original paper omits this last condition (perhaps because
          Kleisli categories weren’t widespread back then?). On the other hand,
          <a href="https://arxiv.org/abs/1112.3076">Cheng</a> implicitly assumes
          the result for Kleisli categories. I have a feeling that it possibly
          follows out of the treatment of adjoint functors in Section 3 in the
          Beck paper, but I can’t quite get my head around it, and in any case I
          needed to write the construction down from first principles for my
          application.</p>
          <p>To warm up, let’s look at the most well-known use for a
          distributive law
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>λ</mi><mo>:</mo><mi>S</mi><mi>T</mi><mo>→</mo><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">\lambda : ST \to TS</annotation></semantics></math>:
          giving the composite functor
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">TS</annotation></semantics></math>
          a monad structure. Simply composing the units
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>η</mi><mi>T</mi></msup><mo>∘</mo><msup><mi>η</mi><mi>S</mi></msup></mrow><annotation encoding="application/x-tex">\eta^T \circ \eta^S</annotation></semantics></math>
          gives a natural transformation which will be the unit of the composite
          monad, but the bit which actually requires a distributive law is
          defining a multiplication
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>μ</mi><mrow><mi>T</mi><mi>S</mi></mrow></msup><mo>:</mo><mi>T</mi><mi>S</mi><mi>T</mi><mi>S</mi><mo>→</mo><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">\mu^{TS} : TSTS \rightarrow TS</annotation></semantics></math>.
          It’s one of those times when there’s essentially only one thing you
          can write down, and that is exactly what you need:</p>
          <p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>S</mi><mi>T</mi><mi>S</mi><mover><mo>→</mo><mrow><mi>T</mi><mi>λ</mi><mi>S</mi></mrow></mover><mi>T</mi><mi>T</mi><mi>S</mi><mi>S</mi><mover><mo>→</mo><mrow><msup><mi>μ</mi><mi>T</mi></msup><msup><mi>μ</mi><mi>S</mi></msup></mrow></mover><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">TSTS \xrightarrow{T \lambda S} TTSS \xrightarrow{\mu^T \mu^S} TS</annotation></semantics></math></p>
          <p>and all the relevant coherence conditions match up to satisfy the
          monad laws.</p>
          <p>For the Kleisli category, we need to define a monad
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mover><mi>S</mi><mo accent="true">̃</mo></mover><annotation encoding="application/x-tex">\tilde{S}</annotation></semantics></math>
          on
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝐊</mi><mi>𝐥</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>T</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathbf{Kl}(T)</annotation></semantics></math>.
          Even just to define the functor part we already need the distributive
          law: the objects are the same, but for a map
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo>:</mo><mi>X</mi><mo>↛</mo><mi>Y</mi></mrow><annotation encoding="application/x-tex">f: X \nrightarrow Y</annotation></semantics></math>,
          we need to define</p>
          <p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover><mi>S</mi><mo accent="true">̃</mo></mover><mi>f</mi><mo>:</mo><mi>S</mi><mi>X</mi><mo>→</mo><mi>T</mi><mi>S</mi><mi>Y</mi><mo>=</mo><mi>S</mi><mi>X</mi><mover><mo>→</mo><mrow><mi>S</mi><mi>f</mi></mrow></mover><mi>S</mi><mi>T</mi><mi>Y</mi><mover><mo>→</mo><msub><mi>λ</mi><mi>Y</mi></msub></mover><mi>T</mi><mi>S</mi><mi>Y</mi></mrow><annotation encoding="application/x-tex">
          \tilde{S}f: SX \rightarrow TSY =
          SX \xrightarrow{Sf} STY \xrightarrow{\lambda_Y} TSY
          </annotation></semantics></math></p>
          <p>So handwaving over the proofs that this is a proper functor, we now
          just need a unit and multiplication. The unit is again just a
          composite of the constituent units:</p>
          <p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>η</mi><mi>X</mi></msub><mo>:</mo><mi>X</mi><mo>↛</mo><mover><mi>S</mi><mo accent="true">̃</mo></mover><mi>X</mi><mo>=</mo><mi>X</mi><mover><mo>→</mo><msubsup><mi>η</mi><mi>X</mi><mi>S</mi></msubsup></mover><mi>S</mi><mi>X</mi><mover><mo>→</mo><msubsup><mi>η</mi><mrow><mi>S</mi><mi>X</mi></mrow><mi>T</mi></msubsup></mover><mi>T</mi><mi>S</mi><mi>X</mi></mrow><annotation encoding="application/x-tex">
          \eta_X: X \nrightarrow \tilde{S}X =
          X \xrightarrow{\eta^S_X} SX \xrightarrow{\eta^T_{SX}} TSX
          </annotation></semantics></math></p>
          <p>and the multiplication is a little more fiddly, but still
          straightforward:</p>
          <p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>μ</mi><mi>X</mi></msub><mo>:</mo><mover><mi>S</mi><mo accent="true">̃</mo></mover><mover><mi>S</mi><mo accent="true">̃</mo></mover><mi>X</mi><mo>↛</mo><mover><mi>S</mi><mo accent="true">̃</mo></mover><mi>X</mi><mo>=</mo><mi>S</mi><mi>S</mi><mi>X</mi><mover><mo>→</mo><msubsup><mi>μ</mi><mi>X</mi><mi>S</mi></msubsup></mover><mi>S</mi><mi>X</mi><mover><mo>→</mo><mrow><mi>S</mi><msubsup><mi>η</mi><mi>X</mi><mi>T</mi></msubsup></mrow></mover><mi>S</mi><mi>T</mi><mi>X</mi><mover><mo>→</mo><msub><mi>λ</mi><mi>X</mi></msub></mover><mi>T</mi><mi>S</mi><mi>X</mi></mrow><annotation encoding="application/x-tex">
          \mu_X: \tilde{S}\tilde{S}X \nrightarrow \tilde{S}X =
          SSX \xrightarrow{\mu^S_X} SX \xrightarrow{S\eta^T_X} STX
          \xrightarrow{\lambda_X} TSX
          </annotation></semantics></math></p>
          <p>And, again glossing over all the annoying coherence proofs, we’re
          done!</p>
          <p>There are quite a few pieces I’ve left out of all of this, notably
          going back the other way, from a lifting of
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>S</mi><annotation encoding="application/x-tex">S</annotation></semantics></math>
          to
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝐊</mi><mi>𝐥</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>T</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathbf{Kl}(T)</annotation></semantics></math>
          to a distributive law
          <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>S</mi><mi>T</mi><mo>→</mo><mi>T</mi><mi>S</mi></mrow><annotation encoding="application/x-tex">ST \rightarrow TS</annotation></semantics></math>,
          and most of the verifications that all these things satisfy the laws
          they are supposed to, but this is mostly what I wanted to figure out.
          Hopefully it’s useful to someone other than me. Any mistakes or
          comments, send me an email or tweet and I’d be happy to discuss.</p>
          <section id="footnotes" class="footnotes footnotes-end-of-document"
          role="doc-endnotes">
          <hr />
          <ol>
          <li id="fn1"><p><a
          href="http://james-iry.blogspot.co.uk/2009/05/brief-incomplete-and-mostly-wrong.html">what’s
          the problem?</a><a href="#fnref1" class="footnote-back"
          role="doc-backlink">↩︎</a></p></li>
          </ol>
          </section>
        
        </article>
      ]]></description>
    </item>
    <item>
      <title>New website</title>
      <link>https://inv.alid.pw/posts/new-site/</link>
      <pubDate>Fri, 09 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://inv.alid.pw/posts/new-site/</guid>
      <description><![CDATA[
        <article itemscope itemtype="http://schema.org/BlogPosting">
          <header>
        	<h1 itemprop="name headline title">New website</h1>
        	<time itemprop="dateCreated pubdate datePublished"
        		  datetime=""><a href="/posts/new-site/" itemprop="url">9 February
        2018</a></time>
          </header>
        
          <p>I’ve finally updated my personal homepage! Highlights include
          up-to-date information about myself, a switch from Jekyll to Hakyll,
          and ditching Bootstrap for hand-coded CSS. I have some intent to
          actually post things to the blog in the future also, but whether that
          happens does remain to be seen.</p>
          <p>Still to be done are re-implementing some sort of mobile/responsive
          design, adding a more formal CV, generating an RSS feed, and perhaps
          even a publication list. There are also no doubt plenty of places that
          could use a little prettification; I make no claims to being talented
          at web design.</p>
        
        </article>
      ]]></description>
    </item>
  </channel>
</rss>
