<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/assets/atom.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Michael Maclean</title>
    <subtitle>A software developer and technical architect, based in Scotland.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://mgdm.net/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://mgdm.net"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2024-06-06T00:00:00+00:00</updated>
    <id>https://mgdm.net/atom.xml</id>
    <entry xml:lang="en">
        <title>Using private flakes in NixOS</title>
        <published>2024-06-06T00:00:00+00:00</published>
        <updated>2024-06-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/nixos-with-private-flakes/"/>
        <id>https://mgdm.net/weblog/nixos-with-private-flakes/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/nixos-with-private-flakes/">&lt;p&gt;I’ve been using Nix and NixOS for a while now, but I’d got into a way of working where it was doing what I needed to do, so I haven’t felt the need to modernise it with the new features that have come along since I started using it. On the other hand, I did want to use some code that I’m not ready to open source yet and I wanted to find a neat way to do that. It’s likely that none of this post will be new or interesting to a lot of people who use Nix and NixOS, but I haven’t seen it written down anywhere in exactly this way.&lt;&#x2F;p&gt;
&lt;p&gt;Until now, to make this code work, I had been using a pretty awful and in no way hermetic solution with a local git checkout and some overlays. For some time I had imagined there must be a better way to do this using Flakes. I had searched around a couple of times to figure out how this might work but I never found a way to meet two preferences I had:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The code should be pulled from GitHub from a private repository without having to be proxied somehow&lt;&#x2F;li&gt;
&lt;li&gt;I shouldn’t have to have any credentials for GitHub stored on the box in the clear&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;While I was at &lt;a href=&quot;https:&#x2F;&#x2F;emfcamp.org&quot;&gt;EMF&lt;&#x2F;a&gt;, I dropped into the &lt;a href=&quot;https:&#x2F;&#x2F;nix.camp&quot;&gt;nix.camp&lt;&#x2F;a&gt; tent a couple of times, and finally managed to work it out after a couple of pointers from Matt. I haven’t really used Flakes an awful lot so it took a couple of tries.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;key-changes&quot;&gt;Key changes&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#key-changes&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;There were three key points:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;don-t-use-etc-nixos-any-more&quot;&gt;Don’t use &#x2F;etc&#x2F;nixos any more&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#don-t-use-etc-nixos-any-more&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The configuration for my machine was still stored in &lt;code&gt;&#x2F;etc&#x2F;nixos&lt;&#x2F;code&gt;, which was how I’d installed it in the first place. With Flakes, you can keep the configuration anywhere on the filesystem. With the config in my home directory, the rebuild command becomes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;sudo nixos-rebuild switch --flake .#&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;don-t-use-sudo-with-nixos-rebuild&quot;&gt;Don’t use &lt;code&gt;sudo&lt;&#x2F;code&gt; with nixos-rebuild&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#don-t-use-sudo-with-nixos-rebuild&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The next problem was how to use the &lt;code&gt;ssh&lt;&#x2F;code&gt; credentials I have as my normal user, without having to copy them to root. It turns out this is also fairly simple, though the name of the option is a little non-obvious given my use of it – &lt;code&gt;--use-remote-sudo&lt;&#x2F;code&gt;. By using this, you don’t need the whole command to be run with &lt;code&gt;sudo&lt;&#x2F;code&gt;, and instead it will ask for the password after it’s completed the work in the Nix store when it needs to apply the changes to the system. With this, the command is:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;sudo nixos-rebuild switch --flake .# --use-remote-sudo&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-ssh-agent-forwarding&quot;&gt;Use SSH agent forwarding&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#use-ssh-agent-forwarding&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I’m not normally keen on this feature of SSH, and I don’t have it switched on permanently, but in this particular case it works for me. For this to work I need to have &lt;code&gt;ssh-agent&lt;&#x2F;code&gt; running locally, I need to use &lt;code&gt;ssh -A&lt;&#x2F;code&gt; to connect, and then everything should work. If it doesn’t work for some reason I get some errors when it’s retrieving the flakes. This saves me having to keep something like a GitHub access token or deploy key on the machine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-service-s-flake&quot;&gt;The service’s flake&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#the-service-s-flake&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In my service’s repo, my &lt;code&gt;flake.nix&lt;&#x2F;code&gt; looks like this (all my services are written in Rust):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;inputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;naersk&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github:nix-community&#x2F;naersk&#x2F;master&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github:NixOS&#x2F;nixpkgs&#x2F;nixpkgs-unstable&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;utils&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github:numtide&#x2F;flake-utils&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;outputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;utils&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;naersk&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;utils&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;eachDefaultSystem&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-4 z-nix&quot;&gt;system&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;let&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-inherit z-nix&quot;&gt;inherit&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-single z-nix&quot;&gt;system&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-inherit z-nix&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;naersk-lib&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;callPackage&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;naersk&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;in&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;packages&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;naersk-lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;buildPackage&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-path z-nix&quot;&gt;.&#x2F;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;devShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;          &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;buildInputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;cargo&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;cargo-edit&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;rustc&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;rustfmt&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pre-commit&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;rustPackages&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;clippy&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;          &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;RUST_SRC_PATH&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;rustPlatform&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;rustLibSrc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;system-configuration&quot;&gt;System configuration&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#system-configuration&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;First off, I added a very basic &lt;code&gt;flake.nix&lt;&#x2F;code&gt; inspired by the documentation. It includes my own package, and then imports the existing &lt;code&gt;configuration.nix&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;description&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Flake-based NixOS configuration&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;inputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github:NixOS&#x2F;nixpkgs&#x2F;nixos-24.05&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;myPackage&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git+ssh:&#x2F;&#x2F;git@github.com&#x2F;mgdm&#x2F;myPackage.git&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;outputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;@&lt;span class=&quot;z-variable z-parameter z-function z-3 z-nix&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;nixosConfigurations&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;metis&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nixosSystem&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;system&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;x86_64-linux&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;specialArgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-inherit z-nix&quot;&gt;inherit&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-single z-nix&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-inherit z-nix&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;modules&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-path z-nix&quot;&gt;.&#x2F;configuration.nix&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then in my &lt;code&gt;configuration.nix&lt;&#x2F;code&gt;, I made a few changes.&lt;&#x2F;p&gt;
&lt;p&gt;First off, I added inputs at the top:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To make referring to the package involve a little less typing, I gave it a shorter name:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;let&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;myPackage&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;myPackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;packages&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-italic&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-nix&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;system&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;in&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;nix&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;extraOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;experimental-features = nix-command flakes&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then later I can reference that in &lt;code&gt;environment.systemPackages&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;environment&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;systemPackages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;vim&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;ripgrep&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;git&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;tmux&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;myPackage&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I have a &lt;code&gt;systemd&lt;&#x2F;code&gt; service configured for this in &lt;code&gt;configuration.nix&lt;&#x2F;code&gt;, but my next move is to investigate how to provide a module in the service’s &lt;code&gt;flake.nix&lt;&#x2F;code&gt; and move that configuration there. Eventually I’ll look into building this remotely so I can keep the configuration on my local computer.&lt;&#x2F;p&gt;
&lt;p&gt;If there are better ways to do any of this, I’d be happy to hear about them.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Adventures in digital radio</title>
        <published>2022-12-22T00:00:00+00:00</published>
        <updated>2022-12-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/adventures-in-digital-radio/"/>
        <id>https://mgdm.net/weblog/adventures-in-digital-radio/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/adventures-in-digital-radio/">&lt;p&gt;A few years ago I got my foundation amateur radio licence. It was something I’d been considering doing for quite a long time but there were few opportunities to do so where I was at the time. I used it a bit as MM6YHF, mainly on 2m and 70cm analogue FM repeaters. It’s been a while since I did  very much radio, as where I stay now is a bit further away from the repeaters so it became harder to do.&lt;&#x2F;p&gt;
&lt;p&gt;A few weeks ago I spent a weekend at the &lt;a href=&quot;https:&#x2F;&#x2F;57north.org.uk&quot;&gt;57 North hackspace&lt;&#x2F;a&gt; and saw &lt;a href=&quot;https:&#x2F;&#x2F;foxk.it&quot;&gt;Hibby&lt;&#x2F;a&gt; using a DMR radio. What I found interesting about this was that he was using a hotspot running &lt;a href=&quot;https:&#x2F;&#x2F;www.pistar.uk&quot;&gt;Pi-Star&lt;&#x2F;a&gt; elsewhere in the hackspace, so it was possible to communicate with people without having to be within range of a repeater. This particular one was on the &lt;a href=&quot;https:&#x2F;&#x2F;brandmeister.network&quot;&gt;Brandmeister network&lt;&#x2F;a&gt;, though other networks are available.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I got a TyT MD-UV390 radio, and borrowed Hibby’s hotspot to try it out for myself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;programming-the-radio&quot;&gt;Programming the radio&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#programming-the-radio&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It turns out that DMR radio, having been designed for commercial use, is a bit more complex than analogue FM. Working out how to program it was a bit of an expedition round some blogs, forums, and YouTube channels. As well as having the RF configuration for input and output frequencies, each repeater has two time slots upon which can be carried several talkgroups. The radio additionally has channels, scan groups, and zones. On my particular radio, I have opted to have one zone per digital repeater, including the hotspot, and another zone to contain the analogue FM repeaters. Each talkgroup on each repeater is then programmed as a separate channel. There is a feature for dynamically calling talkgroups but I’ll figure that one out later on.&lt;&#x2F;p&gt;
&lt;p&gt;The configuration of the radio is referred to as a “codeplug”. The software used to program the radio, referred to as “CPS” perhaps for “codeplug software” or maybe “customer programming software”, takes a bit of getting used to. There are open source options including &lt;a href=&quot;https:&#x2F;&#x2F;dm3mat.darc.de&#x2F;qdmr&#x2F;&quot;&gt;qdmr&lt;&#x2F;a&gt; which I have tried out briefly. I made a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;qdmr&quot;&gt;Nix flake for qmdr&lt;&#x2F;a&gt;, although I later found that it doesn’t quite cover all of the features of the radio. In the end I found a variety of YouTube videos which described the features, and finally &lt;a href=&quot;https:&#x2F;&#x2F;mcbainsite.co.uk&#x2F;how-to-make-a-dmr-codeplug-tyt&#x2F;&quot;&gt;a very helpful blog post&lt;&#x2F;a&gt; that described exactly how to make a codeplug from scratch. Before programming or using the radio, you need to register for a DMR ID at &lt;a href=&quot;https:&#x2F;&#x2F;radioid.net&quot;&gt;RadioID&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;firmware&quot;&gt;Firmware&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#firmware&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The firmware my radio arrived with was version &lt;code&gt;D019.005&lt;&#x2F;code&gt;. The &lt;code&gt;D&lt;&#x2F;code&gt; indicates that it’s configured to reserve space in the internal storage for recording audio. You can replace the firmware with another that has a version number starting with &lt;code&gt;S&lt;&#x2F;code&gt; that allows the storage to instead be used for storing contacts. It should hold around 100,000, which should let the radio identify most people I’m likely to talk to. You can obtain lists of contacts, which are mappings from DMR IDs to callsigns and first names, from RadioID.&lt;&#x2F;p&gt;
&lt;p&gt;Finding the firmware was a bit of fun. The &lt;a href=&quot;https:&#x2F;&#x2F;www.tyt888.com&#x2F;?mod=download&quot;&gt;manufacturer’s website&lt;&#x2F;a&gt; doesn’t make it simple to identify what version you’re downloading, and I couldn’t find any that was newer than &lt;code&gt;S018&lt;&#x2F;code&gt;. It turns out however that this hardware is also sold as the Retevis RT3. The Retevis site was much easier to navigate than the TyT one, so I obtained version &lt;code&gt;S019.005&lt;&#x2F;code&gt; from there and flashed that. It worked fine, although the graphic displayed when the radio is switched on will be different now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;loading-contacts&quot;&gt;Loading contacts&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#loading-contacts&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;One issue I’ve had is that while I can compile a contact list in CSV from the database on &lt;a href=&quot;https:&#x2F;&#x2F;radioid.net&quot;&gt;RadioID&lt;&#x2F;a&gt;, programming that to the radio using the TyT CPS requires a copy of Microsoft Excel. I don’t have that. &lt;code&gt;qdmr&lt;&#x2F;code&gt; has a UI for doing this, but trying it out displays a message about my radio not being supported. I’ve not quite worked around this yet. I’d quite like to avoid having to get a trial version of Office.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pi-star&quot;&gt;Pi-Star&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#pi-star&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Pi-Star is a Raspbian-based Linux distribution that runs on Raspberry Pis and similar devices with appropriate radio hardware attached. It can provide repeater functionality for a variety of digital radio protocols including DMR, and will interface with networks like Brandmeister. The configuration is completely handled by a web UI, which I found intuitive once I had an understanding of talkgroups and time slots. It will backhaul the radio traffic over wifi to your chosen network, which feels a little like cheating.&lt;&#x2F;p&gt;
&lt;p&gt;As it’s been a little while since I used the radio for much I’ve mainly been listening in a bit to remind myself how it works before getting too involved. Thanks go to Hibby both for the loan of the hotspot and also putting up with many elementary questions during the process of getting set up.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using JQ with SQLite</title>
        <published>2022-10-25T00:00:00+00:00</published>
        <updated>2022-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/using-jq-in-sqlite/"/>
        <id>https://mgdm.net/weblog/using-jq-in-sqlite/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/using-jq-in-sqlite/">&lt;p&gt;A while ago I was doing some work with data that I was loading into SQLite. I had been using &lt;code&gt;jq&lt;&#x2F;code&gt; to do some exploratory work to get different parts of the data out, but those queries didn’t directly translate to the JSON operators that exist in SQLite. I wondered if it might be possible to add an extension to SQLite to add operators that speak &lt;code&gt;jq&lt;&#x2F;code&gt;’s syntax.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out that it’s relatively easy. I opted to use Go to write this addon, as there is both a solid &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;itchyny&#x2F;gojq&quot;&gt;native Go implementation of &lt;code&gt;jq&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;riyaz-ali&#x2F;sqlite&quot;&gt;Go library for writing SQLite addons&lt;&#x2F;a&gt;, and I didn’t fancy writing it in C. The extension is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;sqlite-jq&quot;&gt;available on GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installing&quot;&gt;Installing&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#installing&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The instructions are a little different between macOS and Linux.&lt;&#x2F;p&gt;
&lt;p&gt;On macOS, run &lt;code&gt;make&lt;&#x2F;code&gt;, then you can load the resulting extension into &lt;code&gt;sqlite3&lt;&#x2F;code&gt; using &lt;code&gt;.load sqlite_jq.dylib&lt;&#x2F;code&gt; (or perhaps &lt;code&gt;.load sqlite_jq.so&lt;&#x2F;code&gt;, depending where you got your compiler from).&lt;&#x2F;p&gt;
&lt;p&gt;On Linux, run &lt;code&gt;make&lt;&#x2F;code&gt; to build, though you will then have to place the extension somewhere on &lt;code&gt;LD_LIBRARY_PATH&lt;&#x2F;code&gt;. Alternatively, for testing, you can set this directly:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;LD_LIBRARY_PATH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:LD_LIBRARY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, you can load the resulting extension with &lt;code&gt;.load sqlite_jq&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#overview&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It provides a scalar function, &lt;code&gt;jq()&lt;&#x2F;code&gt;, which lets you extract values from a JSON field using a &lt;code&gt;jq&lt;&#x2F;code&gt; expression:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; jq(&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;{&amp;quot;a&amp;quot;: &amp;quot;xyz&amp;quot;}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; returns &amp;quot;xyz&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is also a &lt;a href=&quot;https:&#x2F;&#x2F;www.sqlite.org&#x2F;vtab.html#tabfunc2&quot;&gt;table-valued function&lt;&#x2F;a&gt; called &lt;code&gt;jq_each()&lt;&#x2F;code&gt; that can be used to create a table of values from JSON fields.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; jq_each(&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;{&amp;quot;rows&amp;quot;: [&amp;quot;hello&amp;quot;, &amp;quot;world&amp;quot;]}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.rows[]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; returns two rows, &amp;quot;hello&amp;quot; and &amp;quot;world&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;worked-example&quot;&gt;Worked example&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#worked-example&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;For this example, I’m going to use &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jonty&quot;&gt;Jonty’s&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Jonty&#x2F;airline-route-data&quot;&gt;airline routes data&lt;&#x2F;a&gt;. It’s a large JSON file, which looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;AAA&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;city_name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Anaa&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;continent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;OC&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;country&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;French Polynesia&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;country_code&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;PF&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;display_name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Anaa, Anaa Airport (AAA), French Polynesia&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;elevation&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-json&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;iata&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;AAA&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;icao&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;NTGA&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;latitude&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-17.355648&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;longitude&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-145.50913&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Anaa Airport&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;routes&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;            &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;                &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;carriers&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;                    &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Air Tahiti&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;                &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;                &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;iata&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;FAC&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;                &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;km&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-json&quot;&gt;76&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;                &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;min&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-json&quot;&gt;25&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;            &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;timezone&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Pacific&#x2F;Tahiti&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-json&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; ...
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s a single large object where the keys are the IATA codes for each airport. To start with, I’m going to create a table with a single column, and import each of these sub-objects into that table, one per row.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;create&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;table&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;raw_data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    raw &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;text&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I’ll insert the rows directly from the file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;insert into&lt;&#x2F;span&gt; raw_data &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; jq_each(readfile(&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;airline_routes.json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;), &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.[]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, I can use these functions to extract the data into other tables. Let’s create a table for the airports.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;create&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;table&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;airports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    iata &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;char&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;3&lt;&#x2F;span&gt;) &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;primary key&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    icao &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;char&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;4&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    latitude float,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    longitude float,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    name &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;varchar&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;255&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    timezone &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;varchar&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;255&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I can then use the &lt;code&gt;jq()&lt;&#x2F;code&gt; function to load data into this table.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;insert into&lt;&#x2F;span&gt; airports &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(raw, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.iata&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(raw, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.icao&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(raw, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.latitude&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(raw, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.longitude&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(raw, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(raw, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.timezone&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; raw_data;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This can, of course, be done just as easily with SQLite’s own &lt;code&gt;json_extract()&lt;&#x2F;code&gt; function, with a slightly different syntax, or in newer releases of SQLite using the &lt;code&gt;-&amp;gt;&lt;&#x2F;code&gt; or &lt;code&gt;-&amp;gt;&amp;gt;&lt;&#x2F;code&gt; operators.&lt;&#x2F;p&gt;
&lt;p&gt;Now, we’ll extract the route data, into another table.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;create&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;table&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;routes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    origin_iata &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;char&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;3&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    destination_iata &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;char&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;3&lt;&#x2F;span&gt;),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    distance &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;int&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;time&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;int&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    carrier &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;varchar&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;255&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we can use a much longer &lt;code&gt;jq&lt;&#x2F;code&gt; expression to extract the route and carrier information. I’m using &lt;code&gt;json_extract()&lt;&#x2F;code&gt; here to demonstrate that the two extensions interoperate.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;insert into&lt;&#x2F;span&gt; routes &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    jq(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;raw_data&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.iata&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; origin_iata,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    json_extract(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;routes&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;value&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;$[0]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; dest_iata,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    json_extract(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;routes&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;value&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;$[1]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; distance,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    json_extract(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;routes&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;value&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;$[2]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;time&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    json_extract(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;routes&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;value&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;$[3]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; carrier
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; raw_data,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;jq_each(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;raw_data&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.routes[] | . as $route | .carriers[] | [ $route.iata, $route.km, $route.min, . ]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; routes;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can use the data to find all of the routes from Glasgow Airport.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;origin&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;iata&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;origin&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;name&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;destination&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;iata&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;destination&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;name&lt;&#x2F;span&gt;, routes.&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; airports origin
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;left join&lt;&#x2F;span&gt; routes on &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;routes&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;origin_iata&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;origin&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;iata&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;left join&lt;&#x2F;span&gt; airports &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; destination on &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;routes&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;destination_iata&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;destination&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;iata&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;where&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;origin&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;iata&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;GLA&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; GLA|Glasgow|LHR|Heathrow|GLA|LHR|555|90|British Airways
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; GLA|Glasgow|DUB|Dublin|GLA|DUB|295|60|Aer Lingus
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; GLA|Glasgow|DUB|Dublin|GLA|DUB|295|60|Ryanair
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; GLA|Glasgow|LGW|Gatwick|GLA|LGW|595|95|easyJet
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; ...
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The complete script can be seen &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;using-jq-in-sqlite&#x2F;load-airports.sql.txt&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;to-do&quot;&gt;To-do&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#to-do&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It’s very small, and I’ve got some work to do to add tests now that I understand how everything fits together. There’s probably some optimisation work to be done too, as this does do quite a lot of translation back and forth from JSON behind the scenes. I’m not sure if some form of caching might be appropriate, but I’ll look into it.&lt;&#x2F;p&gt;
&lt;p&gt;There’s also a question about whether this is a good idea at all, but I’m happy with it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Wrangling JSON in PostgreSQL</title>
        <published>2022-01-12T00:00:00+00:00</published>
        <updated>2022-01-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/json-in-postgresql/"/>
        <id>https://mgdm.net/weblog/json-in-postgresql/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/json-in-postgresql/">&lt;p&gt;I’ve been using SQLite a bit in some of my own projects recently, and I think it’s a great solution for small self-hosted applications, avoiding the need to run a full-blown RDBMS where it’s not really warranted. &lt;a href=&quot;https:&#x2F;&#x2F;christine.website&#x2F;blog&#x2F;sqlite-json-munge-2022-01-04&quot;&gt;Xe’s post about JSON in SQLite&lt;&#x2F;a&gt; talks a lot about how to use SQLite to handle JSON data and load it into other tables without having to have your application do it, which is great.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, in 2020 I spent a lot of time with a team demolishing an old enterprise system at work, with a fairly convoluted database structure. I learned a bit about PostgreSQL’s JSON functions in the process. I’ve been meaning to write up what I learned for some time now before I &lt;del&gt;banished&lt;&#x2F;del&gt; forgot it entirely, so Xe’s post was a good prompt.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out that similar capabilities exist in both databases, so I’m going to translate Xe’s post more or less directly into PostgreSQL equivalents. My site doesn’t have a JSONFeed endpoint (yet, perhaps &lt;a href=&quot;https:&#x2F;&#x2F;getzola.org&quot;&gt;Zola&lt;&#x2F;a&gt; will acquire one, one day), so I’m going to borrow Xe’s feed and Python script as the basis for what I do here. I’m using PostgreSQL 13.5 here. There are some &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;release&#x2F;14.0&#x2F;&quot;&gt;neat features in 14&lt;&#x2F;a&gt;, like array subscripting for JSON column types and things like that, which are worth reading up on.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setting-up-the-tables&quot;&gt;Setting up the tables&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#setting-up-the-tables&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;SQLite uses text data types to store JSON in, and has operators which can work on that. However, PostgreSQL has a separate JSON datatype. In fact, it has two–&lt;code&gt;json&lt;&#x2F;code&gt; and &lt;code&gt;jsonb&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The &lt;code&gt;json&lt;&#x2F;code&gt; type stores an exact copy of the input text, while &lt;code&gt;jsonb&lt;&#x2F;code&gt; transforms it into a binary form that is faster for many operations as well as being indexable. I’ve only ever used &lt;code&gt;jsonb&lt;&#x2F;code&gt;, and I’ll continue to do that here.&lt;&#x2F;p&gt;
&lt;p&gt;Because PostgreSQL is a relational database server, there is some work around setting up a new database and its permissions that I’m going to skip past. There are plenty of tutorials for getting this up and running already elsewhere. Because I’m a Nix fan I used &lt;code&gt;nix-shell&lt;&#x2F;code&gt; to install PostgreSQL, as described in a &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;postgresql-in-a-nix-shell&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;. For this example I’m going to assume the database is local, and the database, username and password are all &lt;code&gt;mydb&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s create a table, and throw some data into it. The key differences are the column types I’m using (&lt;code&gt;timestamp&lt;&#x2F;code&gt; and &lt;code&gt;jsonb&lt;&#x2F;code&gt;), and the slightly different syntax required for the default timestamp.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;#&lt;&#x2F;span&gt; schema.sql
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;IF NOT EXISTS &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_raw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  ( feed_url     &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;PRIMARY KEY&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , scrape_date  &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TIMESTAMP&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;DEFAULT&lt;&#x2F;span&gt; NOW&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , raw          JSONB  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  );
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;aside&gt;
&lt;p&gt;I don&#x27;t normally write SQL like this, but I&#x27;ll go with the flow.&lt;&#x2F;p&gt;
&lt;&#x2F;aside&gt;
&lt;p&gt;There are a couple of Python libraries for communicating with PostgreSQL, but the one I’m most familar with is the dubiously-named &lt;code&gt;psycopg2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python z-code&quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt;!&#x2F;usr&#x2F;bin&#x2F;env nix-shell
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt;! nix-shell -p python39 python39Packages.psycopg2 -i python
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;psycopg2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;urllib&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;con&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;psycopg2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;connect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;host&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;localhost&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;dbname&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;mydb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;mydb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;mydb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;&lt;span class=&quot;z-keyword z-declaration z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;get_feed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;feed_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-function z-begin z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;req&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;urllib&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;Request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;feed_url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;User-Agent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-python&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;mgdm&#x2F;feedfetch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-meta z-statement z-with z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-with z-python&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;urllib&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;urlopen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;req&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-statement z-with z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-with z-as z-python&quot;&gt;as&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-with z-python&quot;&gt; &lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;response&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-block z-with z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;cur&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;con&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;cursor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;read&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;decode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;utf-8&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;cur&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;execute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;           &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT INTO&lt;&#x2F;span&gt; jsonfeed_raw
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;             (feed_url, raw)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;           &lt;span class=&quot;z-keyword z-other z-DML z-II z-sql&quot;&gt;VALUES&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;             (&lt;span class=&quot;z-constant z-other z-placeholder z-python&quot;&gt;%s&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-other z-placeholder z-python&quot;&gt;%s&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-sequence z-tuple z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;feed_url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;con&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;print&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;got feed &lt;span class=&quot;z-constant z-other z-placeholder z-python&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;%&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;feed_url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;get_feed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;https:&#x2F;&#x2F;christine.website&#x2F;blog.json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can create the table from the schema above with the &lt;code&gt;psql&lt;&#x2F;code&gt; command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; psql&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;U&lt;&#x2F;span&gt; mydb&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; schema.sql mydb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then use the Python script to load the data:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; python jsonfeedfetch.py&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;json-operators&quot;&gt;JSON operators&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#json-operators&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;PostgreSQL has &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;functions-json.html&quot;&gt;a few operators&lt;&#x2F;a&gt; that can be used for accessing data held in JSON columns. They look a little different from the ones in SQLite. The &lt;code&gt;-&amp;gt;&lt;&#x2F;code&gt; operator returns a JSONB type, which can be queried further–we’ll see this in action later. However, the &lt;code&gt;-&amp;gt;&amp;gt;&lt;&#x2F;code&gt; operator will return a text representation of whatever value it retrieves. Note that the names of the JSON fields need to be quoted, otherwise PostgreSQL will think that you are referring to a column.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;mydb&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; title,  pg_typeof(raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    title    | pg_typeof
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;-----------+-----------
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Xe&amp;#39;s Blog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; | jsonb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt; row)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;mydb&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; title,  pg_typeof(raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;   title   | pg_typeof
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;---------+-----------
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; Xe&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;s Blog | text
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;(1 row)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can chain these operators, and also use integers to select array elements, so you can use something like this to select the title of the first post in the feed:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;mydb&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;select&lt;&#x2F;span&gt; raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;items&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; post_title &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;from&lt;&#x2F;span&gt; jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;          post_title           
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;-----------------------------
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;A Tool to Aid Forgetfulness&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt; row)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rather than using this syntax, it’s possible to use other operators to go more directly to the data you need. The query above could also be expressed as one of the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-- Using a list of object keys and array indices
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;select raw #&amp;gt; &amp;#39;{items,0,title}&amp;#39; as post_title from jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-- Using JSONPath
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;select jsonb_path_query(raw, &amp;#39;$.items[0].title&amp;#39;) from jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s go on and create the metadata table and insert the data into it. I only had to make one change to the syntax here, to the default value on the &lt;code&gt;updated_at&lt;&#x2F;code&gt; column:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;IF NOT EXISTS &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  ( feed_url      &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;PRIMARY KEY&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , title         &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , description   &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , home_page_url &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , updated_at    &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;DEFAULT&lt;&#x2F;span&gt; NOW&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  );
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Populating the second table looks fairly similar, although note the different operators inside the &lt;code&gt;SELECT&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT INTO&lt;&#x2F;span&gt; jsonfeed_metadata
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            ( feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , description
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , home_page_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , updated_at
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;jsonfeed_raw&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;feed_url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;     , raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;     , raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; description
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;     , raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;home_page_url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; home_page_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;     , NOW&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; updated_at
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;triggers&quot;&gt;Triggers&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#triggers&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Triggers are a little more complex in PostgreSQL. It’s not currently possible to write triggers in plain SQL&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Instead we have to write a function in another language and call that. The easiest choice in this case is to use &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;plpgsql.html&quot;&gt;PL&#x2F;pgSQL&lt;&#x2F;a&gt;, which is a PostgreSQL-specific superset of SQL. That’s going to look something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-drop z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;DROP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TRIGGER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; IF &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;EXISTS&lt;&#x2F;span&gt; jsonfeed_raw_ins ON jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-drop z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;DROP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;FUNCTION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; IF &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;EXISTS&lt;&#x2F;span&gt; jsonfeed_update;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;FUNCTION&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; RETURNS trigger &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; $jsonfeed_update$
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  &lt;span class=&quot;z-keyword z-other z-LUW z-sql&quot;&gt;BEGIN&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT INTO&lt;&#x2F;span&gt; jsonfeed_metadata
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                ( feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                , title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                , description
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                , home_page_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-II z-sql&quot;&gt;VALUES&lt;&#x2F;span&gt; ( &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;feed_url&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;home_page_url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    ON CONFLICT (feed_url) DO
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;       &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;UPDATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SET&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;             title         &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;           , description   &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;           , home_page_url &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;NEW&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;home_page_url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    RETURN &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;; &lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; Ignored because this is an AFTER trigger
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;END&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;$jsonfeed_update$ LANGUAGE plpgsql;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TRIGGER&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_raw_ins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;AFTER &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;OR&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;UPDATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;OR&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;DELETE&lt;&#x2F;span&gt; ON jsonfeed_raw
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    FOR EACH ROW EXECUTE FUNCTION jsonfeed_update&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a little more verbose, but does the same thing. Note the slightly different &lt;code&gt;ON CONFLICT&lt;&#x2F;code&gt; syntax, where we have to specify a column name unlike in the SQLite version. Speaking of conflicts, let’s also update the Python script so that it does an update on a conflict in the &lt;code&gt;jsonfeed_raw&lt;&#x2F;code&gt; table:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python z-code&quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;cur&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;execute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;           &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT INTO&lt;&#x2F;span&gt; jsonfeed_raw
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;             (feed_url, raw)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;           &lt;span class=&quot;z-keyword z-other z-DML z-II z-sql&quot;&gt;VALUES&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;             (&lt;span class=&quot;z-constant z-other z-placeholder z-python&quot;&gt;%s&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-other z-placeholder z-python&quot;&gt;%s&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;          ON CONFLICT (feed_url) DO
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;UPDATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SET&lt;&#x2F;span&gt; raw &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-placeholder z-python&quot;&gt;%s&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-block z-python&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-sequence z-tuple z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;feed_url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, if we delete everything from each of the tables and run the script again, we should see data in &lt;code&gt;jsonfeed_metadata&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mydb=&amp;gt; select * from jsonfeed_metadata;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;              feed_url               |    title    |                        description                         |        home_page_url        |          updated_at           
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-------------------------------------+-------------+------------------------------------------------------------+-----------------------------+-------------------------------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; https:&#x2F;&#x2F;christine.website&#x2F;blog.json | &amp;quot;Xe&amp;#39;s Blog&amp;quot; | &amp;quot;My blog posts and rants about various technology things.&amp;quot; | &amp;quot;https:&#x2F;&#x2F;christine.website&amp;quot; | 2022-01-12 22:15:36.920008+00
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(1 row)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mydb=&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;extracting-rows-from-the-json&quot;&gt;Extracting rows from the JSON&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#extracting-rows-from-the-json&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Like the &lt;code&gt;json_each&lt;&#x2F;code&gt; function in SQLite, PostgreSQL can unpack arrays of items in JSON and use those to create more rows using a function called &lt;code&gt;jsonb_array_elements&lt;&#x2F;code&gt;. Let’s create a table to put blog posts into:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;IF NOT EXISTS &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_posts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  ( url             &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;PRIMARY KEY&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , feed_url        &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , title           &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TEXT&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  , date_published  &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;TIMESTAMP&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  );
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can populate this table as follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT INTO&lt;&#x2F;span&gt; jsonfeed_posts
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            ( url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            , date_published
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  items&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;, raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;feed_url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;, items&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;, (items&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;date_published&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;)::&lt;span class=&quot;z-storage z-type z-sql&quot;&gt;timestamp&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; date_published
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  jsonfeed_raw 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;, jsonb_array_elements(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;jsonfeed_raw&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;items&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; items;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can do the same thing here as we did before, and turn this into a trigger. Again, we’ll need to use a slightly different language to do it, but it’s not going to be particularly difficult.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-drop z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;DROP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TRIGGER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; IF &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;EXISTS&lt;&#x2F;span&gt; jsonfeed_raw_ins_posts ON jsonfeed_raw;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-drop z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;DROP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;FUNCTION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; IF &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;EXISTS&lt;&#x2F;span&gt; jsonfeed_update_posts;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;FUNCTION&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_update_posts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; RETURNS trigger &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; $jsonfeed_update_posts$
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  &lt;span class=&quot;z-keyword z-other z-LUW z-sql&quot;&gt;BEGIN&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT INTO&lt;&#x2F;span&gt; jsonfeed_posts
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                ( url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                , feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                , title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                , date_published
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;      items&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    , raw&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;feed_url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; feed_url
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    , items&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; title
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    , (items&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;date_published&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;)::&lt;span class=&quot;z-storage z-type z-sql&quot;&gt;timestamp&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; date_published
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;      jsonfeed_raw 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    , jsonb_array_elements(&lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;jsonfeed_raw&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;raw&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;items&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;as&lt;&#x2F;span&gt; items
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    ON CONFLICT (url) DO
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;      &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;UPDATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SET&lt;&#x2F;span&gt; title &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;EXCLUDED&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;title&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;               , date_published &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;EXCLUDED&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;date_published&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    RETURN &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;  &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;END&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;$jsonfeed_update_posts$ LANGUAGE plpgsql;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TRIGGER&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;jsonfeed_raw_ins_posts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;AFTER &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;INSERT&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;OR&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;UPDATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;OR&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;DELETE&lt;&#x2F;span&gt; ON jsonfeed_raw
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    FOR EACH ROW EXECUTE FUNCTION jsonfeed_update_posts&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next time you run &lt;code&gt;jsonfeedfetch.py&lt;&#x2F;code&gt;, you should have a fully-populated &lt;code&gt;jsonfeed_posts&lt;&#x2F;code&gt; table containing all of the posts from the feed.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;There are also operators that can work on JSON stored in text fields, but I’ve not used those at all.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;From the &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;triggers.html&quot;&gt;PostgreSQL documentation on triggers&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Firecracker, Ignite, and ZFS</title>
        <published>2021-10-26T00:00:00+00:00</published>
        <updated>2021-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/firecracker-ignite-zfs/"/>
        <id>https://mgdm.net/weblog/firecracker-ignite-zfs/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/firecracker-ignite-zfs/">&lt;p&gt;Now that I have my &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;nixos-on-raspberry-pi-4&#x2F;&quot;&gt;NixOS Pi 4&lt;&#x2F;a&gt; up and running and doing a couple of useful things, I thought I’d see what else I could do with it. So far it’s just running DHCP, DNS and Tailscale, so it’s got a bit of spare horsepower. I also wrote a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;argonone-utils&quot;&gt;fan control daemon for the Argon ONE case&lt;&#x2F;a&gt; because I had some different requirements from the one that Argon40 themselves ship.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to try out running Firecracker VMs on it, as I was aware Firecracker gained Pi 4 support some time ago and I’d been meaning to give it a go. I’d also recently read about the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weaveworks&#x2F;ignite&quot;&gt;Ignite tool from Weaveworks&lt;&#x2F;a&gt; that lets you run VMs based on Docker container images without having to repack or rebuild them yourself. I expected that the quoted 125ms VM startup time was unlikely to be met on this hardware, but I figured it probably would still work.&lt;&#x2F;p&gt;
&lt;p&gt;As I’m running NixOS, most of this was set up inside &lt;code&gt;configuration.nix&lt;&#x2F;code&gt;. I added &lt;code&gt;firecracker&lt;&#x2F;code&gt;, &lt;code&gt;ignite&lt;&#x2F;code&gt;, &lt;code&gt;git&lt;&#x2F;code&gt;, and &lt;code&gt;binutils-unwrapped&lt;&#x2F;code&gt; to &lt;code&gt;environment.systemPackages&lt;&#x2F;code&gt;, and also added a line to set &lt;code&gt;virtualisation.containerd.enable&lt;&#x2F;code&gt; to &lt;code&gt;true&lt;&#x2F;code&gt;. Ignite relies on &lt;code&gt;git&lt;&#x2F;code&gt; and the &lt;code&gt;strings&lt;&#x2F;code&gt; command from binutils, which I think should be explicit dependencies in the package, but I’ll come back to that later.&lt;&#x2F;p&gt;
&lt;p&gt;A quick rebuild later, I had all the tools in place to be able to try and run a VM:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ignite run weaveworks&#x2F;ignite-ubuntu &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;    --&lt;&#x2F;span&gt;cpus&lt;&#x2F;span&gt; 1 &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;    --&lt;&#x2F;span&gt;memory&lt;&#x2F;span&gt; 512MB &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;    --&lt;&#x2F;span&gt;ssh&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;    --&lt;&#x2F;span&gt;name&lt;&#x2F;span&gt; hello-world&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This didn’t give me a lot of output, but ultimately failed. Rerunning it with &lt;code&gt;--log-level debug&lt;&#x2F;code&gt; gave me something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DEBU[0001] Writing &amp;quot;&#x2F;var&#x2F;lib&#x2F;firecracker&#x2F;vm&#x2F;57b9e0bf6cf0228a&#x2F;runtime.containerd.resolv.conf&amp;quot; with new hash: &amp;quot;fbe74b53a9d2380c8212bed5097146735021280bbc84d9e176139552a999fd25&amp;quot;, old hash: &amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FATA[0001] failed to start container for VM &amp;quot;57b9e0bf6cf0228a&amp;quot;: failed to mount &#x2F;tmp&#x2F;containerd-mount920509976: invalid argument
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And digging into the journal gave me:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Oct 26 20:13:12 nixpi kernel: overlayfs: upper fs does not support RENAME_WHITEOUT.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Oct 26 20:13:12 nixpi kernel: overlayfs: upper fs missing required features.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because I apparently enjoy making obtuse computing problems for myself to solve, I’m running this Pi on ZFS in order to learn more about how to operate it. It seems that ZFS doesn’t support something that &lt;code&gt;overlayfs&lt;&#x2F;code&gt; requires. I mentioned I had this problem on IRC and &lt;a href=&quot;https:&#x2F;&#x2F;grahamc.com&quot;&gt;Graham&lt;&#x2F;a&gt; suggested a &lt;code&gt;zvol&lt;&#x2F;code&gt;. This is not something I’d encountered before, but it’s a way of creating a block device that lives in your ZFS pool, which you can then format with whichever filesystem you like.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out after all I’m not the first person to try and work around this, as &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weaveworks&#x2F;ignite&#x2F;issues&#x2F;630#issuecomment-763652140&quot;&gt;this GitHub comment&lt;&#x2F;a&gt; in the Ignite repository proves, and I ended up using a very similar approach to the one described there.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl stop containerd.service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zfs create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;V&lt;&#x2F;span&gt; 15G rpool&#x2F;containerd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkfs.ext4&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;b&lt;&#x2F;span&gt; 4096&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;L&lt;&#x2F;span&gt; containerd &#x2F;dev&#x2F;zvol&#x2F;rpool&#x2F;containerd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir &#x2F;tmp&#x2F;migrate&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount &#x2F;dev&#x2F;zvol&#x2F;rpool&#x2F;containerd &#x2F;tmp&#x2F;migrate&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cp&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;r&lt;&#x2F;span&gt; &#x2F;var&#x2F;lib&#x2F;containerd&#x2F;&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt; &#x2F;tmp&#x2F;migrate&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; umount &#x2F;tmp&#x2F;migrate&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount &#x2F;dev&#x2F;zvol&#x2F;rpool&#x2F;containerd &#x2F;var&#x2F;lib&#x2F;containerd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl start containerd.service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Running it again worked fine this time:&lt;&#x2F;p&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;mgdm.net&amp;#x2F;processed_images&amp;#x2F;ignite.748c878a6ee8a52d.png&quot; alt=&quot;A screenshot of the Ignite terminal session running the ignite run command from earlier&quot; &#x2F;&gt;

&lt;p&gt;I’ll make the new filesystem permanent by adding it into my &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt; using something like the below. It turns out that using &lt;code&gt;rpool&#x2F;containerd&lt;&#x2F;code&gt; doesn’t work on boot, instead I need to use the device it’s exposed as (&lt;code&gt;&#x2F;dev&#x2F;zd0&lt;&#x2F;code&gt;), although a more robust way to do it would be to find its symlink in &lt;code&gt;&#x2F;dev&#x2F;disk&#x2F;by-uuid&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;fileSystems&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;var&#x2F;lib&#x2F;containerd&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;device&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;zvol&#x2F;rpool&#x2F;containerd&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fsType&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;ext4&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m pretty certain that this would have worked out of the box on a more conventional setup, but by doing it this way at I suppose I learned something. I don’t have any specific plans for this, but I’m going to see if it will handle things like the Unifi controller that I’d normally use Docker for.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>htmlq, revisited</title>
        <published>2021-09-12T00:00:00+00:00</published>
        <updated>2021-09-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/htmlq-revisited/"/>
        <id>https://mgdm.net/weblog/htmlq-revisited/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/htmlq-revisited/">&lt;p&gt;A couple of years ago &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;htmlq&#x2F;&quot;&gt;I wrote about a tool I’d created&lt;&#x2F;a&gt; called &lt;code&gt;htmlq&lt;&#x2F;code&gt;. At the time, I’d been doing a bit of web scraping, and while it’s absolutely doable using Python and BeautifulSoup glued together with a shell script, it was a bit slow waiting for the Python startup time for each iteration. I ended up writing a bit more code to do the thing I wanted to do at an acceptable pace. Don’t get me wrong–both Python and BeautifulSoup are great tools, but sometimes I just want to be able to glue things together in an iterative way with &lt;code&gt;curl&lt;&#x2F;code&gt; and bash. I’m a fan of Rust, and knowing that the Mozilla Servo browser components were available, I looked to use those to make a tool to solve my problem (and hopefully learn something along the way).&lt;&#x2F;p&gt;
&lt;p&gt;Last Monday I woke up to find that the tool I’d written was &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=28441880&quot;&gt;at the top of Hacker News&lt;&#x2F;a&gt;, where it had been submitted by &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jasonbosco&quot;&gt;Jason Bosco&lt;&#x2F;a&gt;. It remained near the top for much of the day. This was great! However, at the time I’d not really thought too much about &lt;code&gt;htmlq&lt;&#x2F;code&gt; since I first wrote it. It turns out that a couple of people had been sending PRs and making suggestions in the time I’d not been paying attention, but I’d not spotted the notifications about them. I can only apologise for the oversight, but between some PRs that have been there for a little while and some more that came since, it’s in a better shape.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;htmlq&quot;&gt;released a new version to crates.io&lt;&#x2F;a&gt;. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NikolayMurha&quot;&gt;Nikolay Murha&lt;&#x2F;a&gt; kindly added it to Homebrew. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chrisdickinson&quot;&gt;Chris Dickinson&lt;&#x2F;a&gt; kindly sent a PR last year which used GitHub Actions to create binary builds, which unfortunately sat around for a while before I got to merging it. Several people have also contributed to the documentation and to tweaking the defaults. It’s been really nice to have people do these things!&lt;&#x2F;p&gt;
&lt;p&gt;At the moment I’m working on adding a couple of features that were requested, including one &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;htmlq&#x2F;pull&#x2F;21&quot;&gt;to convert relative links to absolute ones&lt;&#x2F;a&gt; either using a &lt;code&gt;&amp;lt;base&amp;gt;&lt;&#x2F;code&gt; specified in the document or one supplied on the command line. I’m aiming to put a bit more testing around it too, and improve the pretty printing of the output.&lt;&#x2F;p&gt;
&lt;p&gt;If anyone’s got any more suggestions, I’d be happy to hear about them.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Why Nix?</title>
        <published>2021-09-05T00:00:00+00:00</published>
        <updated>2021-09-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/why-nix/"/>
        <id>https://mgdm.net/weblog/why-nix/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/why-nix/">&lt;p&gt;I’ve written a lot about Nix and NixOS over the last couple of years, and I use Nix in some way most days that I’m on a computer. Sometimes when I mention this, people ask me what’s so interesting about it. I’m going to try and answer that here, by running through what I find useful about Nix.&lt;&#x2F;p&gt;
&lt;p&gt;If you read the front page of the &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;Nix website&lt;&#x2F;a&gt;, you’ll see a quote like this:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nix is a tool that takes a unique approach to package management and system configuration. Learn how to make reproducible, declarative and reliable systems.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;All of the above is true, and some folks may be able to see what is attractive about that immediately. I was not entirely one of those people when I started off, though I’d heard a lot about it from others. I’m still not an advanced Nix user by any stretch. I don’t really properly understand the Nix language yet, but this hasn’t particularly stopped me finding value in it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#background&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Normally, on a Linux machine, you’ve got a package manager that can install whatever you like, whenever you need it. If you’re on a Debian or Ubuntu machine, you might want to do some basic resizing of an image, and end up doing something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;me@laptop:~$ convert -geometry 1024x big.jpg small.jpg
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;bash: convert: command not found
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;me@laptop:~$ sudo apt install imagemagick
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Much text ensues
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;me@laptop:~$ convert -geometry 1024x big.jpg small.jpg
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Success!
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This demonstrates one of the key points I want to get across here: on a conventional Linux distribution, &lt;strong&gt;these little changes accrete&lt;&#x2F;strong&gt;. If you need to wipe your machine, move to a new one, or just use a different computer for a little while, many of the things that you expect to be there are not going to be present. You might end up encountering these little paper cuts for some time as you continue working. Additionally, you end up with tools installed that you might use once and never again, taking up space.&lt;&#x2F;p&gt;
&lt;p&gt;At work I generally use macOS, and on there I used to use Homebrew to install things. For 90% of what I do this was fine, but one thing tipped me over the edge into finally installing Nix. I was doing some data work which required me to use PostgreSQL. I’d just used &lt;code&gt;brew install postgresql&lt;&#x2F;code&gt; and got on with it at the time, without thinking too hard about what version was installed. It was a few weeks later that the version of PostgreSQL in Homebrew was upgraded as a side effect of installing something else, and the next time I looked at my Postgres DB it had been wiped and started from scratch. The data was still there, it was just in a different directory with the version number in the path, but the running daemon had been upgraded to a different one so it had started from an empty DB. There are other ways to solve this problem, but by this point I’d heard enough about “reproducibility” and “immutability” to wonder if this would be something that I could use.&lt;&#x2F;p&gt;
&lt;p&gt;I installed Nix on macOS, and found out how to install things with &lt;code&gt;nix-env&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ nix-env -iA nixpkgs.imagemagick
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is basically what I had before with &lt;code&gt;apt&lt;&#x2F;code&gt; or &lt;code&gt;brew&lt;&#x2F;code&gt;, except that it pulls from Nix’s own repository, called &lt;code&gt;nixpkgs&lt;&#x2F;code&gt;. You can install things, and they appear in your shell environment. It’s just different, not better.&lt;&#x2F;p&gt;
&lt;p&gt;What is better is &lt;code&gt;nix-shell&lt;&#x2F;code&gt;. With this, you can create a new shell with any set of tools that you like present. For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ nix-shell -p imagemagick
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This drops me into a new shell with ImageMagick present. When I close it again, it’s no longer there. If I don’t use it again eventually it’ll be garbage collected. I use this a bit for tools that I don’t need all of the time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shell-nix&quot;&gt;shell.nix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#shell-nix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Shortly after this, I learned enough to discover &lt;code&gt;shell.nix&lt;&#x2F;code&gt; files. This is the part of Nix that I probably still use the most. These are files you can write and keep inside your projects that describe things you want to be available when you’re working on that bit of code. An example I have from the repository for this website looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixpkgs&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;buildInputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;zola&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This just means that if I change into the directory for the site, I can type &lt;code&gt;nix-shell&lt;&#x2F;code&gt; and that file will be loaded, and a new shell will result with &lt;code&gt;zola&lt;&#x2F;code&gt; available. Once I quit that shell, &lt;code&gt;zola&lt;&#x2F;code&gt; disappears from the environment. This is more important than it may appear, and results in next two key points: &lt;strong&gt;I can have different versions of tools available in different projects&lt;&#x2F;strong&gt;, and &lt;strong&gt;you can ensure you have only the tools you require&lt;&#x2F;strong&gt;. If I stop working on a project that has a particular dependency, it can get garbage collected and it’s no longer present on the system.&lt;&#x2F;p&gt;
&lt;p&gt;I commit these &lt;code&gt;shell.nix&lt;&#x2F;code&gt; files to my projects, and I have blogged marginally more complex examples before for &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;postgresql-in-a-nix-shell&#x2F;&quot;&gt;keeping a PostgreSQL environment per-project&lt;&#x2F;a&gt; and also for &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;vscode-nix-go-tools&#x2F;&quot;&gt;the Go tools that VS Code wants&lt;&#x2F;a&gt;. For other projects at work where I’m the only person using Nix to install the build tools, I’ll sometimes keep them to myself by adding them to &lt;code&gt;.git&#x2F;info&#x2F;exclude&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A neat feature of this is that you can override how the packages you install are defined. For example, if you want to create a Python 3 environment with some packages from PyPI, you can do something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixpkgs&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;let&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;my-python-packages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-4 z-nix&quot;&gt;python-packages&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;python-packages&lt;&#x2F;span&gt;; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pillow&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;numpy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;black&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;python-with-my-packages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;python3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;withPackages&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;my-python-packages&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;in&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;buildInputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;python-with-my-packages&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;direnv-and-lorri&quot;&gt;Direnv and Lorri&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#direnv-and-lorri&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;nix-shell&lt;&#x2F;code&gt; is pretty neat, but it’s a bit like Python virtualenvs where you need to remember to activate and deactivate them as you go. You can use a tool called &lt;a href=&quot;https:&#x2F;&#x2F;direnv.net&quot;&gt;direnv&lt;&#x2F;a&gt; with its &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nix-direnv&quot;&gt;Nix addon&lt;&#x2F;a&gt; to automate this for you.&lt;&#x2F;p&gt;
&lt;p&gt;Once you have that configured, setting up a project is pretty simple. You’ll need a &lt;code&gt;shell.nix&lt;&#x2F;code&gt; as above, and then you create a file to tell &lt;code&gt;direnv&lt;&#x2F;code&gt; what to do.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ echo &amp;#39;use nix&amp;#39; &amp;gt; .envrc
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The error here demonstrates that you have to explicitly permit &lt;code&gt;direnv&lt;&#x2F;code&gt; to work in this directory. It prevents you accidentally running code in your shell directly from a Git checkout, or similar.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ direnv allow
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then all of your Nix dependencies will be installed, and you’ll return to your prompt in the same shell. It can take a little while, and if you do &lt;code&gt;nix-channel --update&lt;&#x2F;code&gt; or similar it will often do it again, but it’s pretty neat.&lt;&#x2F;p&gt;
&lt;p&gt;To take some of the time out of this, you can combine direnv with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;lorri&quot;&gt;lorri&lt;&#x2F;a&gt;. It’s a daemon that runs in the background and can react live to updates in &lt;code&gt;shell.nix&lt;&#x2F;code&gt;. It also prevents your dependencies being cleared out if you run &lt;code&gt;nix-collect-garbage&lt;&#x2F;code&gt;–more on that command later. This also makes it easier to kick off new projects using &lt;code&gt;lorri init&lt;&#x2F;code&gt; instead of creating the files manually like I described.&lt;&#x2F;p&gt;
&lt;p&gt;These days, at work, I’ve switched roles into one where I don’t do so much development as I used to, so I don’t actually use &lt;code&gt;lorri&lt;&#x2F;code&gt; any more. It’s still a pretty cool tool though and I’ll probably use it again if I return to a full-time software development role.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;home-manager&quot;&gt;Home Manager&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#home-manager&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;With Nix, I can create individual environments for projects I’m working on. It’d be cool if I could extend this idea to my entire login environment. With &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&quot;&gt;Home Manager&lt;&#x2F;a&gt;, I can. At a basic level, you can install it and do essentially the same thing as I described with &lt;code&gt;shell.nix&lt;&#x2F;code&gt; above, but it affects all of your shells. You can type &lt;code&gt;home-manager edit&lt;&#x2F;code&gt; and you’re dropped into an editor where you can make whatever changes you need, before using &lt;code&gt;home-manager switch&lt;&#x2F;code&gt; to apply them.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s a basic example from one of my machines:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;let&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;pkgsUnstable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixpkgs-unstable&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;in&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;home&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;stateVersion&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;19.09&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;home&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;packages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;awscli&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;direnv&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;htop&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;wget&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;ripgrep&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;jq&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgsUnstable&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;asuka&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here I’m installing some of the tools I expect to be available all the time, including a newer version of &lt;code&gt;git&lt;&#x2F;code&gt; than is provided by macOS or Xcode. I normally use the stable version of a Nix release, but here I wanted to use a Gemini client called &lt;code&gt;asuka&lt;&#x2F;code&gt; which wasn’t available in a stable release when I set this up, so I installed that from the &lt;code&gt;unstable&lt;&#x2F;code&gt; release.&lt;&#x2F;p&gt;
&lt;p&gt;If you keep your configuration in Git or somewhere like that, you can share it across machines, and have the same environment present everywhere you do work.&lt;&#x2F;p&gt;
&lt;p&gt;Home Manager lets you do more than just install packages, though. You can configure them too, and it’s a convenient way to manage dotfiles. For example, I keep my Git configuration in there, and so Home Manager will write that to &lt;code&gt;~&#x2F;.gitconfig&lt;&#x2F;code&gt; for me.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;programs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;git&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;userName&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Michael Maclean&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;userEmail&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;michael at thisdomain dot net&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It can also start services for you at login. One example of this is &lt;code&gt;gpg-agent&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;services&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;gpg-agent&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;defaultCacheTtl&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-nix&quot;&gt;1800&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enableSshSupport&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You’re also not limited to using it to install command line tools. On one of my Linux machines, I use it to configure VS Code and all the extensions I use. (I don’t use this on macOS–I’ll talk about that &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;why-nix&#x2F;#things-i-don-t-use&quot;&gt;later&lt;&#x2F;a&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;I use this on every machine I have access to. The configuration is kept in Git so I can update it, and as long as I remember to pull the changes on my other machines, I end up having the same set of tools available.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nixos&quot;&gt;NixOS&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#nixos&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;If you’ve read this far, you hopefully are able to see why I find Nix valuable. It lets me install the tools that I use and keep them configured the way I want in one place. It would be nice if I could build an entire system this way, which is where NixOS comes in. It’s a Linux distribution that fundamentally can be configured in the same way as I described above, using a Nix file to describe the state of the system you want. This differs from other configuration management tools, where sometimes you have to describe the set of actions that must be taken to make the system you want.&lt;&#x2F;p&gt;
&lt;p&gt;The nicest thing about NixOS for me is that some thought has gone into how the services on your machine should be configured. Instead of having to write separate files in different languages and scatter them all across &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt;, they’re all in one place (&lt;code&gt;&#x2F;etc&#x2F;nixos&#x2F;configuration.nix&lt;&#x2F;code&gt;) and use the same language. I run a Miniflux RSS reader, and configuring that was really simple and clear:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;services&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;miniflux&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;services&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nginx&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;recommendedGzipSettings&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;recommendedOptimisation&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;recommendedProxySettings&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;recommendedTlsSettings&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;virtualHosts&lt;&#x2F;span&gt;.&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rss-reader&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;forceSSL&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enableACME&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;locations&lt;&#x2F;span&gt;.&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;        &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;proxyPass&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http:&#x2F;&#x2F;127.0.0.1:8080&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;security&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;acme&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;acceptTerms&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;email&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;blah&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m not going to go into a lot more detail here as I’ve already covered some of what the rest of the system configuration looks like in previous posts. If you’d like to see what this might look like, check out these posts:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;nixos-on-raspberry-pi-4&#x2F;&quot;&gt;Installing NixOS on the Raspberry Pi 4&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;nixos-on-kimsufi&#x2F;&quot;&gt;Installing NixOS on Kimsufi machines&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;installing-nixos&#x2F;&quot;&gt;Installing NixOS on a desktop, with encrypted disks&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;evading-broken-dns&#x2F;&quot;&gt;This post on setting up a DNS server&lt;&#x2F;a&gt; shows another example of how simple it can be to configure services on NixOS.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Using NixOS doesn’t mean you need to throw out your Home Manager setup, either. I use NixOS’s own configuration to set up the hardware and the display manager, and to run services like OpenSSH on the machine, but all the software I want as a user (including Firefox, VS Code, that sort of thing) is set up using Home Manager. They coexist well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;things-i-don-t-use&quot;&gt;Things I don’t use&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#things-i-don-t-use&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Nix is a package manager, so obviously it can be used to package software for distribution. It can also build machine images, Docker images, Snaps, Flatpaks, and probably other things I’m forgetting. I don’t actually use it for much of that, which is related to me not doing full-time software development at the moment.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve also not tried to push the use of Nix for building software at work, partly due to the learning curve. I’m happy to help people as far as I can if they come to it themselves, but I’m not an evangelist for it there.&lt;&#x2F;p&gt;
&lt;p&gt;Although I use Nix on macOS quite happily, I don’t use Nix to install GUI software there. I do on Linux. On macOS, most of the packages I’m interested in (things like Virtualbox) are marked as Linux-only and while I could override that, I found it didn’t really work, so I’ve not directly replaced &lt;code&gt;brew cask&lt;&#x2F;code&gt; with Nix. There is a tool called &lt;code&gt;nix-darwin&lt;&#x2F;code&gt; that I believe can do some of this, but I’ve not tried it. On my work computer I suspect it may upset the MDM, and on my home Mac I’m happy enough with Home Manager.&lt;&#x2F;p&gt;
&lt;p&gt;In all three environments–&lt;code&gt;nix-shell&lt;&#x2F;code&gt;, Home Manager and NixOS–you can freeze the version of &lt;code&gt;nixpkgs&lt;&#x2F;code&gt; you are installing from, to specifically lock your environment to the versions of the dependencies that you know work. This is similar to a lock file in a package manager like Composer or NPM. I have used this a bit, but on the whole I’ve not had any trouble from just tracking the stable version of &lt;code&gt;nixpkgs&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-summary&quot;&gt;In summary&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#in-summary&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I get a lot of value out of Nix even at my current “advanced beginner” level of experience. I still don’t really know the Nix language. I’ve not used Flakes. I’ve not tried NixOps properly yet. All of these are things I am going to learn, but not knowing them has not held me back. I’ve been able to do all the things I’ve described, and do some contribution to &lt;code&gt;nixpkgs&lt;&#x2F;code&gt; itself, by learning from others and using the code and documentation that is already out there.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re a user of Nix already, you may note I’ve not talked about the core parts of how Nix works. I’ve not mentioned the store, nor immutability, nor really reproducibility–these are things that are important to how Nix works, but I find you don’t really need to understand them to make use of it.&lt;&#x2F;p&gt;
&lt;p&gt;I have had a lot of assistance along the way. The Nix community has been pretty welcoming, although #nixos on Libera IRC is a pretty busy place. &lt;a href=&quot;https:&#x2F;&#x2F;grahamc.com&quot;&gt;Graham&lt;&#x2F;a&gt; has helped me and many others out a lot in the past, and I’ve learned a fair bit from discussions with &lt;a href=&quot;https:&#x2F;&#x2F;seancoates.com&#x2F;&quot;&gt;Sean&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;nerderati.com&#x2F;&quot;&gt;Joël&lt;&#x2F;a&gt; too. Thanks to all of them, and those in the community that have helped me in the past.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Installing NixOS on the Raspberry Pi 4</title>
        <published>2021-09-04T00:00:00+00:00</published>
        <updated>2021-09-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/nixos-on-raspberry-pi-4/"/>
        <id>https://mgdm.net/weblog/nixos-on-raspberry-pi-4/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/nixos-on-raspberry-pi-4/">&lt;p&gt;I have been wanting to find a more permanent home for &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;evading-broken-dns&#x2F;&quot;&gt;the DNS server I built before&lt;&#x2F;a&gt; which was on a Pi 4 running Raspbian. As is evident by the number of posts I have on here about installing Nix on every computing device I can get my hands on, I wanted to put NixOS on it. Previously I’d not been keen doing that on an SD card because I still have a perception that Pis running Linux can chew them up pretty quickly, although I suppose reinstalling them from a reproducible OS would be less painful were this to happen.&lt;&#x2F;p&gt;
&lt;p&gt;As it happens, last week a vendor sent me an email saying that they had a sale on the &lt;a href=&quot;https:&#x2F;&#x2F;www.argon40.com&#x2F;argon-one-m-2-case-for-raspberry-pi-4.html&quot;&gt;Argon ONE m.2 case&lt;&#x2F;a&gt;, which would accept an m.2 SATA SSD. This would give me a bit more space and probably stand up to more use than the SD card would, so I got one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#requirements&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I could quite easily have just &lt;code&gt;dd&lt;&#x2F;code&gt;ed the SD card image onto the drive and booted that and called it a day, but I &lt;del&gt;wanted to make life difficult for myself&lt;&#x2F;del&gt; really wanted to use ZFS. I also wanted to use the AArch64 architecture instead of the armv7 that I believe Raspbian had been using.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing I did before getting started was boot Raspbian, update it, and then use it to update the firmware to a version that properly supports USB boot, as my Pi 4 was old enough not to have that out of the box.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rpi-eeprom-update &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Read the output of this before proceeding&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rpi-eeprom-update&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Actually do the update&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; raspi-config &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Go to Advanced Options and enable USB boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;installation-process&quot;&gt;Installation process&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#installation-process&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I did consider trying to install it from the existing Raspbian OS that was on the SD card already, in a similar fashion to &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;nixos-on-kimsufi&#x2F;&quot;&gt;how I did so using the Kimsufi recovery OS&lt;&#x2F;a&gt;, but as I believe it was running a different architecture I wasn’t sure how that would work.&lt;&#x2F;p&gt;
&lt;p&gt;I grabbed &lt;a href=&quot;https:&#x2F;&#x2F;hydra.nixos.org&#x2F;job&#x2F;nixos&#x2F;release-21.05&#x2F;nixos.sd_image_new_kernel.aarch64-linux&quot;&gt;the latest NixOS 21.05 &lt;code&gt;new_kernel&lt;&#x2F;code&gt; image I could find&lt;&#x2F;a&gt; on Hydra. This ended up being one built in July–images since then appear to have had some build failures due to something related to ZFS. I didn’t entirely pay attention here and ended up writing the compressed image to the SD card and trying to boot that–this predictably failed, and I re-read &lt;a href=&quot;https:&#x2F;&#x2F;nixos.wiki&#x2F;wiki&#x2F;NixOS_on_ARM&#x2F;Raspberry_Pi_4&quot;&gt;the instructions&lt;&#x2F;a&gt; and uncompressed it first before trying again.&lt;&#x2F;p&gt;
&lt;p&gt;Booting this results in it resizing to fit the SD card, and then drops you into a terminal. Normally here you’d probably create a &lt;code&gt;configuration.nix&lt;&#x2F;code&gt; and do &lt;code&gt;nixos-rebuild&lt;&#x2F;code&gt; to make the system you want, but I wanted to install to my SSD so I had a little more work to do.&lt;&#x2F;p&gt;
&lt;p&gt;The procedure I followed was remarkably similar to that I used for the Kimsufi box. The SSD even presented it as &lt;code&gt;&#x2F;dev&#x2F;sda&lt;&#x2F;code&gt;, the same as on that machine. I’ll reproduce the commands here, as there are a couple of differences.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;partitioning&quot;&gt;Partitioning&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#partitioning&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;wipefs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt; &#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; This sets a variable called DISK to save some typing later&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; It should be set to the file starting with ata in the directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&#x2F;dev&#x2F;disk&#x2F;by-id&#x2F;ata&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mklabel msdos&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkpart primary fat32 0MiB 512MiB &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; &#x2F;dev&#x2F;sda1 is &#x2F;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkpart primary 512MiB -4GiB &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; This is the ZFS partition&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkpart primary linux-swap -4GiB 100&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Swap. This is optional&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkfs.vfat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;F32&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-part1 &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Format &#x2F;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create the zpool&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;O&lt;&#x2F;span&gt; mountpoint=none rpool &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-part2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create some datasets inside the pool&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; mountpoint=legacy rpool&#x2F;root&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; mountpoint=legacy rpool&#x2F;root&#x2F;nixos&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; mountpoint=legacy rpool&#x2F;home&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt; zfs rpool&#x2F;root&#x2F;nixos &#x2F;mnt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;mnt&#x2F;home&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt; zfs rpool&#x2F;home &#x2F;mnt&#x2F;home&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;mnt&#x2F;boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-part1 &#x2F;mnt&#x2F;boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;nix-install&quot;&gt;Nix install&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#nix-install&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The installation process after this is a little cleaner than the one in the recovery system from previously.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nixos-generate-config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;root&lt;&#x2F;span&gt; &#x2F;mnt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, I can edit the files in &lt;code&gt;&#x2F;mnt&#x2F;etc&#x2F;nixos&lt;&#x2F;code&gt;. However, as the SD image I’m using is from July, it still has the same bug in it that I encountered last time, where the &lt;code&gt;nixos-install&lt;&#x2F;code&gt; process crashes out with errors similar to&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;getting attributes of path &#x2F;nix&#x2F;store&#x2F;dbri2d4r470fc6nrh95qa8bwcj54wh1q-zfs-kernel-2.0.5-5.10.52: No such file or directory
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This has been fixed in a new version of Nix, but it wasn’t incorporated in the build I was using. I again used the workaround from &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;issues&#x2F;126141#issuecomment-861724383&quot;&gt;this GitHub issue&lt;&#x2F;a&gt; to allow me to proceed, although as it was a native NixOS machine I didn’t have quite so much to type as before:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nix-build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&amp;lt;nixpkgs&#x2F;nixos&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;A&lt;&#x2F;span&gt; config.system.build.toplevel&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;I&lt;&#x2F;span&gt; nixos-config=&#x2F;mnt&#x2F;etc&#x2F;nixos&#x2F;configuration.nix&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nixos-install&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;root&lt;&#x2F;span&gt; &#x2F;mnt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;firmware&quot;&gt;Firmware&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#firmware&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The Raspberry Pi and&#x2F;or U-Boot need some firmware files to be present in the first filesystem on the disk. The SD installer image keeps this in a partition at &lt;code&gt;&#x2F;dev&#x2F;mmcblk0p1&lt;&#x2F;code&gt; which is not actually mounted normally. I opted to mount the equivalent of that partition at &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; on my install, so it contains the generated &lt;code&gt;initrd&lt;&#x2F;code&gt;. However, NixOS doesn’t currently provide a neat way of copying these files into place.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, I just did something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;firmware&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;mmcblk0p1 &#x2F;firmware&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;firmware&#x2F;&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt; &#x2F;mnt&#x2F;boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It took me a bit of effort to try and work out what partition type to use here, and then a little more to work out how to get the firmware on there. It’s not ideal, but you only need to do it once.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gotchas&quot;&gt;Gotchas&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#gotchas&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;There were a couple of things worth noting that I found out as I was doing this.&lt;&#x2F;p&gt;
&lt;p&gt;If the Pi’s firmware couldn’t work out what to do with the USB disk, it would fall back to booting off the SD card. This is fine in theory, but sometimes it would boot all the way past stage 2 and just at the point where you’d expect it to start a console the screen would go black, and then the monitor would switch off. The Pi wasn’t visible on the network at this point either so the only thing I could do was pull the power and give it a few moments before trying again. It normally worked from a cold boot.&lt;&#x2F;p&gt;
&lt;p&gt;It took me a little while to work out what the first partition should look like. I had a few occasions where the machine would complain &lt;code&gt;Unable to read partition as FAT&lt;&#x2F;code&gt;. In the end, I needed to make it FAT32, start right at the beginning of the disk instead of 1MiB in like I had done before, and also flag it as type &lt;code&gt;0c&lt;&#x2F;code&gt;, which is &lt;code&gt;W95 FAT32 (LBA)&lt;&#x2F;code&gt; according to &lt;code&gt;fdisk&lt;&#x2F;code&gt;. I’m not sure which were the important parts of this, but it works now.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, some NixOS-on-RPi documentation suggests using the &lt;code&gt;boot.tmpOnTmpfs&lt;&#x2F;code&gt; option to put &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; into a ramdisk. I found that doing that and asking Nix to install a few things at once made it run out of space very quickly and fail the build, so I turned that off. I could imagine that if I were to be installing on an SD card and not doing too much work I would consider enabling it again.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configuration-files&quot;&gt;Configuration files&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#configuration-files&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;These are here in case they’re useful to anyone.&lt;&#x2F;p&gt;
&lt;p&gt;My &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt; is pretty much the default, but there are some additions to include  &lt;code&gt;zfs&lt;&#x2F;code&gt; in the supported filesystems.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hardware-configuration-nix&quot;&gt;hardware-configuration.nix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#hardware-configuration-nix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;modulesPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;imports&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;modulesPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;installer&#x2F;scan&#x2F;not-detected.nix&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;initrd&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;availableKernelModules&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;xhci_pci&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;usbhid&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;uas&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;usb_storage&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;initrd&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;kernelModules&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;kernelModules&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;extraModulePackages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;initrd&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;supportedFilesystems&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zfs&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;supportedFilesystems&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zfs&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fileSystems&lt;&#x2F;span&gt;.&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;device&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rpool&#x2F;root&#x2F;nixos&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fsType&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zfs&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fileSystems&lt;&#x2F;span&gt;.&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;home&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;device&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rpool&#x2F;home&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fsType&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zfs&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fileSystems&lt;&#x2F;span&gt;.&lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;boot&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;device&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;sda1&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;fsType&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;vfat&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;swapDevices&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;powerManagement&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;cpuFreqGovernor&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkDefault&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;ondemand&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# high-resolution display&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;hardware&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;video&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;hidpi&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkDefault&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;configuration-nix&quot;&gt;configuration.nix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#configuration-nix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;As an experiment, I’m running XFCE on this, just to see how it performs. You can comment all of that out.&lt;&#x2F;p&gt;
&lt;p&gt;In this, I added an overlay, which you can see in the imports section. You can do this using the commands:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo nix-channel --add https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixos-hardware&#x2F;archive&#x2F;master.tar.gz nixos-hardware
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo nix-channel --update
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, the only thing it provided for me was the option to do hardware acceleration for X (the option called &lt;code&gt;hardware.raspberry-pi.&quot;4&quot;.fkms-3d.enable&lt;&#x2F;code&gt;). This didn’t work out for me, and X just gave me a black screen. I intend to dig into this further and hopefully manage to reenable it in the future.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;imports&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixos-hardware&#x2F;raspberry-pi&#x2F;4&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-path z-nix&quot;&gt;.&#x2F;hardware-configuration.nix&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;kernelPackages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;linuxPackages_rpi4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# tmpOnTmpfs = true; # See note&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;kernelParams&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;8250.nr_uarts=1&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;console=ttyAMA0,115200&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;console=tty1&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cma=128M&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;loader&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;raspberryPi&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;version&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-nix&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;loader&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;grub&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;boot&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;loader&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;generic-extlinux-compatible&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;hardware&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enableRedistributableFirmware&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;config&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;allowUnfree&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networking&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;hostName&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;nixpi&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networking&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;hostId&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;3bc6efa8&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# For ZFS&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networking&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networkmanager&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Set your time zone.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;time&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;timeZone&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Europe&#x2F;London&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networking&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;useDHCP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networking&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;interfaces&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;eth0&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;useDHCP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;networking&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;interfaces&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;wlan0&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;useDHCP&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Select internationalisation properties.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;i18n&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;defaultLocale&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;en_GB.UTF-8&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;console&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;font&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Lat2-Terminus16&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;keyMap&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;uk&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;services&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;xserver&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;displayManager&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;lightdm&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;desktopManager&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;xfce&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Configure keymap in X11&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;services&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;xserver&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;layout&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;gb&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;services&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;xserver&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;xkbOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;eurosign:e&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Enable sound.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;sound&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;hardware&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;pulseaudio&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Enabling this caused X to have a black screen on boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# hardware.raspberry-pi.&amp;quot;4&amp;quot;.fkms-3d.enable = true;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;users&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;users&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;michael&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;     &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;isNormalUser&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;     &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;extraGroups&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;wheel&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Enable ‘sudo’ for the user.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# List packages installed in system profile. To search, run:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# $ nix search wget&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;environment&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;systemPackages&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;vim&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Enable the OpenSSH daemon.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;services&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;openssh&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;system&lt;&#x2F;span&gt;.&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;stateVersion&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;21.05&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Installing NixOS on Kimsufi machines</title>
        <published>2021-07-26T00:00:00+00:00</published>
        <updated>2021-07-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/nixos-on-kimsufi/"/>
        <id>https://mgdm.net/weblog/nixos-on-kimsufi/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/nixos-on-kimsufi/">&lt;div class=&quot;notice&quot;&gt;
	&lt;p&gt;&lt;strong&gt;Note 2:&lt;&#x2F;strong&gt; This was fun at the time, but these days you probably want to use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nixos-anywhere&quot;&gt;nixos-anywhere&lt;&#x2F;a&gt; and probably &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;disko&quot;&gt;disko&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;I’ve been using a few EC2 and DigitalOcean machines for various small projects recently, but I was getting a little bored of the cost of all the little machines I’d ended up setting up for different purposes. I decided to consolidate them all into one hardware machine upon which I am going to run some containers (probably LXD, which I anticipate will be a future blog post). I opted to get a Kimsufi machine to see if I can persuade it to run NixOS. That way, the things I do which are Nix-native can live in NixOS containers, and all the other things that live on Ubuntu or similar can run inside LXD. There’s the theory. As it’s an experiment, I got one of the cheaper machines with a single disk to start with.&lt;&#x2F;p&gt;
&lt;p&gt;Installing a deeply non-standard OS on a machine to which you have no console access is fun. I complicated my life further by deciding to use ZFS to learn more about that too. A couple of hours of research led me to two separate web pages that I decided to collide together:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lewo.abesis.fr&#x2F;posts&#x2F;2019-12-01-install-nixos-on-kimsufi.html&quot;&gt;How to install NixOS on kimsufi&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nixos.wiki&#x2F;wiki&#x2F;NixOS_on_ZFS&quot;&gt;NixOS on ZFS on the NixOS Wiki&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;oops&quot;&gt;Oops&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#oops&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The major mistake I made through this process was assuming that the Kimsufi box would be happy enough booting using UEFI. Not so! I did all the setup and installed everything, and upon rebooting, my machine fell off the planet. It was unhappy to the point where it wouldn’t boot the rescue system any more and support had to intervene. Redoing it all assuming BIOS worked.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to&quot;&gt;How-to&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#how-to&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Set your machine to netboot into the rescue system using the Kimsufi control panel, and reboot it. You’ll get a password for the root user via email. The rescue system starts the machine up using a Linux distro provided over a read-only NFS, and a home directory which is in a &lt;code&gt;tmpfs&lt;&#x2F;code&gt; in memory. We’ll use this space to install the Nix tools later on. We’re logged in as root which gives us a fair amount of flexibility. The machine’s own hard disk is not mounted by default–we’ll do this after partitioning.&lt;&#x2F;p&gt;
&lt;p&gt;The first steps are to log in via SSH, and flatten the disk, then set up the partition layout.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;partitioning-and-formatting&quot;&gt;Partitioning and formatting&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#partitioning-and-formatting&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This layout is mostly inspired by the first post I mentioned above. It’s a 2TB disk and the machine has 8GB RAM, so I created a 512MB partition for &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;, then most of the disk is taken up by the ZFS partition, and the final 8GB is swap. I’m told it is theoretically possible to have &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; inside the ZFS pool but it can be hard to make it work reliably with &lt;code&gt;grub&lt;&#x2F;code&gt;, so I’m going to keep that one as &lt;code&gt;ext4&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to present all these commands as if it were a script, but I did it all interactively.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;wipefs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt; &#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; This sets a variable called DISK to save some typing later&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; It should be set to the file starting with ata in the directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&#x2F;dev&#x2F;disk&#x2F;by-id&#x2F;ata&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mklabel msdos&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkpart primary 1MiB 512MiB &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; &#x2F;dev&#x2F;sda1 is &#x2F;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkpart primary 512MiB -8GiB &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; This is the ZFS partition&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;parted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;dev&#x2F;sda&lt;span class=&quot;z-keyword z-operator z-end-of-options z-shell&quot;&gt; --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkpart primary linux-swap -8GiB 100&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Swap&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkfs.ext4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;L&lt;&#x2F;span&gt; boot &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-part1 &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Format &#x2F;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create the zpool&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; There are lots of options here: see the wiki page above&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;O&lt;&#x2F;span&gt; mountpoint=none rpool &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-part2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create some datasets inside the pool&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; I&amp;#39;m going to add another later for LXD but this is enough for now&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; mountpoint=legacy rpool&#x2F;root&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; mountpoint=legacy rpool&#x2F;root&#x2F;nixos&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; mountpoint=legacy rpool&#x2F;home&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt; zfs rpool&#x2F;root&#x2F;nixos &#x2F;mnt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;mnt&#x2F;home&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt; zfs rpool&#x2F;home &#x2F;mnt&#x2F;home&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;mnt&#x2F;boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-part1 &#x2F;mnt&#x2F;boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now the partition layout is complete. We can move on to the NixOS parts.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;getting-nix&quot;&gt;Getting Nix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#getting-nix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;There are some prerequisites needed before we can use Nix. These are largely from the first post above again.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create a user for the Nix daemon&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;groupadd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;g&lt;&#x2F;span&gt; 30000 nixbld&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;useradd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;u&lt;&#x2F;span&gt; 30000&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;g&lt;&#x2F;span&gt; nixbld&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;G&lt;&#x2F;span&gt; nixbld nixbld&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;useradd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; setupuser&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Set this to something you will remember, you&amp;#39;ll need it in a moment&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;passwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; setupuser &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; s&#x2F;root&#x2F;setupuser&#x2F; &#x2F;etc&#x2F;sudoers&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;su&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; setupuser&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt; &#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Install Nix&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; -L is required because the script is now a redirect&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;curl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;L&lt;&#x2F;span&gt; https:&#x2F;&#x2F;nixos.org&#x2F;nix&#x2F;install&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; This next line makes the Nix tools available in our shell&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-source z-shell&quot;&gt;source&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.nix-profile&#x2F;etc&#x2F;profile.d&#x2F;nix.sh&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nix-channel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;add&lt;&#x2F;span&gt; https:&#x2F;&#x2F;nixos.org&#x2F;channels&#x2F;nixos-21.05 nixpkgs&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nix-channel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We need to take a minor detour here as &lt;code&gt;nixos-generate-config&lt;&#x2F;code&gt; is not installed by default.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nix-shell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; nixos-generate-config&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-command z-backticks z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;which&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nixos-generate-config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;root&lt;&#x2F;span&gt; &#x2F;mnt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will place the usual configuration in &lt;code&gt;&#x2F;etc&#x2F;nixos&#x2F;configuration.nix&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;etc&#x2F;nixos&#x2F;hardware-configuration.nix&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hardware-configuration-nix&quot;&gt;hardware-configuration.nix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#hardware-configuration-nix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I didn’t change very much in here, I only added these two lines:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;initrd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;supportedFilesystems&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zfs&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;supportedFilesystems&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zfs&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;configuration-nix&quot;&gt;configuration.nix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#configuration-nix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I changed more in here. I’m not going to paste the entire config in here, but I will call out the key parts that were needed for this to work.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# This machine is very insistent on BIOS boot, so configure that&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;loader&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;grub&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;loader&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;grub&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;version&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-nix&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;loader&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;grub&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;device&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;sda&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# or &amp;quot;nodev&amp;quot; for efi only&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;hostName&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;metis&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Make a random 8-character hex string for this. ZFS requires it.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;hostId&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;13371337&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Check what the rescue system&amp;#39;s IP, route and optionally nameservers are&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# (or just use 8.8.8.8 for DNS if you like)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;usePredictableInterfaceNames&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;interfaces&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;eth0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;ipv4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;addresses&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;address&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;192.0.2.1&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;prefixLength&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-nix&quot;&gt;24&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;defaultGateway&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;192.0.2.254&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;nameservers&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;8.8.8.8&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;services&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# You can enable this once you&amp;#39;ve proved the machine boots&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;firewall&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;enable&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;users&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;users&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;michael&lt;&#x2F;span&gt; &lt;span class=&quot;z-invalid z-illegal&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# Usual user config goes here. Be sure to include your SSH public key&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;installing-nixos&quot;&gt;Installing NixOS&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#installing-nixos&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I again had to take a detour here, because something is a little broken in NixOS 21.05 at the moment, resulting in errors like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;getting attributes of path &#x2F;nix&#x2F;store&#x2F;dbri2d4r470fc6nrh95qa8bwcj54wh1q-zfs-kernel-2.0.5-5.10.52: No such file or directory
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I have no idea what causes this, and perhaps it’s fixed by the time you read this, but it is documented in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;issues&#x2F;126141#issuecomment-861724383&quot;&gt;this GitHub issue&lt;&#x2F;a&gt;. The workaround described at that comment allowed me to continue, with this fairly contorted pair of commands:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; PATH=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; NIX_PATH=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;NIX_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-command z-backticks z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;which&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nix-build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&amp;lt;nixpkgs&#x2F;nixos&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;A&lt;&#x2F;span&gt; config.system.build.toplevel&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;I&lt;&#x2F;span&gt; nixos-config=&#x2F;mnt&#x2F;etc&#x2F;nixos&#x2F;configuration.nix&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; PATH=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; NIX_PATH=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;NIX_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-command z-backticks z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;which&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nixos-install&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;root&lt;&#x2F;span&gt; &#x2F;mnt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all goes well, you should be asked to set a root password. You may encounter quite a lot of errors about locales being missing–I ignored these as they didn’t seem to matter.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, you should have a NixOS system ready to go on the machine’s internal disk. You’ll need to use the Kimsufi control panel to set the machine back to boot from its own hard disk, using the menu option marked Netboot.&lt;&#x2F;p&gt;
&lt;p&gt;Now, all you can do is &lt;code&gt;reboot&lt;&#x2F;code&gt; and cross your fingers. It worked for me, although it’s worth noting that it took a good couple of minutes for the machine to come up and respond to SSH. You can connect as the user you set up in &lt;code&gt;configuration.nix&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You will probably encounter an error when you connect because the SSH host key will have changed. You can fix this with &lt;code&gt;ssh-keygen -R 192.0.2.1&lt;&#x2F;code&gt; (replacing the IP with the one for your machine), and then try again. Hopefully you’ve now got a new NixOS machine up and running and ready to do whatever you need it to do.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#thanks&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Big thanks to &lt;a href=&quot;https:&#x2F;&#x2F;grahamc.com&quot;&gt;Graham Christensen&lt;&#x2F;a&gt; of Nix specialists &lt;a href=&quot;https:&#x2F;&#x2F;determinate.systems&#x2F;&quot;&gt;Determinate Systems&lt;&#x2F;a&gt; for helping me out throughout this process.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>systemd socket activation</title>
        <published>2021-07-19T00:00:00+00:00</published>
        <updated>2021-07-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/systemd-socket-activation/"/>
        <id>https://mgdm.net/weblog/systemd-socket-activation/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/systemd-socket-activation/">&lt;p&gt;My &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;systemd&#x2F;&quot;&gt;last post on this topic&lt;&#x2F;a&gt; caught some attention, so I’m going to continue exploring some of the systemd features that may be useful to people writing network services. Here are some more things about socket activation I didn’t cover in the previous post.&lt;&#x2F;p&gt;
&lt;p&gt;Firstly, it’s not something that needs a binding to a specific library to work (although systemd does make one available for this task). It uses conventions that already exist in Unix, and have done for a long time. The network sockets are presented as file descriptors, and some information about them as environment variables.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inetd&quot;&gt;inetd&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#inetd&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As I mentioned in the previous post, socket activation is pretty similar to how &lt;code&gt;inetd&lt;&#x2F;code&gt; operates. &lt;code&gt;inetd&lt;&#x2F;code&gt; is a “super-server”, which first appeared in 4.3BSD in 1986. There are other implementations of the same idea–&lt;code&gt;xinetd&lt;&#x2F;code&gt; is a common one using a different configuration format.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is that it listens on a set of ports normally configured in &lt;code&gt;&#x2F;etc&#x2F;inetd.conf&lt;&#x2F;code&gt;, and then any time a new connection arrives on that port, it will spawn a new instance of the configured process and send the incoming data to its standard input, and the process’s output back to the client. An example configuration for the &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc865&quot;&gt;Quote of the Day service&lt;&#x2F;a&gt; in the original &lt;code&gt;inetd&lt;&#x2F;code&gt; may look like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;qotd stream tcp nowait root &#x2F;usr&#x2F;sbin&#x2F;tcpd &#x2F;usr&#x2F;games&#x2F;fortune
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The fields are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The service name. This references a service list in &lt;code&gt;&#x2F;etc&#x2F;services&lt;&#x2F;code&gt;. In this case, &lt;code&gt;qotd&lt;&#x2F;code&gt; maps to port 17.&lt;&#x2F;li&gt;
&lt;li&gt;It’s a &lt;code&gt;stream&lt;&#x2F;code&gt; service operating over TCP, as opposed to a &lt;code&gt;dgram&lt;&#x2F;code&gt; service operating on UDP&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nowait&lt;&#x2F;code&gt; means to spawn a new instance of the process for every connection, instead of waiting for a single process to deal with each connection&lt;&#x2F;li&gt;
&lt;li&gt;This service is configured to run as root, which seems like an awful idea but may possibly be required for &lt;code&gt;tcpd&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The final fields are the command to run on each incoming connection. &lt;code&gt;tcpd&lt;&#x2F;code&gt; is a program that does some basic filtering of incoming traffic. I’ll skip over this for the moment.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;using-systemd-like-inetd&quot;&gt;Using systemd like inetd&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#using-systemd-like-inetd&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We can use systemd for the same purpose as &lt;code&gt;inetd&lt;&#x2F;code&gt;, by configuring it to create processes on demand and connecting the network socket to standard input and output.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s try it out, and use some of the features I talked about before to protect the service, as the &lt;code&gt;fortune&lt;&#x2F;code&gt; command isn’t really designed to be connected to a network so we don’t want it to get exploited. I’m on Ubuntu 21.04 here, but this should work on most distributions.&lt;&#x2F;p&gt;
&lt;p&gt;Create a file called &lt;code&gt;&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;fortune@.service&lt;&#x2F;code&gt;, and put the following in it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;QoTD
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# Note the - to make systemd ignore the exit code
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;usr&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;games&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;fortune
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# This is the part that makes it work like inetd
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;StandardOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;socket
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# Run as a dynamic user
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;yes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# ProtectSystem=strict # Implied by DynamicUser=yes
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# PrivateTmp=true # Also implied by DynamicUser=yes
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# DynamicUser implies ProtectHome=read-only, but we do not need home directories
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectHome&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# We also do not need to see users
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateUsers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;multi&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note the comments–some of the features I talked about before are enabled automatically when choosing &lt;code&gt;DynamicUser=true&lt;&#x2F;code&gt;. Also note the &lt;code&gt;@&lt;&#x2F;code&gt; in the filename - this is significant as it indicates the service is a template, and that a new instance of the service will be run on every connection.&lt;&#x2F;p&gt;
&lt;p&gt;Then put this in &lt;code&gt;&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;fortune.socket&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Socket]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# Listen on TCP port 17 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# Use ListenDatagram to listen on UDP
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ListenStream&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;17&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# Call accept(3) on the socket before handing it to the process
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# This is necessary because fortune knows nothing about the network
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Accept&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;yes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sockets&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After this, you’ll need to do &lt;code&gt;systemctl daemon-reload&lt;&#x2F;code&gt; followed by &lt;code&gt;systemctl start fortune.socket&lt;&#x2F;code&gt; (and &lt;code&gt;systemctl enable fortune.socket&lt;&#x2F;code&gt; if you want it to start on boot).&lt;&#x2F;p&gt;
&lt;p&gt;Now, we’ve built a QOTD service–port 17 is the IANA registered port number for this service. To try it out, you can use &lt;code&gt;nc&lt;&#x2F;code&gt; or perhaps &lt;code&gt;telnet&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mgdm@io:~$ nc localhost 17
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Never trust an operating system.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s good advice!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;socket-presentation-in-systemd&quot;&gt;Socket presentation in systemd&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#socket-presentation-in-systemd&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Socket activation using systemd’s own convention is similar to &lt;code&gt;inetd&lt;&#x2F;code&gt;, but has more room for expansion. The sockets themselves are presented to the process as file descriptors, similar to the inetd approach. The main difference that systemd does not use the standard streams, to allow it to supply more than one socket. It uses file descriptors numbered 3 and above. You can configure more than just the one I demonstrated above. If you specify more than one, they’ll be presented in the same order as they appear in the &lt;code&gt;.socket&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;In order for the process to be able to understand what to do with the sockets, a couple of environment variables are used. Firstly, &lt;code&gt;LISTEN_FDS&lt;&#x2F;code&gt; gives the number of sockets configured. For example, if this is set to &lt;code&gt;2&lt;&#x2F;code&gt;, the process will be able to work out that it has been given listening sockets on FDs 3 and 4.&lt;&#x2F;p&gt;
&lt;p&gt;It’s handy that you can configure several listening ports, but you also need to be able to work out which is which. Some software may want to listen on more than one port, and it may or may not be obvious which protocol should be configured on each–consider a hypothetical web server that may want to present plaintext HTTP on port 80 and HTTPS on port 443. In this case it’s probably quite easy to work out which service needs to go where from the port numbers, but regardless, it is possible to supply a name for each socket to make this slightly more foolproof. A variable called &lt;code&gt;LISTEN_FDNAMES&lt;&#x2F;code&gt; can be set with a colon-separated list of the name to be given to each socket.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#example&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s extend &lt;code&gt;lunchd&lt;&#x2F;code&gt; from &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;systemd&#x2F;&quot;&gt;my previous post&lt;&#x2F;a&gt;, and in the process finish the exercise I left at the end, by making it listen on both HTTP and HTTPS. On the HTTP port, we’ll just redirect every request we get to HTTPS.&lt;&#x2F;p&gt;
&lt;p&gt;The original &lt;code&gt;lunchd.socket&lt;&#x2F;code&gt; looked like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Socket]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ListenStream&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;443&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; both
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sockets&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We need to modify it slightly and then rename it. Add the extra &lt;code&gt;Service&lt;&#x2F;code&gt; and &lt;code&gt;FileDescriptorName&lt;&#x2F;code&gt; lines so it looks like below, and then rename it to &lt;code&gt;lunchd-https.socket&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Socket]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ListenStream&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;443&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; both
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;FileDescriptorName&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; https
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;lunchd&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;service
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sockets&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, copy it to &lt;code&gt;lunchd-http.socket&lt;&#x2F;code&gt; and change the port number there to 80 and the &lt;code&gt;FileDescriptorName&lt;&#x2F;code&gt; to &lt;code&gt;http&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Socket]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ListenStream&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;80&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; both
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;FileDescriptorName&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; http
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;lunchd&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;service
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sockets&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We now have two &lt;code&gt;.socket&lt;&#x2F;code&gt; files which is required if we want to present more than one different class of listening socket. By default, the names handed to the process for each socket type will be the same as the &lt;code&gt;.socket&lt;&#x2F;code&gt; files, but in this case we’re using the &lt;code&gt;FileDescriptorName&lt;&#x2F;code&gt; option to rename them.&lt;&#x2F;p&gt;
&lt;p&gt;Next up, we need to make a little change to the actual &lt;code&gt;lunchd&lt;&#x2F;code&gt; code. The CoreOS library I’ve been using since the last post knows to look for the &lt;code&gt;LISTEN_FDS&lt;&#x2F;code&gt; variable to find out how many file descriptors have been presented, and also has the ability to look at &lt;code&gt;LISTEN_FDNAMES&lt;&#x2F;code&gt; to group them by name. To make use of this latter feature we’re going to switch to using &lt;code&gt;activation.ListenersWithNames()&lt;&#x2F;code&gt; instead of  &lt;code&gt;activation.Listeners()&lt;&#x2F;code&gt;. This returns a &lt;code&gt;map[string][]net.Listener&lt;&#x2F;code&gt;. The keys in the map are the names configured in each &lt;code&gt;FileDescriptorName&lt;&#x2F;code&gt;, and the values are a slice of &lt;code&gt;net.Listener&lt;&#x2F;code&gt;s (as you can configure multiple &lt;code&gt;ListenStream&lt;&#x2F;code&gt; options in each file to listen on several interfaces or ports).&lt;&#x2F;p&gt;
&lt;p&gt;This code is now reaching the point where I should be refactoring it a little into more than one file, but I’ll keep it as one here just so everything’s on the same page. The key changes are that instead of assuming it’s going to listen on one port, it now looks into the map to work out what to listen on, and spins up a new &lt;code&gt;http.ServeMux&lt;&#x2F;code&gt; for each. Any sockets presented in the key &lt;code&gt;http&lt;&#x2F;code&gt; will listen on plain HTTP, and those in &lt;code&gt;https&lt;&#x2F;code&gt; will run TLS. Any other keys in the map are ignored. In the case where the map is empty (indicating the process is not being run using systemd, or not with socket activation), it’ll default to an unprivileged port (8443). In this way the code still runs happily on other Unix systems such as macOS.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve added a little more logging to this code, so you can see what the environment variables look like when systemd starts the process. In this case, I had port 80 configured for HTTP and port 443 configured for HTTPS, so &lt;code&gt;LISTEN_FDS&lt;&#x2F;code&gt; and &lt;code&gt;LISTEN_FDNAMES&lt;&#x2F;code&gt; looked like the below. The first line indicates there are 2 sockets, and the second denotes the protocols for each.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Jul 18 11:30:23 io lunchd[10425]: 2021&#x2F;07&#x2F;19 11:30:23 LISTEN_FDS is 2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Jul 18 11:30:23 io lunchd[10425]: 2021&#x2F;07&#x2F;19 11:30:23 LISTEN_FDNAMES is http:https
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code is &lt;a href=&quot;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;systemd-socket-activation&#x2F;#final-code&quot;&gt;below&lt;&#x2F;a&gt;, but it’s also available &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;lunchd&#x2F;blob&#x2F;v2&#x2F;main.go&quot;&gt;in a branch in the GitHub repo from last time&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#references&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;This post is quite heavily inspired by &lt;a href=&quot;http:&#x2F;&#x2F;0pointer.de&#x2F;blog&#x2F;projects&#x2F;socket-activation.html&quot;&gt;systemd for Developers I&lt;&#x2F;a&gt; by  Lennart Poettering&lt;&#x2F;li&gt;
&lt;li&gt;Thanks to &lt;a href=&quot;https:&#x2F;&#x2F;bigkevmcd.github.io&#x2F;&quot;&gt;Kevin McDermott&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jogbert&#x2F;&quot;&gt;James O’Gorman&lt;&#x2F;a&gt; for some advice on the Go code on both this and my last post&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;final-code&quot;&gt;Final code&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#final-code&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;pre data-linenos data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;crypto&#x2F;tls&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;errors&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;flag&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;math&#x2F;rand&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&#x2F;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sync&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;time&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github.com&#x2F;coreos&#x2F;go-systemd&#x2F;activation&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;19&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sandwich&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Soup&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Salad&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Burger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;23&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sushi&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;24&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;26&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;27&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Intn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;28&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;29&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getDefaultListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;31&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Listen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tcp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;:8443&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;33&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;35&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;36&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;37&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;38&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;39&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;41&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;42&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;43&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;44&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;activation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ListenersWithNames&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;45&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;46&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;47&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Received no listeners from socket activation, defaulting to HTTPS on port 8443&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;48&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getDefaultListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;49&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;50&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;51&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;52&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;53&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;54&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getCertificatePaths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;55&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;keyPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;flag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;The path to the private key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;certPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;flag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;certificate&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;The path to the certificate&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;57&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;flag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Parse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;58&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;59&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;60&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;errors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;New&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Either or both of -key or -certificate not set&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;61&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;62&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;63&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;64&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;65&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;66&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getTLSConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;keyPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;certPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;67&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;config&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;68&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Certificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;             &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Certificate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;69&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;NextProtos&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;               &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;h2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http&#x2F;1.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;70&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;PreferServerCipherSuites&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;71&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;72&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;73&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;74&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;75&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Loading certs from key: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt; and cert: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;76&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;77&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Certificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;LoadX509KeyPair&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;78&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;79&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;80&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;81&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;82&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;83&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Failed to configure TLS: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;84&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;85&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;86&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;87&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;88&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;89&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;90&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;createWebServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ServeMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ServeMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;91&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;httpMux&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewServeMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;92&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;httpMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandleFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;req&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;93&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;HTTP request from &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;RemoteAddr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;94&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;hostname&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Host&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;95&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Redirect&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hostname&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;RequestURI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;StatusMovedPermanently&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;96&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;97&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;98&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;httpsMux&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewServeMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;99&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;httpsMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandleFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;req&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;100&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;HTTPS request from &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;RemoteAddr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;h1&amp;gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&amp;lt;&#x2F;h1&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;102&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;103&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;104&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;httpMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;httpsMux&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;105&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;106&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;107&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;108&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;UnixNano&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;109&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;110&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;LISTEN_FDS is &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;LISTEN_FDS&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;111&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;LISTEN_FDNAMES is &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;LISTEN_FDNAMES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;112&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;113&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;114&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;httpMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;httpsMux&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;createWebServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;115&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;116&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;117&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Could not set up listeners: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;118&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;119&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;120&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; This is used to block the main goroutine and wait for the others 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;121&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;wg&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;WaitGroup&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;122&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;123&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;tlsListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ok&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;ok&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;124&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getCertificatePaths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;125&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;126&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;127&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Could not load certificates: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;128&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;129&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;130&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;tlsConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getTLSConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;131&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;132&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tlsListeners&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;133&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-variable z-other z-go&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Add&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;134&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;135&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;l&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;136&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;				&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Starting secure web server on port &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;137&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;				&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;tl&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tlsConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;138&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;				&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Serve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;httpsMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;139&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tlsListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;140&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;141&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;142&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;143&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;plainListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ok&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;ok&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;144&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;plainListeners&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;145&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-variable z-other z-go&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Add&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;146&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;147&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;l&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;148&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;				&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Starting plaintext web server on port &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;149&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;				&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Serve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;httpMux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;150&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;plainListeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;151&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;152&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;153&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;154&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; The code never calls `wg.Done()` so this will block forever
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;155&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Letting the other goroutines carry on serving
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;156&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Wait&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;157&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using Nix to install Go tools for VS Code</title>
        <published>2021-07-11T00:00:00+00:00</published>
        <updated>2021-07-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/vscode-nix-go-tools/"/>
        <id>https://mgdm.net/weblog/vscode-nix-go-tools/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/vscode-nix-go-tools/">&lt;p&gt;I use both Nix on macOS and NixOS on different machines, so most of my projects have acquired &lt;code&gt;shell.nix&lt;&#x2F;code&gt; files at their root so that I can have the same set of tools and dependencies available to me regardless of which machine I’m on. I also use VS Code at least some of the time, and the Go extension there requires a number of command line tools for much of its functionality. It’s quite happy to go off and install these itself, but that I’d prefer to maintain those using Nix.&lt;&#x2F;p&gt;
&lt;p&gt;After some experimentation, here’s a skeleton &lt;code&gt;shell.nix&lt;&#x2F;code&gt; that provides everything VS Code’s Go extension looks for:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-function z-2 z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-function z-1 z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixpkgs&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-entity z-function z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;pkgs&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;buildInputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;gotools&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;gopls&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;go-outline&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;gocode&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;gopkgs&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;gocode-gomod&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;godef&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;golint&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I find it works best if I switch to the project directory, enter &lt;code&gt;nix-shell&lt;&#x2F;code&gt; (or &lt;a href=&quot;https:&#x2F;&#x2F;hardselius.github.io&#x2F;2020&#x2F;nix-shell-and-direnv&#x2F;&quot;&gt;use direnv&lt;&#x2F;a&gt; if you prefer), then launch Code using &lt;code&gt;code .&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I have tried the &lt;code&gt;nix-env-selector&lt;&#x2F;code&gt; extension in the past, but I’ve found that not every VS Code language extension plays well with that, and previously Go was one of those which didn’t. I will give it another shot later, but for now this works for me.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Avoiding complexity with systemd</title>
        <published>2021-06-26T00:00:00+00:00</published>
        <updated>2021-06-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/systemd/"/>
        <id>https://mgdm.net/weblog/systemd/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/systemd/">&lt;p&gt;Unix machines, since the early days of the operating system, have been designed for multiple users to use concurrently. Traditionally there is a set of “unprivileged” users used by people and system services, and the root account which can generally do anything. Because of the concept that most things in Unix are represented by a file, users could be allowed to perform various operations by adding them to groups and using filesystem permissions. There were also other functions which could not be delegated in this way–notably, binding to certain IP ports. Various operating systems developed over the years have blurred these lines a little, particularly on Linux which has features like capabilities and ACLs that allow more control than the standard Unix permission model provides.&lt;&#x2F;p&gt;
&lt;aside&gt;
Linux goes much further than this. There are mandatory access control systems like SELinux or AppArmor that let you apply restrictions at the kernel level outside of the software you&#x27;re running. Features like `cgroups` and namespaces combine to provide what we now call containers. Other features like `seccomp` allow software to opt-in to limits on its own ability to use various system calls. 
&lt;p&gt;BSD operating systems have similar features, notably &lt;code&gt;pledge&lt;&#x2F;code&gt; and &lt;code&gt;unveil&lt;&#x2F;code&gt; on OpenBSD.&lt;&#x2F;p&gt;
&lt;&#x2F;aside&gt;
&lt;p&gt;Much of the original permission model remains to this day. If you want to run a service that listens on a “well-known” port, those numbered less than 1024, you generally need to be root to bind to the port. There are other ways to allow this on Linux, such as applying a capability called &lt;code&gt;CAP_NET_BIND_SERVICE&lt;&#x2F;code&gt; to the program you want to run, but most server software that is designed to be portable among Unix systems implements a feature called privilege dropping. The service initially starts as root, binds to the ports that it requires, and then calls some functions to set its own user and group IDs to an unprivileged user. Ideally it does this before doing any significant work in order to minimise the potential for an exploit to occur while running as root.&lt;&#x2F;p&gt;
&lt;p&gt;Even if the service isn’t going to bind to a privileged port, sometimes there are files only readable by root that are required for the service to operate. A good example of these are the private keys for TLS certificates, which often live in a root-owned directory under &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt;. It’s common to do a similar trick to access these–start the service as root, open the files, and then drop the privileges once they’ve been read. Ideally the service will drop the privileges before parsing anything. Parser code needs to be written very carefully, especially in languages with manual memory management, and it has historically been a source of security vulnerabilities.&lt;&#x2F;p&gt;
&lt;p&gt;All of this adds a bit of complexity to the services we write, which it would be nice to avoid. It also adds to the attack surface: privilege dropping code has been a source of vulnerabilities, notably on a couple of occasions in Bash. Avoiding writing it at all, or at least delegating it to other software with more testing than our own, would be good.&lt;&#x2F;p&gt;
&lt;p&gt;It’s fairly common these days to write a service that runs on an unprivileged port and then run some other software in front of it as a reverse proxy–often nginx or Apache are used for this purpose. Depending on the use case these may provide some advantages, but they do require additional configuration and will use some resources on the machines operating the service.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;an-example&quot;&gt;An example&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#an-example&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;I’m working on my new startup idea–Lunch as a Service, a new SaaS application to solve the complex problem of deciding what to have for lunch. While I’m working on getting the VC funding together, I’m not going to be deploying it on a huge Kubernetes setup with a service mesh and a GitOps CI&#x2F;CD platform. While that would be nice one day, for now I’m going to make do with a VM.&lt;&#x2F;p&gt;
&lt;p&gt;The core of the new service is &lt;code&gt;lunchd&lt;&#x2F;code&gt;. It looks like this.&lt;&#x2F;p&gt;
&lt;pre data-linenos data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;math&#x2F;rand&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&#x2F;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;time&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sandwich&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Soup&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Salad&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Burger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sushi&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;19&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Intn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;23&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;UnixNano&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;24&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandleFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;req&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;26&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;h1&amp;gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&amp;lt;&#x2F;h1&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;27&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;28&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;29&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Starting web server on port 8080&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ListenAndServe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;:8080&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;31&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m using a reasonably recent Linux distribution with &lt;code&gt;systemd&lt;&#x2F;code&gt;, so I’m going to use that to start the service when the machine boots. The basic unit file looks like this.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-comment z-genconfig&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-genconfig&quot;&gt;# This goes in &#x2F;etc&#x2F;systemd&#x2F;system&#x2F;lunchd.service
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Lunch as a Service
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;usr&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;local&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;bin&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;multi&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’ve added a user called &lt;code&gt;lunchd&lt;&#x2F;code&gt; for the the service. After running &lt;code&gt;sudo systemctl daemon-reload&lt;&#x2F;code&gt;, I can then do &lt;code&gt;sudo systemctl start lunchd&lt;&#x2F;code&gt;. The service is hard coded to run on port 8080 right now, which is not a privileged port so it’ll start quite happily and run as a standard user. The final line makes sure it starts when the system boots normally.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-it-ready-for-production&quot;&gt;Getting it ready for production&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#getting-it-ready-for-production&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I can boot the application and have it run as a user other than root, which is a good start. However, I want it to be able to run on port 443 and use a TLS certificate. I would also like to use some of the filesystem protection features that systemd advertises. Can I use all of these to avoid writing code to drop privileges?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;filesystem-sandboxing&quot;&gt;Filesystem sandboxing&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#filesystem-sandboxing&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Our service doesn’t require much in the way of filesystem access. &lt;code&gt;systemd&lt;&#x2F;code&gt; provides ways to restrict the parts of the filesystem the service can see. By doing so, we can limit some of the opportunities for an attacker if the service is compromised.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ProtectSystem&lt;&#x2F;code&gt; can be set to &lt;code&gt;true&lt;&#x2F;code&gt; to make &lt;code&gt;&#x2F;usr&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; or &lt;code&gt;&#x2F;efi&lt;&#x2F;code&gt; read-only for this process. If set to &lt;code&gt;full&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt; is read-only too. &lt;code&gt;strict&lt;&#x2F;code&gt; makes the entire filesystem hierarchy read-only. This is fine for this service as it doesn’t read anything, so we’ll enable that.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ProtectHome&lt;&#x2F;code&gt; can be set to &lt;code&gt;true&lt;&#x2F;code&gt; to make &lt;code&gt;&#x2F;home&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;root&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;run&#x2F;user&lt;&#x2F;code&gt; empty and inaccessible from the point of view of the service.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;PrivateTmp&lt;&#x2F;code&gt; makes sure that the process’s temp directories are only visible to itself, and not another process. Additionally, they’ll be emptied once the process finishes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The complete list of options can be found &lt;a href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd.exec.html&quot;&gt;in the systemd documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s add some of these features to our unit file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Lunch as a Service
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;usr&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;local&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;bin&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectSystem&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;strict
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectHome&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateUsers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateTmp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;multi&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are far more options available here than I really want to get into describing. The documentation linked above is a good reference. To get some ideas for a service of your own, you can try a command similar to&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemd-analyze security lunchd.service&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;no-pager&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gives you an overview of what security features systemd has, and which are enabled. It is probably not a matter of just enabling everything it mentions, as then your service may not be able to do very much–instead, you should consider these as suggestions and see if they will work for you.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dynamic-users&quot;&gt;Dynamic users&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#dynamic-users&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Traditionally, many services have expected to run as a defined user and group, usually specified in their configuration file. Some will start and run as that user if they don’t need to do anything privileged, but others will start as root and switch. Many common internet services such as web and mail servers operate in this way.&lt;&#x2F;p&gt;
&lt;p&gt;With systemd we can have a brand new user and group allocated for us when the service starts. These users are prevented from changing any state in the system except in the directories detailed above. Once the service exits, the user is removed–it never actually exists in &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt;. This makes it harder to create a persistent route in to a system after an exploit.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Lunch as a Service
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;usr&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;local&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;bin&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectSystem&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;strict
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectHome&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateUsers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateTmp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;yes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;multi&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For this I’ve removed the system user I added earlier. After another &lt;code&gt;daemon-reload&lt;&#x2F;code&gt; and restarting the service, we can see that the service is still running as a user called &lt;code&gt;lunchd&lt;&#x2F;code&gt;, but it has a very high user ID:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mgdm@lunchbox:~$ ps aux | grep lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lunchd     33146  0.2  0.4 1002788 4312 ?        Ssl  20:28   0:00 &#x2F;usr&#x2F;local&#x2F;bin&#x2F;lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mgdm@lunchbox:~$ id lunchd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;uid=62840(lunchd) gid=62840(lunchd) groups=62840(lunchd)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;None of these changes have, so far, required much in the way of modification to our source code. At the most, we just need to make sure our service can accept some configuration for the directories it writes to.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;using-port-80&quot;&gt;Using port 80&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#using-port-80&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Although we’ve added some security features, our service is still running on port 8080. That’s fine for development purposes, but we’ve run into the first of the problems I described at the start. We want to bind to a privileged port, but the service is now definitely running as an unprivileged user.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;systemd&lt;&#x2F;code&gt; has a feature called socket activation, which allows it to bind to a port and then hand a file descriptor for that port to a process it launches. It can either launch the process once per connection, in a similar fashion to the old &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inetd&quot;&gt;inetd daemon&lt;&#x2F;a&gt;, or it can bind to the port once and hand it to a persistent process. This latter option is what we’ll do. It does require some modification to the code, but none of it will ever run as root which further reduces the attack surface.&lt;&#x2F;p&gt;
&lt;p&gt;It’s certainly possible to hand-write this code but in this case I’m going to use a package from CoreOS. If you’d like to see a minimal hand-written version, check out &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;systemd&#x2F;portable-walkthrough-go&#x2F;blob&#x2F;master&#x2F;main.go#L15-L31&quot;&gt;this one from Lennart Poettering&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s the modified service.&lt;&#x2F;p&gt;
&lt;pre data-linenos data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;math&#x2F;rand&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&#x2F;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;time&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github.com&#x2F;coreos&#x2F;go-systemd&#x2F;activation&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sandwich&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Soup&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Salad&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Burger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;19&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sushi&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;23&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Intn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;24&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;26&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;27&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;activation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;28&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;29&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Excpected one listener, got &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%d&lt;&#x2F;span&gt;: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;31&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Listen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tcp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;:8080&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;33&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;35&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;36&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;37&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;38&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;39&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;UnixNano&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;41&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;42&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;43&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;44&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;45&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;                &lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Panicf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Could not set up listener: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;46&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;47&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;48&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandleFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;req&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;49&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;                &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;h1&amp;gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&amp;lt;&#x2F;h1&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;50&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;51&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;52&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Starting web server on port &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;53&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Serve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;54&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we’ve built the new version, we can test the freshly-built version before deploying it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mgdm@lunchbox:~$ systemd-socket-activate -l 8080 .&#x2F;main
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Listening on [::]:8080 as 3.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Communication attempt on fd 3.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Execing .&#x2F;main (.&#x2F;main)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Starting web server on port 8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This runs fine. To make it work this way permanently, we need to create a socket file for systemd in addition to the service file. It describes the port you want the systemd to bind to and pass to the service. This can go in &lt;code&gt;&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;lunchd.socket&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Socket]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ListenStream&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;80&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; both
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Accept&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;no&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sockets&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After another &lt;code&gt;systemctl daemon-reload&lt;&#x2F;code&gt;, you can then type &lt;code&gt;systemctl start lunchd.socket&lt;&#x2F;code&gt; which will make it listen to the port.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Accept&lt;&#x2F;code&gt; option provides a choice between systemd starting the service once and handing it the listening sockets (&lt;code&gt;Accept=no&lt;&#x2F;code&gt;), or starting a new instance of the service on each request (&lt;code&gt;Accept=yes&lt;&#x2F;code&gt;). This latter mode is quite like how &lt;code&gt;inetd&lt;&#x2F;code&gt; operates.&lt;&#x2F;p&gt;
&lt;p&gt;Another advantage of having systemd listen on these ports is that if the service crashes, requests can still come in on port 80 and systemd will take care of starting a new one for you. Theoretically at least, this means you shouldn’t drop those requests.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adding-https&quot;&gt;Adding HTTPS&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#adding-https&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;For this we’ll need a certificate, which most of the time we can get from LetsEncrypt. However, most LetsEncrypt clients will place the private key somewhere in &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt; in a directory only accessible by root. This is fine, as having the private key owned by another user makes it harder to steal in the event our service is compromised. (We’ll just have to hope we don’t have &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cloudbleed&quot;&gt;some kind of memory leak attack&lt;&#x2F;a&gt;). We want to be able to use the certificate, but we don’t want to use privilege dropping here.&lt;&#x2F;p&gt;
&lt;p&gt;Normally for this, we’d use code something like the following, &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;src&#x2F;crypto&#x2F;tls&#x2F;example_test.go#L114&quot;&gt;taken from the Go documentation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-linenos data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;ExampleLoadX509KeyPair&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;LoadX509KeyPair&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;example-cert.pem&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;example-key.pem&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cfg&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Certificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Certificate&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;cert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Listen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tcp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;:2000&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;cfg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can pretty much use this, although the paths are hard-coded so this assumes the process is going to be able to open the files from whatever user it’s running as. I’ve used &lt;code&gt;certbot&lt;&#x2F;code&gt; to create a LetsEncrypt certificate, which is stored in &lt;code&gt;&#x2F;etc&#x2F;letsencrypt&#x2F;live&#x2F;lunch.mgdm.net&lt;&#x2F;code&gt; and is only readable by root.&lt;&#x2F;p&gt;
&lt;p&gt;We can work around this using systemd. It can open the files and present them in a modified filesystem view to the service. We’ll need to make some more changes to our code, but we were going to have to do this anyway to add the TLS. The only thing to remember is to make the paths to those files configurable. In this case, I’ve added flags called &lt;code&gt;key&lt;&#x2F;code&gt; and &lt;code&gt;certificate&lt;&#x2F;code&gt; which provide the paths to the TLS private key and the certificate with its chain.&lt;&#x2F;p&gt;
&lt;p&gt;The key thing here is the &lt;code&gt;LoadCredential&lt;&#x2F;code&gt; setting. It takes both a key and a path, separated by &lt;code&gt;:&lt;&#x2F;code&gt;. systemd will load the contents of the file at the specified path, and expose it in a directory as a file named after the key. This directory is given to the process as an environment variable called &lt;code&gt;CREDENTIALS_DIRECTORY&lt;&#x2F;code&gt;, which can also be used in the &lt;code&gt;ExecStart&lt;&#x2F;code&gt; line of the unit file. You can see this in action in the modified unit file below. We’ve also made a change to the socket file in order to make it listen on port 443 instead.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;lunchd-service&quot;&gt;lunchd.service&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#lunchd-service&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Lunch as a Service
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;usr&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;local&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;bin&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;lunchd &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;key&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-source z-genconfig&quot;&gt;${CREDENTIALS_DIRECTORY}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;key&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;pem &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;certificate&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-source z-genconfig&quot;&gt;${CREDENTIALS_DIRECTORY}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;chain&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;pem
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;LoadCredential&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;key&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;pem&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;etc&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;letsencrypt&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;live&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;lunch&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-genconfig&quot;&gt;mgdm.net&#x2F;privkey.pem&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;LoadCredential&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;chain&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;pem&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;etc&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;letsencrypt&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;live&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;lunch&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-genconfig&quot;&gt;mgdm.net&#x2F;fullchain.pem&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectSystem&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;strict
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ProtectHome&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateUsers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;PrivateTmp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;DynamicUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-genconfig&quot;&gt;yes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;multi&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;lunchd-socket&quot;&gt;lunchd.socket&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#lunchd-socket&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Socket]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ListenStream&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;443&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;BindIPv6Only&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; both
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sockets&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;main-go&quot;&gt;main.go&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#main-go&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-linenos data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;crypto&#x2F;tls&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;flag&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;math&#x2F;rand&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&#x2F;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;time&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github.com&#x2F;coreos&#x2F;go-systemd&#x2F;activation&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sandwich&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Soup&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;19&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Salad&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Burger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sushi&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;23&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;24&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Intn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;lunchOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;26&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;27&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;28&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;29&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;activation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;31&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Excpected one listener, got &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%d&lt;&#x2F;span&gt;: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;33&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Listen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tcp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;:8080&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;35&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;36&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;37&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;38&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listeners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;39&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;41&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;getCertificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;42&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;keyPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;flag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;The path to the private key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;43&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;certPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;flag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;certificate&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;The path to the certificate&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;44&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;flag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Parse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;45&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;46&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;47&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Either or both of -key or -cert not set&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;48&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;49&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;50&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;51&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;52&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;53&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;tlsSetup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;keyPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;certPath&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;listener&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;54&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;config&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;55&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Certificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;             &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Certificate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;NextProtos&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;               &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;h2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http&#x2F;1.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;57&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;PreferServerCipherSuites&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;58&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;59&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;60&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;61&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;62&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Loading certs from key: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt; and cert: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;63&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;64&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Certificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;LoadX509KeyPair&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;65&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;66&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;67&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;68&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;69&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;70&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Failed to configure TLS: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;71&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;72&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;73&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;74&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tls&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;75&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;76&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;77&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;78&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;UnixNano&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;79&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;80&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;81&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;82&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;83&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Could not set up listener: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;84&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;85&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;86&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getCertificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;87&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;88&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;89&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Could not load certificates: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;90&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;91&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;92&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;tlsListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;tlsSetup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;keyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;certPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;listener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;93&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;94&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandleFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;req&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;95&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;h1&amp;gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&amp;lt;&#x2F;h1&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;getRandomLunch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;96&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;97&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;98&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Starting web server on port &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;tlsListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;99&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Serve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;tlsListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;tr&gt;&lt;td&gt;100&lt;&#x2F;td&gt;&lt;td&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we make these changes, compile it, and deploy it, we can see the following in the journal by running &lt;code&gt;sudo journalctl -xe&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Jun 26 12:05:35 lunchbox lunchd[943]: 2021&#x2F;06&#x2F;26 12:05:35 Loading certs from key: &#x2F;run&#x2F;credentials&#x2F;lunchd.service&#x2F;key.pem and cert: &#x2F;run&#x2F;credentials&#x2F;lunchd.service&#x2F;chain.pem
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This shows that the &lt;code&gt;CREDENTIALS_DIRECTORY&lt;&#x2F;code&gt; has been set to &lt;code&gt;&#x2F;run&#x2F;credentials&#x2F;lunchd.service&lt;&#x2F;code&gt; in this case, and the private key and chain are exposed there. To make this work, no changes have been made to the code beyond that required to enable TLS, which would be common to any platform I ran this code on. The only thing that I’ve done is made sure that I can specify the paths to the key and certificate on the command line. The systemd-specific &lt;code&gt;CREDENTIALS_DIRECTORY&lt;&#x2F;code&gt; is only referenced in the unit file.&lt;&#x2F;p&gt;
&lt;p&gt;I could modify the service further so that systemd sets up listeners on both ports 80 and 443, so the service deals with both HTTP and HTTPS itself, but I think I’ll leave that as an exercise for the reader.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#references&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;I found the following articles helpful.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;systemd.exec.html&quot;&gt;The documentation for systemd.exec&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;ageis&#x2F;f5595e59b1cddb1513d1b425a323db04&quot;&gt;Options for hardening systemd service units&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;vincent.bernat.ch&#x2F;en&#x2F;blog&#x2F;2018-systemd-golang-socket-activation&quot;&gt;Integration of a Go service with systemd: socket activation by Vincent Bernat&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;wiki.debian.org&#x2F;ServiceSandboxing&quot;&gt;The Debian docs on Service Sandboxing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;0pointer.net&#x2F;blog&#x2F;walkthrough-for-portable-services-in-go.html&quot;&gt;Walkthrough for Portable Services in Go&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;lunchd&quot;&gt;The code is on GitHub&lt;&#x2F;a&gt; in case it’s useful to anyone.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to accidentally a MySQL server</title>
        <published>2021-03-23T00:00:00+00:00</published>
        <updated>2021-03-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/how-to-accidentally-mysql/"/>
        <id>https://mgdm.net/weblog/how-to-accidentally-mysql/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/how-to-accidentally-mysql/">&lt;h2 id=&quot;a-long-time-ago-in-a-company-far-far-away&quot;&gt;A long time ago, in a company far, far away&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#a-long-time-ago-in-a-company-far-far-away&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Our site ran on dedicated hardware, rented from a managed hosting provider who we never really got around to doing a lot of managing. As such, we all had root on all the machines, and so were free to do what we wanted. We also didn’t really know a lot about configuration management at that point, so changes were largely ad-hoc and unrepeatable.&lt;&#x2F;p&gt;
&lt;p&gt;At some point we found that the DB server was a bit slow for some queries, and that it had a lot more RAM than it appeared to be using. While nowadays I would probably assume that I could bump the &lt;code&gt;innodb_buffer_pool_size&lt;&#x2F;code&gt; up by some gigabytes, at that point what appeared to be a really great idea to past-Michael was to stick the MySQL temporary tables into a RAM disk. This made things &lt;em&gt;fly&lt;&#x2F;em&gt; and seemed like a totally great idea with no possible future negative consequences.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-the-mean-time&quot;&gt;In the mean time&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#in-the-mean-time&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We were using the site to show some media that required us to implement a geographic filter for the viewers. This was implemented by either using the users’ device’s geolocation to supply a latitude and longitude, or by having the user enter a postal code. Our site could look up whether it was within a certain bounding box, and if not it would redirect to another provider.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;eventually&quot;&gt;Eventually&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#eventually&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We came to move to AWS. We had everything built out with configuration management, deployed our site to EC2, used &lt;code&gt;memcached&lt;&#x2F;code&gt; provided by Elasticache, and finally put our MySQL database on RDS.&lt;&#x2F;p&gt;
&lt;p&gt;We had a couple of runs at switching it over from the dedicated host. The second time it finally stuck, after bumping the database size up a bit. That evening we had one of these media events that needed the geographic filter. I had hoped that we wouldn’t need to use it, but it turned out we had to. I hung around in the office to watch what ensued.&lt;&#x2F;p&gt;
&lt;p&gt;About 10 minutes prior to the event, the site fell all the way over. Something was thrashing the database in a way that hadn’t been happening before.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;skip-to-the-end&quot;&gt;Skip to the end&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#skip-to-the-end&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It turned out our geographic filter was implemented like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;User provides their latitude and longitude via the geolocation API on a device like an iPad&lt;&#x2F;li&gt;
&lt;li&gt;The site does a query against a table containing a snapshot of the Ordnance Survey Codepoint database. This is a list of every known UK postal code and the coordinates of its centre point, which consisted of something like 350 000 rows.&lt;&#x2F;li&gt;
&lt;li&gt;This query implements the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Haversine_formula&quot;&gt;Haversine formula&lt;&#x2F;a&gt;, which uses spherical trigonometry to calculate a pretty accurate &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Great-circle_distance&quot;&gt;great circle distance&lt;&#x2F;a&gt; between the user-supplied point, and each of the 350 000 rows in the Codepoint database.&lt;&#x2F;li&gt;
&lt;li&gt;The query finished up with &lt;code&gt;ORDER BY distance LIMIT 1&lt;&#x2F;code&gt;, which threw away 349 999 of those rows and returned the distance to the nearest. It could then see if this row was within the area for which we held the rights.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The query looked like the below, and I suspect it was taken from &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;13250645&#x2F;sql-syntax-error-haversine-formula&quot;&gt;this StackOverflow answer&lt;&#x2F;a&gt; which is from around the right time period.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;postcode,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;( &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;6371&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; acos( cos( radians(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;18&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;204540500000&lt;&#x2F;span&gt;) ) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                   &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; cos( radians( latitude ) ) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                   &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; cos( radians( longitude ) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                    &lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt; radians(&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;66&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;450958500000&lt;&#x2F;span&gt;) ) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                   &lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;+&lt;&#x2F;span&gt; sin( radians(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;18&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;204540500000&lt;&#x2F;span&gt; ) )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;                   &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; sin( radians( latitude ) ) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;              )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; ) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; distance 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; codepoint
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; distance
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;LIMIT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On our dedicated hardware, with the oh-so-clever RAM disk trick, this query took 0.2 seconds. On RDS, where you are prevented from doing bullshit like that, it took 14 seconds. As it was not even slightly cacheable the traffic brought down the DB and hence the site in pretty short order.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-fix&quot;&gt;The fix&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#the-fix&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We moved it to Elasticsearch, where the same query executed in about 0.4ms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;postscript&quot;&gt;Postscript&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#postscript&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This was probably only the third-worst failure we experienced while I was there.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Evading broken DNS</title>
        <published>2020-12-29T00:00:00+00:00</published>
        <updated>2020-12-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/evading-broken-dns/"/>
        <id>https://mgdm.net/weblog/evading-broken-dns/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/evading-broken-dns/">&lt;p&gt;Once upon a time I had quite a good ISP. They were fairly technically adept, had decent uptime, and would let you use whatever equipment you liked. Unfortunately a couple of years ago they were bought by my current ISP. They’re less friendly, require you to use their own equipment, do not provide a bridge mode on their routers, and finally they do an unfortunate thing where they will redirect any DNS queries I make on my internet connection to their own DNS resolvers. It doesn’t matter if you specify different ones, the resolver that responds is always going to be theirs.&lt;&#x2F;p&gt;
&lt;p&gt;This isn’t great from a privacy point of view; as DNS queries are generally transmitted in the clear, they can use their resolvers to get analytics on who’s doing what. I’ve been thinking about looking into their T&amp;amp;Cs to see what’s going on there but, despite 2020, I haven’t been sufficiently bored enough yet.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re concerned that this might be happening to you, there are ways to test for it. One that’s quite easy to use is the &lt;a href=&quot;https:&#x2F;&#x2F;www.dnsleaktest.com&#x2F;&quot;&gt;DNS leak test&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As I’m using my connection for working from home I haven’t been in a hurry to go and invite the possibility of a couple of days of downtime in a failed switchover.&lt;&#x2F;p&gt;
&lt;p&gt;A couple of days ago everything seemed to be grinding to a halt. It seemed like there was something consuming a lot of bandwidth, but having unplugged everything it became apparent that the ISP’s DNS servers were just failing intermittently. As I write this, it’s been about 48 hours and they’re still doing it. Sadly, because of their cheeky firewall implementation, even if I configure my DHCP server to point DNS elsewhere, it still ends up on the failing resolvers. As is in-vogue these days, the status pages have not been updated to indicate that there’s any fault.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-fixes&quot;&gt;The fixes&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#the-fixes&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;So how can I work around this, if there’s no way to use another DNS service? There are two possibilities.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;browsers-dns-over-https&quot;&gt;Browsers - DNS over HTTPS&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#browsers-dns-over-https&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Modern browsers (I’m using Firefox) have a feature built-in called DNS over HTTPS, or DoH. This routes DNS queries over an HTTPS-based transport, which appear to the ISP as standard HTTPS traffic, so they can’t really do much about it if you force it on in the browser’s settings.&lt;&#x2F;p&gt;
&lt;p&gt;Generally speaking, browsers will default to Cloudflare (1.1.1.1) or Google (8.8.8.8) for their DoH services. There is obviously a question of trust for using either of those, though for me it was better than what was available to me already.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;1.1.1.1&#x2F;dns-over-https&#x2F;web-browser&quot;&gt;Cloudflare’s pages on enabling DoH&lt;&#x2F;a&gt; cover how to do it for desktop browsers.&lt;&#x2F;p&gt;
&lt;p&gt;Apparently DoH has made it into iOS 14 and macOS Big Sur. &lt;a href=&quot;https:&#x2F;&#x2F;paulmillr.com&#x2F;posts&#x2F;encrypted-dns&#x2F;&quot;&gt;Paul Miller has a post on enabling it in iOS&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;everything-else-dns-over-tls&quot;&gt;Everything else - DNS over TLS&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#everything-else-dns-over-tls&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;That covers some web browsers, but it won’t fix the other devices on my network. As well as DNS over HTTPS, there is a specification for DNS over TLS. This, to me at least, feels like the kind of thing that should have been done a while ago. Rather than sending queries over an HTTP-based API, DoT just sends the same traditional DNS queries over a TLS-based encrypted and authenticated connection.&lt;&#x2F;p&gt;
&lt;p&gt;There’s a little bit of a chicken-and-egg thing with DoT. Because it’s TLS, and we want to use the trust features of the protocol, we want to be able to specify a hostname in the connection setup so that we can verify it in the same way as we do for HTTPS. However, we can’t resolve the hostname ourselves, so we need to specify the server’s IP and also the hostname we expect from it.&lt;&#x2F;p&gt;
&lt;p&gt;In practice this turned out to be pretty simple. I used CoreDNS. The configuration to create a new resolver forwarding everything to Cloudflare’s 1.1.1.1 service and caching it looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    . {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;      forward . tls:&#x2F;&#x2F;1.1.1.1 {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;          tls_servername tls.cloudflare-dns.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;      cache
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As I’m running this on NixOS, the changes required to make it work amounted to adding the following to &lt;code&gt;configuration.nix&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  services.coredns.enable = true;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  services.coredns.config = &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    . {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;      forward . tls:&#x2F;&#x2F;1.1.1.1 {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;          tls_servername tls.cloudflare-dns.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;      cache
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  &amp;#39;&amp;#39;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Followed by a quick &lt;code&gt;sudo nixos-rebuild switch&lt;&#x2F;code&gt;. I then had a functioning DNS resolver that could not be intercepted by my ISP, and I could slot its IP into my router’s DHCP options.&lt;&#x2F;p&gt;
&lt;p&gt;This all works great, although I’m probably going to move it onto another device for a more permanent solution. I’ve not yet played with Pi-Hole, and I do expect this could use the same trick.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;NB&lt;&#x2F;strong&gt;: I don’t have a good reference for this, but I’ve seen people mention that lot of IoT devices such as set top boxes do not actually pay any attention to the DNS servers issued to them by DHCP. Some of them just use 8.8.8.8 all the time regardless of what the network is telling them to do. In this particular case with an actively hostile ISP, we couldn’t solve the problem for those devices without a router or similar doing something more clever than I’ve talked about here.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using PostgreSQL in a nix-shell</title>
        <published>2020-06-13T00:00:00+00:00</published>
        <updated>2020-06-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/postgresql-in-a-nix-shell/"/>
        <id>https://mgdm.net/weblog/postgresql-in-a-nix-shell/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/postgresql-in-a-nix-shell/">&lt;p&gt;Sometimes (well, quite often of late, at work) I want to load some data into a PostgreSQL database and do some work with it. I use a Mac at work, and used to do this by installing PostgreSQL using Homebrew and running it system-wide. This stung me a couple of times; Homebrew would upgrade the package to a new minor release (9.5 -&amp;gt; 9.6, etc) and create a new data directory with the version number in it, meaning that a &lt;code&gt;brew upgrade&lt;&#x2F;code&gt; would sometimes make the data I loaded previously inaccessible. I never lost anything through this route, but it did slow me down.&lt;&#x2F;p&gt;
&lt;p&gt;Nowadays, I’ve switched to using Nix for everything I can get away with, which means I can install PostgreSQL as my own user. Using Nix shells, I can even have many of them, one for each different project.&lt;&#x2F;p&gt;
&lt;p&gt;In each directory, I have the simplest &lt;code&gt;shell.nix&lt;&#x2F;code&gt; I can get away with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixpkgs&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;buildInputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;postgresql&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Creating this and then running &lt;code&gt;nix-shell&lt;&#x2F;code&gt; means you’ll end up with a new shell with PostgreSQL available, but not actually running. To make it work, you can do this the first time:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create a database with the data stored in the current directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;initdb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;D&lt;&#x2F;span&gt; .tmp&#x2F;mydb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Start PostgreSQL running as the current user&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; and with the Unix socket in the current directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;pg_ctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;D&lt;&#x2F;span&gt; .tmp&#x2F;mydb&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt; logfile&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;--unix_socket_directories=&amp;#39;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; start&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create a database&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;createdb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mydb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then every other time you re-enter that shell, you can just run the part that starts the database. It will keep running until you reboot, or stop it like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;pg_ctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;D&lt;&#x2F;span&gt; .tmp&#x2F;mydb stop&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using Nix’s tools you can pin PostgreSQL to a particular version if you like, or use a more specific dependency like &lt;code&gt;postgresql_9_6&lt;&#x2F;code&gt; if you need it.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually, I will figure out if I can automate a lot of this with &lt;code&gt;shellHook&lt;&#x2F;code&gt; or similar, but it hasn’t annoyed me enough yet to make me look into doing that.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>CSP logging with nginx</title>
        <published>2020-01-21T00:00:00+00:00</published>
        <updated>2020-01-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/csp-logging-with-nginx/"/>
        <id>https://mgdm.net/weblog/csp-logging-with-nginx/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/csp-logging-with-nginx/">&lt;h2 id=&quot;background&quot;&gt;Background&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#background&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Headers&#x2F;Content-Security-Policy&quot;&gt;Content-Security-Policy HTTP response header&lt;&#x2F;a&gt; has a huge number of ways in which you can limit the kinds of resources that your site is permitted to load. This can defend against XSS attacks and other kinds of content injection. It’s very powerful and, depending on how your site is built, can be fairly simple to implement by adding a header to every response that you send, either in your application or in the web server configuration.&lt;&#x2F;p&gt;
&lt;p&gt;CSP headers can include a directive to report to an API when one of these restrictions has been enforced. Also, if you’re working on implementing CSP, you don’t need to go straight to enforcement–&lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Headers&#x2F;Content-Security-Policy-Report-Only&quot;&gt;the Content-Security-Policy-Report-Only header&lt;&#x2F;a&gt; lets you try out a policy and see what would happen if you deployed it for real. The &lt;code&gt;report-uri&lt;&#x2F;code&gt; or &lt;code&gt;report-to&lt;&#x2F;code&gt; directives allow you to specify where to send reports when a policy has, or would have been, enforced. These are simple JSON payloads sent via an HTTP POST to a URL that you specify.&lt;&#x2F;p&gt;
&lt;p&gt;There’s a migration going on from the original &lt;code&gt;report-uri&lt;&#x2F;code&gt; specification to the new &lt;code&gt;report-to&lt;&#x2F;code&gt; one. In the former, you just specified a URL to POST to along the lines of this, taken from the above Mozilla page:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Content-Security-Policy: default-src https:; report-uri &#x2F;csp-violation-report-endpoint&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However the &lt;code&gt;report-to&lt;&#x2F;code&gt; specification is much more flexible and so a bit more complex to set up. It works in conjunction with the new &lt;code&gt;Report-To&lt;&#x2F;code&gt; header, and so would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Report-To: { &amp;quot;group&amp;quot;: &amp;quot;csp-reports&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;             &amp;quot;max_age&amp;quot;: 10886400,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;             &amp;quot;endpoints&amp;quot;: [
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;               { &amp;quot;url&amp;quot;: &amp;quot;https:&#x2F;&#x2F;example.com&#x2F;reports&amp;quot; },
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;               { &amp;quot;url&amp;quot;: &amp;quot;https:&#x2F;&#x2F;backup.com&#x2F;reports&amp;quot; }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;             ] }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Content-Security-Policy:  default-src https:; report-to csp-reports; report-uri https:&#x2F;&#x2F;example.com&#x2F;reports
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, you can include the older &lt;code&gt;report-uri&lt;&#x2F;code&gt; directive as well, for browsers which only support that. Those that support &lt;code&gt;report-to&lt;&#x2F;code&gt; will ignore &lt;code&gt;report-uri&lt;&#x2F;code&gt; when both are specified.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;logging-csp-reports-via-nginx&quot;&gt;Logging CSP reports via nginx&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#logging-csp-reports-via-nginx&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;While there are a number of third-party services which can be used to log these reports, it’s not all that difficult to log them yourself. With nginx, you can use a custom log format to do so. This looks something like the below. I’m using a Debian-packaged nginx and have listed the files where I’ve placed this configuration.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;conf-d-csp-conf&quot;&gt;conf.d&#x2F;csp.conf&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#conf-d-csp-conf&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;log_format CSP escape=json &amp;#39;{&amp;quot;date&amp;quot;:&amp;quot;$time_local&amp;quot;, &amp;quot;IP address&amp;quot;:&amp;quot;$remote_addr&amp;quot;, &amp;quot;http_x_forwarded_for&amp;quot;:&amp;quot;$http_x_forwarded_for&amp;quot;, &amp;quot;status&amp;quot;:&amp;quot;$status&amp;quot;, &amp;quot;http_user_agent&amp;quot;:&amp;quot;$http_user_agent&amp;quot;, &amp;quot;body_bytes_sent&amp;quot;:&amp;quot;$body_bytes_sent&amp;quot;, &amp;quot;request&amp;quot;:&amp;quot;$request&amp;quot;,&amp;quot;request_body&amp;quot;: &amp;quot;$request_body&amp;quot;}&amp;#39;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;sites-available-default&quot;&gt;sites-available&#x2F;default&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#sites-available-default&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen 443 ssl http2 default_server;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    server_name example.org;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    # More config here
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    add_header Content-Security-Policy-Report-Only &amp;quot;default-src &amp;#39;self&amp;#39;; script-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39; fonts.googleapis.com ssl.google-analytics.com; font-src &amp;#39;self&amp;#39; fonts.gstatic.com; style-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39; fonts.googleapis.com; img-src &amp;#39;self&amp;#39; ssl.google-analytics.com; report-uri https:&#x2F;&#x2F;example.org&#x2F;_csp&amp;quot;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    location = &#x2F;_csp {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            access_log &#x2F;var&#x2F;log&#x2F;nginx&#x2F;csp.log CSP;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            proxy_pass http:&#x2F;&#x2F;127.0.0.1&#x2F;_csp_response;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen 80 default_server;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    server_name example.org;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    # More config here
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    location &#x2F;_csp_response {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            access_log off;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            return 204;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At first glance, the &lt;code&gt;proxy_pass&lt;&#x2F;code&gt; directive may look a bit suspicious. The reason it’s there is because if you just do &lt;code&gt;return 204&lt;&#x2F;code&gt; directly from the &lt;code&gt;&#x2F;_csp&lt;&#x2F;code&gt; location, the request body is not logged in the &lt;code&gt;csp.log&lt;&#x2F;code&gt; file. By using the &lt;code&gt;proxy_pass&lt;&#x2F;code&gt; hack, it is. You may also notice in this example I’m only configuring the older &lt;code&gt;report-uri&lt;&#x2F;code&gt; directive.&lt;&#x2F;p&gt;
&lt;p&gt;Something that would be good to do would be to limit the above requests to only HTTP POSTs, and also ensure that the requests have the correct &lt;code&gt;Content-Type&lt;&#x2F;code&gt; header for the CSP report (which would be &lt;code&gt;application&#x2F;csp-report&lt;&#x2F;code&gt;). I’m not doing that in this case to keep the example clearer, but I’d certainly think about it in production.&lt;&#x2F;p&gt;
&lt;p&gt;The actual reports look like this in the log file. If you’re using an older nginx, before &lt;code&gt;1.11.8&lt;&#x2F;code&gt;, it may not support the &lt;code&gt;escape=json&lt;&#x2F;code&gt; part of the log format and you may see all of the &lt;code&gt;&quot;&lt;&#x2F;code&gt; characters in your log being replaced with &lt;code&gt;\x22&lt;&#x2F;code&gt;. You’ll probably want to upgrade to fix that, not least because that version is quite old!&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;{&amp;quot;date&amp;quot;:&amp;quot;21&#x2F;Jan&#x2F;2020:21:58:46 +0000&amp;quot;, &amp;quot;IP address&amp;quot;:&amp;quot;198.51.100.4&amp;quot;, &amp;quot;http_x_forwarded_for&amp;quot;:&amp;quot;&amp;quot;, &amp;quot;status&amp;quot;:&amp;quot;204&amp;quot;, &amp;quot;http_user_agent&amp;quot;:&amp;quot;Mozilla&#x2F;5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit&#x2F;537.36 (KHTML, like Gecko) Chrome&#x2F;79.0.3945.117 Safari&#x2F;537.36&amp;quot;, &amp;quot;body_bytes_sent&amp;quot;:&amp;quot;0&amp;quot;, &amp;quot;request&amp;quot;:&amp;quot;POST &#x2F;_csp HTTP&#x2F;2.0&amp;quot;,&amp;quot;request-body&amp;quot;: {\&amp;quot;csp-report\&amp;quot;:{\&amp;quot;document-uri\&amp;quot;:\&amp;quot;https:&#x2F;&#x2F;example.org&#x2F;\&amp;quot;,\&amp;quot;referrer\&amp;quot;:\&amp;quot;\&amp;quot;,\&amp;quot;violated-directive\&amp;quot;:\&amp;quot;font-src\&amp;quot;,\&amp;quot;effective-directive\&amp;quot;:\&amp;quot;font-src\&amp;quot;,\&amp;quot;original-policy\&amp;quot;:\&amp;quot;default-src &amp;#39;self&amp;#39;; script-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39; fonts.googleapis.com ssl.google-analytics.com gist.github.com; font-src &amp;#39;self&amp;#39; fonts.gstatic.com; style-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39; fonts.googleapis.com github.githubassets.com; img-src &amp;#39;self&amp;#39; ssl.google-analytics.com; report-uri https:&#x2F;&#x2F;example.org&#x2F;_csp\&amp;quot;,\&amp;quot;disposition\&amp;quot;:\&amp;quot;report\&amp;quot;,\&amp;quot;blocked-uri\&amp;quot;:\&amp;quot;\&amp;quot;,\&amp;quot;line-number\&amp;quot;:366,\&amp;quot;column-number\&amp;quot;:179,\&amp;quot;source-file\&amp;quot;:\&amp;quot;https:&#x2F;&#x2F;example.org&#x2F;assets&#x2F;js&#x2F;modernizr.js\&amp;quot;,\&amp;quot;status-code\&amp;quot;:0,\&amp;quot;script-sample\&amp;quot;:\&amp;quot;\&amp;quot;}}}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From here you can use tools like &lt;code&gt;jq&lt;&#x2F;code&gt; to inspect what you find. You’ll note that the actual report is recorded in the &lt;code&gt;request_body&lt;&#x2F;code&gt; property in the JSON, and that this contents is escaped. You can recover this like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ cat &#x2F;var&#x2F;log&#x2F;nginx&#x2F;csp.log | jq -r &amp;#39;.request_body | fromjson&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  &amp;quot;csp-report&amp;quot;: {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;document-uri&amp;quot;: &amp;quot;https:&#x2F;&#x2F;example.org&#x2F;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;referrer&amp;quot;: &amp;quot;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;violated-directive&amp;quot;: &amp;quot;font-src&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;effective-directive&amp;quot;: &amp;quot;font-src&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;original-policy&amp;quot;: &amp;quot;default-src &amp;#39;self&amp;#39;; script-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39; fonts.googleapis.com ssl.google-analytics.com gist.github.com; font-src &amp;#39;self&amp;#39; fonts.gstatic.com; style-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39; fonts.googleapis.com github.githubassets.com; img-src &amp;#39;self&amp;#39; ssl.google-analytics.com; report-uri https:&#x2F;&#x2F;example.org&#x2F;_csp&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;disposition&amp;quot;: &amp;quot;report&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;blocked-uri&amp;quot;: &amp;quot;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;line-number&amp;quot;: 366,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;column-number&amp;quot;: 179,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;source-file&amp;quot;: &amp;quot;https:&#x2F;&#x2F;example.org&#x2F;assets&#x2F;js&#x2F;modernizr.js&amp;quot;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;status-code&amp;quot;: 0,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;script-sample&amp;quot;: &amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From this I can tell that Chrome is not entirely happy with how Modernizr is doing some feature detection around web fonts. I’ll need to look into that, but that is for another day. Later work could also include implementing the other parts of the &lt;code&gt;report-to&lt;&#x2F;code&gt; spec, which include neat things like &lt;a href=&quot;https:&#x2F;&#x2F;scotthelme.co.uk&#x2F;network-error-logging-deep-dive&#x2F;&quot;&gt;network error logging, as explained here by Scott Helme&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;NB:&lt;&#x2F;strong&gt; You will almost certainly want to add the &lt;code&gt;csp.log&lt;&#x2F;code&gt; file to your &lt;code&gt;logrotate&lt;&#x2F;code&gt; configuration, or something similar, otherwise you may end up with a chunky file eating a lot of disk space if your site doesn’t quite comply with your policy!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Developing with Flask on NixOS</title>
        <published>2019-08-22T00:00:00+00:00</published>
        <updated>2019-08-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/flask-on-nixos/"/>
        <id>https://mgdm.net/weblog/flask-on-nixos/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/flask-on-nixos/">&lt;p&gt;I recently acquired a second hand ThinkPad to run NixOS on, and I’ve been using it recently to mess around with a couple of small web projects. I’m prototyping one of these in Flask, and have been using NixOS’s own Flask package in order to do so.&lt;&#x2F;p&gt;
&lt;p&gt;I found that I could quite happily do &lt;code&gt;flask run&lt;&#x2F;code&gt;, but as soon as I tried to enable development mode, I’d end up with an error like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ FLASK_APP=myapp FLASK_ENV=development flask run
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; * Serving Flask app &amp;quot;myapp&amp;quot; (lazy loading)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; * Environment: development
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; * Debug mode: on
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; * Running on http:&#x2F;&#x2F;127.0.0.1:5000&#x2F; (Press CTRL+C to quit)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; * Restarting with stat
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  File &amp;quot;&#x2F;nix&#x2F;store&#x2F;dpdfxfjf6azdgnka78fhsch3a8y3d46g-python3.7-Flask-1.0.2&#x2F;bin&#x2F;flask&amp;quot;, line 2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    export PATH=&amp;#39;&#x2F;nix&#x2F;store&#x2F;96p42644i76jqgdkxjgyl3f0c8n8k16j-python3-3.7.4&#x2F;bin:&#x2F;nix&#x2F;store&#x2F;dpdfxfjf6azdgnka78fhsch3a8y3d46g-python3.7-Flask-1.0.2&#x2F;bin:&#x2F;nix&#x2F;store&#x2F;dvzig77cx97rdxn5i2pdmyblm8f6pf7d-python3.7-setuptools-40.8.0&#x2F;bin&amp;#39;${PATH:+&amp;#39;:&amp;#39;}$PATH
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;              ^
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SyntaxError: invalid syntax
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This looks a bit like something is attempting to run a Bash script through the Python interpreter. I didn’t understand why this was happening until I encountered &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;issues&#x2F;42924&quot;&gt;this issue on Nix’s github&lt;&#x2F;a&gt; which suggests that it ought to be fixed upstream, but that it might be possible to override it in Nix. The code given there to do so didn’t neatly copy and paste into &lt;code&gt;shell.nix&lt;&#x2F;code&gt; as I had hoped, but after some tinkering I got it to work. Here’s what I ended up with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;with&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-nix&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-spath z-nix&quot;&gt;&amp;lt;nixpkgs&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;let&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;myWerkzeug&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;python37Packages&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;werkzeug&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;overrideAttrs&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-4 z-nix&quot;&gt;oldAttrs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-function z-nix&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;rec&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;postPatch&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-other z-start z-nix&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;    substituteInPlace werkzeug&#x2F;_reloader.py \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;      --replace &amp;quot;rv = [sys.executable]&amp;quot; &amp;quot;return sys.argv&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-string z-quoted z-other z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-string z-other z-end z-nix&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;doCheck&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-nix&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;myFlask&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;python37Packages&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;flask&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-nix&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;override&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;werkzeug&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;myWerkzeug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-expression z-nix&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-keyword z-other z-nix&quot;&gt;in&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;mkShell&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;buildInputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;python37&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-name z-nix&quot;&gt;myFlask&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-list z-nix&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Probably not hard to anyone who properly understands Nix, but I learned a couple of things doing it. Hopefully someone else will find this useful.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>htmlq: Like jq, but for HTML</title>
        <published>2019-05-20T00:00:00+00:00</published>
        <updated>2019-05-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/htmlq/"/>
        <id>https://mgdm.net/weblog/htmlq/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/htmlq/">&lt;p&gt;Continuing my journey into learning Rust, I have been looking around for small, useful projects that might be interesting to build rather than doing exercises. In the mean time I was doing some web scraping using Python and BeautifulSoup, which is great but it can be a little slow. I am aware of Servo, the browser written by Mozilla in Rust, and had the idea to try and recycle parts of it to make a small CLI tool to extract data from HTML documents.&lt;&#x2F;p&gt;
&lt;p&gt;The obvious choice for me for the query language was CSS selectors. While XPath works fine for XML, the more specific selector language seems like a better fit for what I wanted to do here. I intended for the CLI to be fairly simple, and fast.&lt;&#x2F;p&gt;
&lt;p&gt;Servo’s HTML rendering library is called &lt;code&gt;html5ever&lt;&#x2F;code&gt;. I initially looked at using this directly, and integrating with the CSS selector parsing engine, but it turns out that someone else has done most of the work I needed here and wrapped both in a library called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kuchiki-rs&#x2F;kuchiki&quot;&gt;Kuchiki&lt;&#x2F;a&gt;. Most of the hard work is actually done in here. Parsing the HTML document becomes as simple as something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;let document = kuchiki::parse_html()
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    .from_utf8()
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    .read_from(&amp;amp;mut input)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    .unwrap();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m very grateful to Kuchiki’s authors for doing most of the hard work!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#examples&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;For example, if I wanted to get the HTML for the section with ID &lt;code&gt;posts&lt;&#x2F;code&gt; on this blog, I could do:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;curl -s https:&#x2F;&#x2F;mgdm.net | htmlq &amp;#39;#posts&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or to find all the links inside &lt;code&gt;&amp;lt;a&amp;gt;&lt;&#x2F;code&gt; elements on a page:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;curl -s https:&#x2F;&#x2F;www.rust-lang.org&#x2F; | htmlq -a href a
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;-a&lt;&#x2F;code&gt; option takes the name of an attribute to return, and the final &lt;code&gt;a&lt;&#x2F;code&gt; is the CSS selector. Elements that do not have the matching attribute are ignored.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;-t&lt;&#x2F;code&gt; option allows you to just return the text content, ignoring the rest of the markup. There’s also a &lt;code&gt;-p&lt;&#x2F;code&gt; which attempts to pretty-print the HTML, but this is a bit of a work in progress.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;htmlq&quot;&gt;It’s now on crates.io&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;htmlq&quot;&gt;the code is on GitHub&lt;&#x2F;a&gt;. You should be able to install it on Unix-like systems with &lt;code&gt;cargo install htmlq&lt;&#x2F;code&gt;. I’d be happy to hear any feedback people may have, and I hope that it might be useful.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Debugging network connections on macOS with nettop</title>
        <published>2019-04-29T00:00:00+00:00</published>
        <updated>2019-04-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/nettop/"/>
        <id>https://mgdm.net/weblog/nettop/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/nettop/">&lt;p&gt;Recently I’ve been learning Rust, and by far the simplest way to install that is to use &lt;a href=&quot;https:&#x2F;&#x2F;rustup.rs&#x2F;&quot;&gt;Rustup&lt;&#x2F;a&gt;. That works really well on my home computer, but I wanted to try solving a problem I had at work using Rust, so I tried it on my work Mac. My company’s network has a fairly restrictive set of firewalls, and I found that rustup was somehow failing to connect to the network to download the indexes it needs. The verbose output didn’t give me any clues, and I found it hard to narrow down what it was trying to do using &lt;code&gt;tcpdump&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After some searching, I came across &lt;code&gt;nettop&lt;&#x2F;code&gt;. It seems to a tool originating from BSD that is mostly used for monitoring network activity across the system, but it’s also possible to narrow it down to a single process:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo nettop -p rustup -L 0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This shows all the network connections being made processes called &lt;code&gt;rustup&lt;&#x2F;code&gt;, in this sort of format:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;21:40:52.233621,tcp4 192.168.33.10:50963&amp;lt;-&amp;gt;server-99-84-8-62.lhr62.r.cloudfront.net:443,utun1,SynSent,0,0,0,0,0,0.00 ms,131072,0,BE,-,cubic,-,-,-,-,
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This indicates that &lt;code&gt;rustup&lt;&#x2F;code&gt; is trying to connect to port 443 on a server in Cloudfront.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-rustup-issue&quot;&gt;The rustup issue&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#the-rustup-issue&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In this case, it turns out that for some reason it was trying to connect to our corporate web proxy on port 8080 instead of port 80. The proxy is set in my environment as &lt;code&gt;http:&#x2F;&#x2F;corporate-proxy.example.org:80&lt;&#x2F;code&gt;. I tweeted about this, and &lt;a href=&quot;https:&#x2F;&#x2F;blog.digital-scurf.org&#x2F;&quot;&gt;Daniel Silverstone&lt;&#x2F;a&gt; found that there was an edge case in the &lt;code&gt;url&lt;&#x2F;code&gt; crate used by the &lt;code&gt;env_proxy&lt;&#x2F;code&gt; crate, in turn used by Rustup to parse the &lt;code&gt;https_proxy&lt;&#x2F;code&gt; environment variable–it would omit the port 80 as that is the default for HTTP, and then &lt;code&gt;env_proxy&lt;&#x2F;code&gt; would assume that because the port had been omitted it should try 8080. This should be fixed shortly! Thanks again to Daniel for the help.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Installing NixOS</title>
        <published>2019-01-05T00:00:00+00:00</published>
        <updated>2019-01-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/installing-nixos/"/>
        <id>https://mgdm.net/weblog/installing-nixos/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/installing-nixos/">&lt;p&gt;It’s been a while since I’ve had a machine running Linux, and even longer since I’ve had actual desktop hardware. Recently my brother upgraded his gaming PC, and I acquired the old motherboard, CPU, RAM and graphics card. It’s a couple of years old but definitely quick enough for my purposes.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to install NixOS on it to give it a proper go. I’d tried Nix on my work OSX laptop for a while, but a lot of tools at work assume you’re using Homebrew so I had to revert back to that. &lt;a href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;releases&#x2F;nix&#x2F;nix-1.9&#x2F;manual&#x2F;#chap-installation&quot;&gt;The manual&lt;&#x2F;a&gt; is pretty informative, but as I wanted to run with full disk encryption I used &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;grhmc&quot;&gt;Graham Christensen&lt;&#x2F;a&gt;’s &lt;a href=&quot;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;nixos-on-dell-9560&quot;&gt;instructions for installing on a Dell machine&lt;&#x2F;a&gt; as the base. All that I had to change were the references to the drive names, as my SATA SSD appeared as &lt;code&gt;&#x2F;dev&#x2F;sda&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;things-to-look-out-for&quot;&gt;Things to look out for&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#things-to-look-out-for&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;uefi-vs-bios&quot;&gt;UEFI vs BIOS&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#uefi-vs-bios&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The installation was relatively straightforward following Graham’s instructions, but when I got to the point where it was going to install Grub, it came up with errors like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;nix&#x2F;store&#x2F;6czhmdkzs04y1bdlq53yvw6hn1bvl1zr-grub-2.x-2015-07-27&#x2F;sbin&#x2F;grub-install: warning: this GPT partition label contains no BIOS Boot Partition; embedding won&amp;#39;t be possible.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;nix&#x2F;store&#x2F;6czhmdkzs04y1bdlq53yvw6hn1bvl1zr-grub-2.x-2015-07-27&#x2F;sbin&#x2F;grub-install: warning: Embedding is not possible.  GRUB can only be installed in this setup by using blocklists.  However, blocklists are UNRELIABLE and their use is discouraged..
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;nix&#x2F;store&#x2F;6czhmdkzs04y1bdlq53yvw6hn1bvl1zr-grub-2.x-2015-07-27&#x2F;sbin&#x2F;grub-install: error: will not proceed with blocklists.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;nix&#x2F;store&#x2F;w345fzhsr2ckzhazmxr3lc906glnxqiy-install-grub.pl: installation of GRUB on &#x2F;dev&#x2F;sda failed
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(These are not the precise errors I got as the paths are different, but they’re the same messages). I had partitioned the SSD with a GPT, as I knew the machine had UEFI, but it turned out that for some reason the installer had opted to boot in BIOS mode. Some messing around in the firmware followed, until I scrolled and found the option to disable the “Compatibility Support Module”, or CSM. Rebooting with that switched off made the installer boot in UEFI mode, which was evident by it having a very much smaller font. I copied the existing &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt; and &lt;code&gt;configuration.nix&lt;&#x2F;code&gt; files and re-ran &lt;code&gt;nixos-generate-config&lt;&#x2F;code&gt;, then put back the &lt;code&gt;boot.initrd.luks.devices&lt;&#x2F;code&gt; section and finally ran &lt;code&gt;nixos-install&lt;&#x2F;code&gt; again.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;usb-keyboards&quot;&gt;USB keyboards&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#usb-keyboards&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I rebooted, and got to the prompt that asked for the passphrase to unlock the disks. I found out quite quickly that the kernel didn’t know what to do with my USB keyboard. I rebooted back into the installer, mounted the disks, and added &lt;code&gt;hid_microsoft&lt;&#x2F;code&gt; to the list in &lt;code&gt;boot.initrd.availableKernelModules&lt;&#x2F;code&gt; and re-ran &lt;code&gt;nixos-install&lt;&#x2F;code&gt;. Rebooting then got me a keyboard. I do have a Microsoft keyboard attached to this machine–I suspect I could have got away with the &lt;code&gt;usbhid&lt;&#x2F;code&gt; module, but this one seemed to make sense.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fun-with-uuids&quot;&gt;Fun with UUIDs&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#fun-with-uuids&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Make absolutely certain that the UUIDs you use for the various drives are correct&lt;&#x2F;strong&gt;. I got quite mixed up here, as when I wrote the &lt;code&gt;boot.initrd.luks.devices&lt;&#x2F;code&gt; section in &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt; I was using the UUIDs for the mapped devices (&lt;code&gt;dm-1&lt;&#x2F;code&gt; and &lt;code&gt;dm-2&lt;&#x2F;code&gt;) which appear after the disks have been unlocked. If you look at &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt; and find the UUIDs in &lt;code&gt;fileSystems.&quot;&#x2F;&quot;&lt;&#x2F;code&gt; or &lt;code&gt;swapDevices&lt;&#x2F;code&gt; are the same as those in your LUKS devices config, then you’ve got the LUKS config wrong, and will want to have a look carefully at the output of &lt;code&gt;ls -l &#x2F;dev&#x2F;disks&#x2F;by-uuid&#x2F;&lt;&#x2F;code&gt; to find the ones that reference actual physical disk partitions like in my case &lt;code&gt;&#x2F;dev&#x2F;sda3&lt;&#x2F;code&gt;, and not mapped devices like &lt;code&gt;dm-1&lt;&#x2F;code&gt; or something under &lt;code&gt;&#x2F;dev&#x2F;mapper&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Fixing this, and one more &lt;code&gt;nixos-install&lt;&#x2F;code&gt;, got me to reboot into a working machine.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>MFFI: A new foreign function interface for PHP</title>
        <published>2015-06-25T00:00:00+00:00</published>
        <updated>2015-06-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/mffi/"/>
        <id>https://mgdm.net/weblog/mffi/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/mffi/">&lt;p&gt;In PHP, if you want to make use of a library written in C, you generally have to go and write a new PHP extension. This isn’t that hard if you’ve done it before, but it does require a bit of work and some getting used to. There’s also a fair bit of boilerplate code that is required to create functions, classes, and methods, and to handle parameter parsing. The documentation for this side of things isn’t that great right now, though there are &lt;a href=&quot;http:&#x2F;&#x2F;www.phpinternalsbook.com&#x2F;&quot;&gt;efforts to change this&lt;&#x2F;a&gt;. One advantage is that there are quite a number of people who have done it before, and you can use tools like &lt;a href=&quot;http:&#x2F;&#x2F;lxr.php.net&quot;&gt;PHP’s OpenGrok&lt;&#x2F;a&gt; to find examples and inspiration.&lt;&#x2F;p&gt;
&lt;p&gt;It would be nice to make this sort of thing simpler to do. Perhaps, we could avoid having to write any C code.  As I mentioned in &lt;a href=&quot;http:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;php-at-the-speed-of-c&#x2F;&quot;&gt;my previous post&lt;&#x2F;a&gt;, there are other tools in the works to make accelerating code written in PHP faster. I mentioned Anthony Ferrara’s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;recki-ct&quot;&gt;Recki-CT&lt;&#x2F;a&gt;, which takes PHP code and accelerates that. There is also the &lt;a href=&quot;http:&#x2F;&#x2F;zephir-lang.com&#x2F;&quot;&gt;Zephir project&lt;&#x2F;a&gt; which takes code written in a PHP-like language and can create extensions for you from that.&lt;&#x2F;p&gt;
&lt;p&gt;Both of these require a bit of time to set up and operate, though. They’re also not really aimed at using existing libraries – their goal is to accelerate self-contained high-level code rather than to provide access to lower-level libraries.&lt;&#x2F;p&gt;
&lt;p&gt;Some languages have a feature that allows the user to load C shared libraries and call functions from them in the same way you’d call any other function in that language. These are known as &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Foreign_function_interface&quot;&gt;&lt;em&gt;foreign function interfaces&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;. Python has a number of these – &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;2&#x2F;library&#x2F;ctypes.html&quot;&gt;ctypes&lt;&#x2F;a&gt; is one example, and &lt;a href=&quot;https:&#x2F;&#x2F;cffi.readthedocs.org&#x2F;en&#x2F;latest&#x2F;&quot;&gt;CFFI&lt;&#x2F;a&gt; is another. Similarly, Ruby has the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ffi&#x2F;ffi&quot;&gt;FFI&lt;&#x2F;a&gt; library. Many other languages possess these. There has been one for PHP for a while, called &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;ffi&quot;&gt;ext&#x2F;ffi&lt;&#x2F;a&gt;, but it hasn’t had a release in a number of years.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mffi&quot;&gt;MFFI&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#mffi&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I decided it sounded like an interesting project, so I would like to present to the world &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;MFFI&quot;&gt;MFFI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It’s an attempt at making a new, intuitive, FFI for PHP. Rather than take the approach of attempting to parse C headers, like &lt;code&gt;ext&#x2F;ffi&lt;&#x2F;code&gt; and Python’s CFFI do, it uses PHP to declare the types. This is easiest to show in an example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&amp;lt;?php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$library = new MFFI\Library();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$puts = $library-&amp;gt;bind(&amp;#39;puts&amp;#39;, [ MFFI\Type::TYPE_STRING ], MFFI\Type::TYPE_INT);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$puts(&amp;#39;Hello world&amp;#39;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code above binds to the PHP process itself, meaning that any functions available within the process can be called. It then creates a new &lt;code&gt;MFFI\Func&lt;&#x2F;code&gt; object to represent &lt;code&gt;libc&lt;&#x2F;code&gt;’s &lt;code&gt;puts&lt;&#x2F;code&gt; function. The second parameter to &lt;code&gt;MFFI\Library::bind()&lt;&#x2F;code&gt; is an array representing the types of the arguments (in this case just one, a string), and the final argument is the return type (an int in this case). Finally, it calls the function with a standard PHP string. Running this code does what you’d expect:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;michael@morbo:mffi% php7 test.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Hello world
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;michael@morbo:mffi%
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s a fairly new extension, so currently it doesn’t have that many features. One thing it can do at the moment is handle custom C structs. You can see this in the code below.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-php&quot;&gt;&amp;lt;?php&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-use z-php&quot;&gt;&lt;span class=&quot;z-keyword z-other z-use z-php&quot;&gt;use&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-use z-php&quot;&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-other z-namespace z-php&quot;&gt;MFFI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-namespace z-php&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-use z-php&quot;&gt;&lt;span class=&quot;z-keyword z-other z-use z-php&quot;&gt;use&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-use z-php&quot;&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-other z-namespace z-php&quot;&gt;MFFI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-namespace z-php&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Struct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-use z-php&quot;&gt;&lt;span class=&quot;z-keyword z-other z-use z-php&quot;&gt;use&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-use z-php&quot;&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-other z-namespace z-php&quot;&gt;MFFI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-namespace z-php&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-php&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-php&quot;&gt;TimeStruct&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-extends z-php&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-php&quot;&gt;Struct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-php&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-php&quot;&gt;static&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-php&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-php&quot;&gt;definition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt; &lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-php&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-php&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-array z-begin z-php&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_sec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,     &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; seconds (0 - 60) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_min&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,     &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; minutes (0 - 59) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_hour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,    &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; hours (0 - 23) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_mday&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,    &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; day of month (1 - 31) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_mon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,     &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; month of year (0 - 11) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_year&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,    &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; year - 1900 &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_wday&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,    &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; day of week (Sunday = 0) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_yday&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,    &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; day of year (0 - 365) &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_isdst&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_INT&lt;&#x2F;span&gt;,   &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; is summer time in effect? &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;tm_zone&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-key z-php&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_STRING&lt;&#x2F;span&gt;,  &lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; abbreviation of timezone name &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-array z-php&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-array z-end z-php&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-php&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-class z-php&quot;&gt;&lt;span class=&quot;z-meta z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-php&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;TimeStruct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_sec&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_min&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_hour&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_mday&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_mon&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_year&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;115&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-php&quot;&gt;tm_zone&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;BST&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;lib&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;asctime&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;asctime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-array z-begin z-php&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;TimeStruct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-class z-php&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-array z-end z-php&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_STRING&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-support z-function z-var z-php&quot;&gt;var_dump&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-invoke z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;asctime&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;tm&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We create a class called &lt;code&gt;TimeStruct&lt;&#x2F;code&gt; that extends &lt;code&gt;MFFI\Struct&lt;&#x2F;code&gt;. This has no methods other than a static one called &lt;code&gt;definition()&lt;&#x2F;code&gt;. This is called the first time one of these classes is instantiated, and returns an array containing the member names and their types. We then create one of these, and set the various parameters to a date. Finally, we bind to &lt;code&gt;libc&lt;&#x2F;code&gt;’s &lt;code&gt;asctime&lt;&#x2F;code&gt; function, which converts the time struct into an ASCII string. This looks like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;michael@morbo:mffi% php7 test2.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;string(25) &amp;quot;Sun Apr  5 15:30:00 2015
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;michael@morbo:mffi%
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It gets a spare trailing newline, but it looks pretty good on the whole.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;binding-to-your-own-libraries&quot;&gt;Binding to your own libraries&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#binding-to-your-own-libraries&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;You can also write your own libraries and use those. Here’s a bit of C code that provides a function that reverses strings. It’s trivial, and PHP already provides this, but it’s just an example. The &lt;code&gt;strrev&lt;&#x2F;code&gt; function in the code accepts a string (as a &lt;code&gt;char *&lt;&#x2F;code&gt;), and returns another string (again a &lt;code&gt;char *&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Taken from http:&#x2F;&#x2F;www8.cs.umu.se&#x2F;~isak&#x2F;snippets&#x2F;strrev.c &lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;string.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;strrev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p1&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p2&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;!&lt;&#x2F;span&gt; str &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;!&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;str&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; str&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;p1 &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; str&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; p2 &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; str &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;strlen&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;str&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt; p2 &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; p1&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;++&lt;&#x2F;span&gt;p1&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;--&lt;&#x2F;span&gt;p2&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p1 &lt;span class=&quot;z-keyword z-operator z-assignment z-augmented z-c&quot;&gt;^=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p2&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p2 &lt;span class=&quot;z-keyword z-operator z-assignment z-augmented z-c&quot;&gt;^=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p1&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p1 &lt;span class=&quot;z-keyword z-operator z-assignment z-augmented z-c&quot;&gt;^=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;p2&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; str&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Save this as &lt;code&gt;rev.c&lt;&#x2F;code&gt;, and compile using a command like &lt;code&gt;gcc -o rev.so -g -fPIC -shared rev.c&lt;&#x2F;code&gt;. You can then use the following PHP code to access the function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-php&quot;&gt;&amp;lt;?php&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;library&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-other z-namespace z-php&quot;&gt;MFFI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-namespace z-php&quot;&gt;\&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;rev.so&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;strrev&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;library&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;strrev&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-array z-begin z-php&quot;&gt;[&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-other z-namespace z-php&quot;&gt;MFFI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-namespace z-php&quot;&gt;\&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_STRING&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-array z-end z-php&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-other z-namespace z-php&quot;&gt;MFFI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-namespace z-php&quot;&gt;\&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;Type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;TYPE_STRING&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-support z-function z-construct z-php&quot;&gt;echo&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-invoke z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;strrev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-single z-php&quot;&gt;Hello world&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The result seems to make sense:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;michael@morbo:mffi% php7 test3.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dlrow olleH
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;michael@morbo:mffi%
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;a-word-of-warning&quot;&gt;A word of warning&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#a-word-of-warning&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This is probably a very, very bad idea. The potential for security problems is monumental. If you get a definition even slightly wrong, you’ll either crash PHP straight away, which is probably the best result, or corrupt some memory somewhere and have unseen and weird effects. I would never advise anyone to use it unless it was a one-shot script or something running in a very controlled, non-public facing environment. If you use this, and it breaks, you get to keep all the bits!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plans&quot;&gt;Plans&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#plans&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This extension is only for PHP 7. It doesn’t work on PHP 5, and I don’t intend to change that. There’s a fairly big TODO list of features I want to add. I want to make it possible to define structs that contain other structs, which is a work in progress, and then handle large arrays of scalar types. This would make it possible to solve the Mandelbrot problem from the previous post fairly efficiently using a small C library that did the maths, without knowing anything about how to write PHP extensions.&lt;&#x2F;p&gt;
&lt;p&gt;I have not done any benchmarking yet. The translation through libffi will have a cost, but I have not yet worked out what that will be.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PHP at the speed of C</title>
        <published>2015-02-23T00:00:00+00:00</published>
        <updated>2015-02-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/php-at-the-speed-of-c/"/>
        <id>https://mgdm.net/weblog/php-at-the-speed-of-c/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/php-at-the-speed-of-c/">&lt;p&gt;For common cases, most dynamic languages are “fast enough”. For most PHP applications, the most overhead is probably hitting network services like the database, and this accounts for far more of the run time than the speed of the language’s function calls. Also, PHP is a fairly thin glue layer on top of a lot of C libraries, which mean that for any significant algorithmic work, you’re probably already calling out to a C library underneath. If this wasn’t the case, basic operations like string searches and regular expressions would be extremely slow.&lt;&#x2F;p&gt;
&lt;p&gt;However, every now and again you do want to do something with PHP that does involve complex algorithms, for which you might not have a C library to hand. Even if you do have a C library or the ability to create one, writing extensions for PHP to expose this functionality has a bit of a learning curve. Wouldn’t it be nice if we could write code in PHP, and have it accelerated somehow to C-like speeds?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-mandelbrot-set&quot;&gt;The Mandelbrot set&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#the-mandelbrot-set&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Mandelbrot_set&quot;&gt;The Mandelbrot set&lt;&#x2F;a&gt; is a set of complex numbers generated using an algorithm that involves a large number of iterations. When plotted with an appropriate colouring scheme, they make fractals which can look very nice. Plotting them is relatively simple, though it’s quite CPU intensive. I have written some fairly naïve code to generate these images, which you can find &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;39e62755c586dc0c8907#file-mandelbrot-php&quot;&gt;in this gist&lt;&#x2F;a&gt;. The output looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;img&#x2F;posts&#x2F;mandel.png&quot; alt=&quot;Mandelbrot set&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There’s a fair bit of code there, but the function that takes most of the time is the &lt;code&gt;mandelbrot()&lt;&#x2F;code&gt; one. It’s where all the iteration happens. On the VM I’m testing this in&lt;sup&gt;&lt;a name=&quot;fn1&quot; href=&quot;#vm&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; it takes around 80 seconds to run, under a release build of PHP 5.6.5:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src$ php colourmandel.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Data took 78.744249
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Render took 0.631219
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That’s pretty slow, by any metric. It’s iterating up to 4096 times for every pixel in an 800x512 image, so unlike most PHP apps it’s going to be CPU-bound rather than dependent on the network or other services. I wonder if there’s a way to speed it up, without having to drop down to pure C?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hhvm&quot;&gt;HHVM&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#hhvm&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Well, one way is to install HHVM:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src$ hhvm mandelbrot.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Data took 5.852351
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Render took 0.236238
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;HHVM, in its default setup, features a Just-In-Time (JIT) compiler, that traces every code path that is executed. If it finds a path that is “hot” – executed a large number of times – it will jump in and compile that code branch down to straight machine code and execute that instead. As this code is essentially arithmetic taking place in a tight loop, it’s a perfect case for HHVM’s JIT compiler to jump in and optimize.&lt;&#x2F;p&gt;
&lt;p&gt;If you’ve got complete control over your infrastructure and don’t mind changing PHP implementations, HHVM could well be the way to go. It also has a number of other extras which may be of interest. But what if you don’t?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;recki-compiler-toolkit&quot;&gt;Recki Compiler Toolkit&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#recki-compiler-toolkit&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Recently, Anthony Ferrara (known throughout the Internet and beyond as &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ircmaxell&quot;&gt;@ircmaxell&lt;&#x2F;a&gt;) and Joe Watkins (similarly well-known as &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;krakjoe&quot;&gt;@krakjoe&lt;&#x2F;a&gt;) have been working on a new set of toys for solving this problem while staying on the “standard” PHP runtime. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;recki-ct&quot;&gt;Recki-CT&lt;&#x2F;a&gt; is a set of tools that implement a PHP compiler, in PHP. While this might you think of things like &lt;a href=&quot;http:&#x2F;&#x2F;pypy.org&quot;&gt;PyPy&lt;&#x2F;a&gt;, which implements a Python virtual machine in Python, this is not Recki’s goal – it doesn’t provide a VM, so it can’t run PHP by itself. However, it can parse PHP code and generate other code from it.&lt;&#x2F;p&gt;
&lt;p&gt;Recki uses the well-known &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nikic&#x2F;PHP-Parser&quot;&gt;PHP-Parser library&lt;&#x2F;a&gt; by &lt;a href=&quot;http:&#x2F;&#x2F;nikic.github.io&#x2F;&quot;&gt;Nikita Popov&lt;&#x2F;a&gt; to generate a graph-based representation of the code, and convert it to an &lt;em&gt;intermediate representation&lt;&#x2F;em&gt;. To get here involves a few steps, which are described in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;recki-ct&#x2F;blob&#x2F;master&#x2F;doc&#x2F;2_basic_operation.md&quot;&gt;Recki’s documentation&lt;&#x2F;a&gt;, but essentially:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It generates a tree-based representation of the code called an &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Abstract_syntax_tree&quot;&gt;abstract syntax tree&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;From the AST, it generates a &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Control_flow_graph&quot;&gt;control flow graph&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;It then converts this graph into &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Static_single_assignment_form&quot;&gt;static single assignment form&lt;&#x2F;a&gt;, where every variable is only assigned once, and all are defined before use. This makes it simpler to optimize.&lt;&#x2F;li&gt;
&lt;li&gt;Next, it repeatedly runs optimizations on this graph&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This intermediate form is pretty low-level, and it is comparatively simple to generate code from it for a variety of targets. One of the targets Recki can use  is a second component, JitFu, which is a PHP extension allowing us to generate machine code at run time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;first-steps-with-recki-and-jitfu&quot;&gt;First steps with Recki and JitFu&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#first-steps-with-recki-and-jitfu&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;So, I’ve decided I’m not yet ready to throw out all my existing infrastructure, and that (perhaps) I’m tied to some extensions that currently only work on main-line PHP.  Where do I start?&lt;&#x2F;p&gt;
&lt;p&gt;First off, I need to follow the instructions on Recki’s README, which include installing &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;libjit&#x2F;&quot;&gt;libjit&lt;&#x2F;a&gt; and the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;krakjoe&#x2F;jitfu&quot;&gt;JitFu extension&lt;&#x2F;a&gt;. Then, we need to install Recki using Composer, and then add Composer’s autoloader to the top of the PHP file as normal. Once we have these in place, we can start to look at how to use JitFu to speed our code up.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;composer require recki-ct&#x2F;recki-ct
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you have a look at the &lt;code&gt;mandelbrot()&lt;&#x2F;code&gt; function in the file, we can see it does all the work itself. For each pixel in the image, it iterates over a mathematical function until either the absolute value of the complex number “escapes” (tends towards infinity), or it hits the maximum number of iterations that we’ve previously defined to be 4096.&lt;&#x2F;p&gt;
&lt;p&gt;For each row of pixels in the image it will create an array containing the number of iterations for each pixel. Then, it creates another array representing columns, which contains the list of rows. Finally, the &lt;code&gt;render()&lt;&#x2F;code&gt; function is used to convert the number of iterations into a colour, but we can ignore that for now as it’s fairly quick by comparison.&lt;&#x2F;p&gt;
&lt;p&gt;We’ll change the &lt;code&gt;main()&lt;&#x2F;code&gt; function so that it will attempt to precompile the &lt;code&gt;mandelbrot()&lt;&#x2F;code&gt; function, and then execute that. Also, we’ll need to tell Recki what the expected input and output types are for our function so that it knows what it’s dealing with. We do this using a docblock, in the same way that we would if we were using phpDocumentor or similar. You can see this version of the code &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;39e62755c586dc0c8907#file-mandelbrotwithrecki-php&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&#x2F;**
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param double $xMin
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param double $xMax
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param double $yMin
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param double $yMax
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param int $xPx
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param int $yPx
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @return array
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; function mandelbrot($xMin, $xMax, $yMin, $yMax, $xPx, $yPx)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; &#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now the changes to the main function – these replace lines 100 to 104:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $start = microtime(true);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $function = ReckiCT\Jit::jitfu(&amp;#39;mandelbrot&amp;#39;);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    printf(&amp;quot;Compiling took %F\n&amp;quot;, $mandelTime);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $start = microtime(true);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $data = $function($xMin, $xMax, $yMin, $yMax, $xPx, $yPx);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $mandelTime = microtime(true) - $start;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    printf(&amp;quot;Data took %F\n&amp;quot;, $mandelTime);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we try and run it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src&#x2F;recki-ct$ php mandelbrotWithRecki.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Fatal error: Uncaught exception &amp;#39;LogicException&amp;#39; with message &amp;#39;Found node without parser rule: Expr_Array&amp;#39; in &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Parser&#x2F;Parser.php:112
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Stack trace:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#0 &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Parser&#x2F;Rules&#x2F;Assign.php(41): ReckiCT\Parser\Parser-&amp;gt;parseNode(Object(PhpParser\Node\Expr\Array_), Object(ReckiCT\Parser\State))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#1 &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Parser&#x2F;Parser.php(109): ReckiCT\Parser\Rules\Assign-&amp;gt;parse(Object(PhpParser\Node\Expr\Assign), Object(ReckiCT\Parser\State))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#2 &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Parser&#x2F;Parser.php(96): ReckiCT\Parser\Parser-&amp;gt;parseNode(Object(PhpParser\Node\Expr\Assign), Object(ReckiCT\Parser\State))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#3 &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Parser&#x2F;Parser.php(86): ReckiCT\Parser\Parser-&amp;gt;parseStmtList(Array, Object(ReckiCT\Parser\State))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#4 &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Jit.php(222): ReckiCT\Parser\Parser-&amp;gt;parseFunction(Object(PhpParser\Node\Stmt\Function_))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#5 &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Jit.php(240): ReckiCT\Jit-&amp;gt;getFunctionG in &#x2F;home&#x2F;vagrant&#x2F;src&#x2F;recki-ct&#x2F;lib&#x2F;ReckiCT&#x2F;Parser&#x2F;Parser.php on line 112
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oh. The problem here is that Recki is still pretty young (it’s only around 6 months since its first release), and it currently doesn’t handle arrays. That’s OK, we can refactor the code a little, and break out the part of the iteration that returns a number into a separate function, which looks like the one below. Note that Recki doesn’t currently do constant lookups either, so we pass the maximum number of iterations as a parameter.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&#x2F;**
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param double $cReal
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param double $cImag
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @param int $maxIterations
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; * @return int
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;function mandelbrotIteration($cReal, $cImag, $maxIterations)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;{
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $originalReal = $cReal;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $originalImag = $cImag;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    $ni = 0;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    while ($ni &amp;lt; $maxIterations &amp;amp;&amp;amp; ($cReal * $cReal * $cImag * $cImag &amp;lt; 4.0)) {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $tmp = $cReal * $cReal - $cImag * $cImag + $originalReal;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $cImag = $cImag * $cReal * 2 + $originalImag;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $cReal = $tmp;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $ni++;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    if ($ni == $maxIterations) {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $ni = 0;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    return $ni;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The new version of the file is &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;39e62755c586dc0c8907#file-mandelbrotafterrefactor-php&quot;&gt;here&lt;&#x2F;a&gt;. Now, let’s try it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src&#x2F;recki-ct$ php mandelbrotAfterRefactor.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Compiling took 1.537641
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Data took 3.724597
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Render took 0.595848
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Not bad! It took about 1.5 seconds to compile, and then ran in 3.7 - somewhere around a 2100% improvement! We can do a little better too, as we can grab the intermediate representation that JitFu has made, and cache it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    if (file_exists(&amp;#39;mandelbrotIteration.ir&amp;#39;)) {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $start = microtime(true);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $ir = file_get_contents(&amp;#39;mandelbrotIteration.ir&amp;#39;);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $iterationFunc = ReckiCT\Jit::getInstance()-&amp;gt;compileIrJitFu($ir, &amp;#39;fibo&amp;#39;);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $loadTime = microtime(true) - $start;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        printf(&amp;quot;Loading took %F\n&amp;quot;, $loadTime);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    } else {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $start = microtime(true);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $iterationFunc = ReckiCT\Jit::jitfu(&amp;#39;mandelbrotIteration&amp;#39;);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        $compileTime = microtime(true) - $start;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        printf(&amp;quot;Compiling took %F\n&amp;quot;, $compileTime);
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;        file_put_contents(&amp;#39;mandelbrotIteration.ir&amp;#39;, 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;            ReckiCT\Jit::getInstance()-&amp;gt;getFunctionIr(&amp;#39;mandelbrotIteration&amp;#39;));
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Follow along with the code &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;39e62755c586dc0c8907#file-mandelbrotwithcachedir-php&quot;&gt;here&lt;&#x2F;a&gt;. Now let’s see how that looks:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src&#x2F;recki-ct$ php mandelbrotWithCachedIR.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Loading took 0.177504
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Data took 3.636709
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Render took 0.653733
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nice.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-next-step-with-recki&quot;&gt;The next step with Recki&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#the-next-step-with-recki&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Recki has another trick up its sleeve that we’ve not seen yet. Earlier, I hinted that it can generate code for multiple targets. One of these targets happens to be C code, wrapped in a PHP extension. This might be an interesting option for people who are a little wary of running code like JitFu on their production servers. Also, it means we can throw all of the knowledge and tricks contained within our C compiler at the code as well, to get as much speed as possible.&lt;&#x2F;p&gt;
&lt;p&gt;To demonstrate this, let’s lift the &lt;code&gt;mandelbrotIteration()&lt;&#x2F;code&gt; function right out of the code, and put it in its own file. I’ll call it &lt;code&gt;iteration.php&lt;&#x2F;code&gt;, and you can see it &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;39e62755c586dc0c8907#file-iteration-php&quot;&gt;here&lt;&#x2F;a&gt;. I can then run this command, assuming I’m in the Recki-CT root directory:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;php bin&#x2F;compile_pecl compile -O mandelbrot iteration.php
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m passing the &lt;code&gt;-O&lt;&#x2F;code&gt; option, which passes &lt;code&gt;-O3&lt;&#x2F;code&gt; to the C compiler to dial up its own optimizations. You should see some familiar text scrolling past as Recki generates, configures, and compiles a PECL extension for us. Next, we can return to our Mandelbrot code rip out all the additions we put in for our JitFu experiments, and indeed remove the &lt;code&gt;mandelbrotIteration()&lt;&#x2F;code&gt; function entirely. I’ve chosen to wrap it inside a &lt;code&gt;function_exists()&lt;&#x2F;code&gt; check instead, so that I can test with or without the extension loaded to prove I get the same output. You can get that version &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;39e62755c586dc0c8907#file-mandelbrotwithextension-php&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src&#x2F;recki-ct$ php -dextension=.&#x2F;mandelbrot.so mandelbrotWithExtension.php
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Data took 2.411557
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Render took 0.637504
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we’re down to 2.4 seconds. Not bad at all. Remember, we’re only optimizing the innermost loop here – once Recki is able to optimize functions using arrays, we could potentially speed it up even further.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Recki-CT is a very young project, so this is not the kind of thing I’d be looking to use in production quite yet, but it’s certainly something to keep an eye on. Particularly where we have certain functions within our applications that are very CPU-heavy, we might well be able to take a considerable amount of load off by optimizing just those functions and leaving the rest of our app stack as standard. As mentioned before, PHP has been talked about in the past as being a glue layer between C libraries and application code. If we can write PHP and generate optimized C code from that, then the barrier to entry for taking advantage of this is considerably lower.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;update&quot;&gt;Update&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#update&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;For comparison, I translated the code to straight C reasonably directly, which you can see &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;31c8ceb27802d2ef6606&quot;&gt;here&lt;&#x2F;a&gt;. It’s a standalone C program, not a PHP extension. It runs in around 2.1 seconds on the same VM:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vagrant@vagrant-ubuntu-trusty-64:~&#x2F;src&#x2F;Mandelbrot-browser$ .&#x2F;basic-mandelbrot
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Data took 2.107163
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Render took 0.000840
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;a name=&quot;vm&quot; href=&quot;#fn1&quot;&gt;1.&lt;&#x2F;a&gt; I realise that VMs don&#x27;t give a terribly accurate benchmark, but these tests deal with orders of magnitude, so they&#x27;ll reflect the speed difference enough to be getting on with.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Vagrantfile inheritance</title>
        <published>2014-04-02T00:00:00+00:00</published>
        <updated>2014-04-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/vagrantfile-inheritance/"/>
        <id>https://mgdm.net/weblog/vagrantfile-inheritance/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/vagrantfile-inheritance/">&lt;p&gt;I’ve recently been using a lot of Vagrant machines at work, and needed to come up with a way to permit people to customise settings such as the developer’s own DNS zone, the amount of RAM and number of vCPUs assigned to each machine, etc.&lt;&#x2F;p&gt;
&lt;p&gt;In the &lt;a href=&quot;http:&#x2F;&#x2F;docs.vagrantup.com&#x2F;v2&#x2F;vagrantfile&#x2F;index.html&quot;&gt;Vagrantfile reference&lt;&#x2F;a&gt; I noticed that Vagrant will merge several Vagrantfiles together on launch.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;First, the Vagrantfile packaged in the box&lt;&#x2F;li&gt;
&lt;li&gt;The Vagrantfile in &lt;code&gt;~&#x2F;.vagrant.d&#x2F;Vagrantfile&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The Vagrantfile in the project directory&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I knew that each Vagrantfile is just a Ruby script, so I decided to try adding a global variable in &lt;code&gt;~&#x2F;.vagrant.d&#x2F;Vagrantfile&lt;&#x2F;code&gt; to see if it was inherited.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; class=&quot;language-ruby z-code&quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-global z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-ruby&quot;&gt;$&lt;&#x2F;span&gt;global_vm_memory&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ruby&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-ruby&quot;&gt;1024&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-global z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-ruby&quot;&gt;$&lt;&#x2F;span&gt;global_vm_cpus&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ruby&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-ruby&quot;&gt;4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-global z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-ruby&quot;&gt;$&lt;&#x2F;span&gt;global_vm_tld&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ruby&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.mgdm&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, in the project’s Vagrantfile I added:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; class=&quot;language-ruby z-code&quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;config&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;vm&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;provider &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;virtualbox&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-start-block z-ruby&quot;&gt;do&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-parameters z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ruby&quot;&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-parameters z-ruby&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-ruby&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-parameters z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ruby&quot;&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;	v&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;memory &lt;span class=&quot;z-keyword z-operator z-assignment z-ruby&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-global z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-ruby&quot;&gt;$&lt;&#x2F;span&gt;global_vm_memory&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-augmented z-ruby&quot;&gt;||=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-ruby&quot;&gt;512&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;	v&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;cpus &lt;span class=&quot;z-keyword z-operator z-assignment z-ruby&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-global z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-ruby&quot;&gt;$&lt;&#x2F;span&gt;global_vm_cpus&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-augmented z-ruby&quot;&gt;||=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-ruby&quot;&gt;2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-keyword z-control z-ruby&quot;&gt;end&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That worked fine. I’m pretty sure it’s not the cleanest way, but it certainly is simple.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>zsh with Antigen</title>
        <published>2013-05-19T00:00:00+00:00</published>
        <updated>2013-05-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/zsh-antigen/"/>
        <id>https://mgdm.net/weblog/zsh-antigen/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/zsh-antigen/">&lt;p&gt;I’ve been using &lt;a href=&quot;http:&#x2F;&#x2F;www.zsh.org&quot;&gt;zsh&lt;&#x2F;a&gt; for a while, with
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;robbyrussell&#x2F;oh-my-zsh&quot;&gt;oh-my-zsh&lt;&#x2F;a&gt; to add a pile of new
features to it. Oh-my-zsh is great, and has a lot of useful things in it, but
I found it a bit of a pain to keep my fork of it in sync with the main
repository and another fork that I’d stolen things from. The fact that it was
one giant repository with everything in there didn’t seem quite right to me.
Then, I came across &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zsh-users&#x2F;antigen&quot;&gt;zsh-antigen&lt;&#x2F;a&gt;, which
promises to be to zsh what &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-pathogen&quot;&gt;Pathogen&lt;&#x2F;a&gt; is
to Vim. That sounded good to me, so I gave it a try.&lt;&#x2F;p&gt;
&lt;p&gt;The main difference is that instead of having one repository with all the
plugins, it lets you load plugins from pretty much any Git repository. It
includes a special case for the oh-my-zsh repository, so you can load plugins
and themes from there by default. I’d recommend reading the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zsh-users&#x2F;antigen&quot;&gt;README in the
Antigen repository&lt;&#x2F;a&gt; to get the full
story, but I’ll give a quick overview of how I’ve got mine set up here.&lt;&#x2F;p&gt;
&lt;p&gt;First off, I created my own Git repository, and added the Antigen repository as
a submodule. I’ve called mine &lt;code&gt;.zsh-antigen&lt;&#x2F;code&gt;, and it lives in my home
directory. It’s on &lt;a href=&quot;http:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;zsh-antigen&quot;&gt;Github&lt;&#x2F;a&gt; if you want to
clone or fork it.&lt;&#x2F;p&gt;
&lt;script src=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;cf14dc0aad25e468411f.js&quot;&gt;
&lt;&#x2F;script&gt;
&lt;p&gt;Next I created my &lt;code&gt;zshrc&lt;&#x2F;code&gt; file, at &lt;code&gt;~&#x2F;.zsh-antigen&#x2F;zshrc&lt;&#x2F;code&gt;. I symlink it into my
home directory to &lt;code&gt;~&#x2F;.zshrc&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;script src=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mgdm&#x2F;5608243.js&quot;&gt;
&lt;&#x2F;script&gt;
&lt;p&gt;On lines 1 and 2, I set up a variable to refer to the antigen directory, and
then load the antigen script itself.&lt;&#x2F;p&gt;
&lt;p&gt;On line 4, we tell antigen to use oh-my-zsh by default. That way, we can load
plugins from there with the &lt;code&gt;antigen-bundle&lt;&#x2F;code&gt; command. I use a few, the vagrant
and git plugins on all my machines, and I detect Mac OS X and load the osx
plugin if I’m on a Mac.&lt;&#x2F;p&gt;
&lt;p&gt;I use a couple of bundles that don’t belong to oh-my-zsh, too – these are
the &lt;code&gt;zsh-syntax-highlighting&lt;&#x2F;code&gt; bundle from zsh-users, which adds nice syntax
highlighting to the command line, and the &lt;code&gt;zsh-history-substring-search&lt;&#x2F;code&gt; bundle
that provides history search when you type part of a command and press the up
cursor key. As you can see, if they’re hosted on Github, it’s as easy as
specifying the repos in a “username&#x2F;repo-name” format.&lt;&#x2F;p&gt;
&lt;p&gt;On line 14, I load a bundle which is local to my config. (It just
provides some path detection to tell me what app I’m in when editing files on
my work computer. These appear in the right prompt.) You can add as many bundles
and as you like, without them having to be part of oh-my-zsh.&lt;&#x2F;p&gt;
&lt;p&gt;Next, on line 16 I apply a theme. This is a theme in the same format as
oh-my-zsh, and just specifies what appears in the left prompt (&lt;code&gt;PS1&lt;&#x2F;code&gt;, as in Bash
and similar shells) and &lt;code&gt;RPS1&lt;&#x2F;code&gt; (which is right-aligned and doesn’t normally exist
in Bash).&lt;&#x2F;p&gt;
&lt;p&gt;We then call &lt;code&gt;antigen-apply&lt;&#x2F;code&gt; last of all, which applies all the
previous configuration. When &lt;code&gt;antigen-apply&lt;&#x2F;code&gt; is called, it will ensure that it
has all the bundles and themes that have been requested. If not, it will go off
and download them and cache them locally. This means that the first time you
load antigen in a new shell, it’ll wait a few seconds while it goes and grabs
the oh-my-zsh code along with any other bundles you’ve requested.&lt;&#x2F;p&gt;
&lt;p&gt;Underneath this, I place all my useful environment variables, aliases, and
install things like rbenv, the same way as I used to do in Bash. I find this
way of working to be quite a bit cleaner than oh-my-zsh - the &lt;code&gt;.zshrc&lt;&#x2F;code&gt; I ended up
with in there had quite a lot going on, along with various ‘magic’ things that
I wasn’t keen on. The automatic updating really got on my nerves, even though
it’s supposed to be convenient. Feel free to grab &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;zsh-antigen&quot;&gt;my
repo&lt;&#x2F;a&gt; and use it as a starting point if
it’s helpful.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PHP room at FOSDEM 2013</title>
        <published>2012-11-19T00:00:00+00:00</published>
        <updated>2012-11-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/fosdem-2013/"/>
        <id>https://mgdm.net/weblog/fosdem-2013/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/fosdem-2013/">&lt;p&gt;I’ve been intending to go to FOSDEM for a few years now, but so far I’ve never
quite got around to making it. This year, though, &lt;a href=&quot;http:&#x2F;&#x2F;lornajane.net&quot;&gt;Lorna&lt;&#x2F;a&gt;
asked me if I was up for helping to run the PHP devroom. I said yes, and so
this year I will be there!&lt;&#x2F;p&gt;
&lt;p&gt;There are calls for papers open for the main track and lightning talks, which
you can find on the &lt;a href=&quot;http:&#x2F;&#x2F;fosdem.org&quot;&gt;FOSDEM site&lt;&#x2F;a&gt;. We’d also like to see
submissions for talks in the PHP room–head on over to the &lt;a href=&quot;http:&#x2F;&#x2F;lrnja.net&#x2F;W1A2Nk&quot;&gt;submission
form&lt;&#x2F;a&gt; to post your talks. This year, we’re going to
try an anonymized process to choose the talks. All we’ll have to go on will be
the talk title, abstract and length; no personally identifiable information
will be there. As the form says, we don’t care who you are, we just want great
talks.&lt;&#x2F;p&gt;
&lt;p&gt;FOSDEM is a huge, community-run event that takes place in Brussels every year.
Attendance and participation is completely free to anyone. This does mean that
we can’t cover costs for accommodation or getting to and from Brussels, but we
hope that doesn’t put too many people off. As well as the PHP room, there will
be a lot more going on in other tracks and rooms around the event, so there’ll
be plenty of things to see and do elsewhere. Hopefully I’ll see some of you
there.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Why one-line installers are a bad idea</title>
        <published>2012-09-14T00:00:00+00:00</published>
        <updated>2012-09-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/why-one-line-installers-are-bad/"/>
        <id>https://mgdm.net/weblog/why-one-line-installers-are-bad/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/why-one-line-installers-are-bad/">&lt;p&gt;There has been a trend in the last while for various bits of useful software to
have a one-line shell command recommended as the installation method. The usual
form of this is to pipe something like &lt;code&gt;curl&lt;&#x2F;code&gt; or &lt;code&gt;wget&lt;&#x2F;code&gt; to some interpreter, be
it &lt;code&gt;bash&lt;&#x2F;code&gt;, &lt;code&gt;php&lt;&#x2F;code&gt;, &lt;code&gt;ruby&lt;&#x2F;code&gt;, or some such. They look like this (taken from &lt;a href=&quot;https:&#x2F;&#x2F;rvm.io&#x2F;rvm&#x2F;install&#x2F;&quot;&gt;RVM’s
installation page&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;curl -L https:&#x2F;&#x2F;get.rvm.io | bash -s stable --ruby
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;RVM is by no means the first bit of software to do this–I remember at
various stages PEAR, Homebrew, and others suggesting the same thing. This
command takes the output of &lt;code&gt;curl&lt;&#x2F;code&gt; and pipes it straight to &lt;code&gt;bash&lt;&#x2F;code&gt;. I have
several issues with this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;it-gives-you-no-opportunity-to-inspect-the-code-that-you-are-running&quot;&gt;It gives you no opportunity to inspect the code that you are running&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#it-gives-you-no-opportunity-to-inspect-the-code-that-you-are-running&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In this example, you are blindly assuming that the code you get from
http:&#x2F;&#x2F;get.rvm.io is actually the RVM installer. There is no verification of
any form - if, for example, the host has been compromised, the installer might
have been replaced with something as simple as an &lt;code&gt;rm -rf .&lt;&#x2F;code&gt;, which would blow
away anything in the current directory. Or, indeed, it could any other command
that you have permission to run as the current user. It might not even be
intentionally malicious–there could just be a bug which has some &lt;a href=&quot;http:&#x2F;&#x2F;pcgamingwiki.com&#x2F;wiki&#x2F;Half-Life#Severe_System_Crippling_and_Data_Destroying_Uninstall_Bug&quot;&gt;unexpected
side-effect&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;there-is-no-way-to-verify-the-source-of-the-code&quot;&gt;There is no way to verify the source of the code&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#there-is-no-way-to-verify-the-source-of-the-code&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It could be argued that because the code is delivered over HTTPS in this case,
there is some verification of the identity of the source. This is not enough,
as can be demonstrated by the case above, where the source is compromised. With
packaging systems such as &lt;code&gt;dpkg&lt;&#x2F;code&gt; or &lt;code&gt;rpm&lt;&#x2F;code&gt;, there are cryptographic signatures
attached to each package. These sign each release of the package in question,
and hence there is a trust layer you can use to help decide if you wish to use
the package source. Also, it can then flag up when the source may have been
compromised.&lt;&#x2F;p&gt;
&lt;p&gt;You can, of course, override the signature verification step in a package
manager along the lines of &lt;code&gt;dpkg&lt;&#x2F;code&gt; or &lt;code&gt;rpm&lt;&#x2F;code&gt; or many others that I have not used;
however, at that point, you are making the decision to do so yourself and
therefore take responsibility for the results.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of PHP’s Composer, which I’ll come back to, &lt;a href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;padraicb&quot;&gt;Pádraic
Brady&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;padraicb&#x2F;status&#x2F;246305589964181504&quot;&gt;pointed
out&lt;&#x2F;a&gt; that the Composer
people are aware of the issue of running arbitrary unsigned code, and a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;composer&#x2F;composer&#x2F;pull&#x2F;1092&quot;&gt;pull
request has been filed&lt;&#x2F;a&gt; to fix
part of it. Although I agree with many of the changes made, I don’t believe it
does anything to protect the installer itself. (I may be wrong here–if I have
misread, please let me know.)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;it-teaches-bad-habits&quot;&gt;It teaches bad habits&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#it-teaches-bad-habits&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The example that prompted this blog post is that of the PHP utility,
&lt;a href=&quot;http:&#x2F;&#x2F;getcomposer.org&quot;&gt;Composer&lt;&#x2F;a&gt;. This is a wonderful piece of software for
managing library dependencies within PHP projects. However, on their &lt;a href=&quot;http:&#x2F;&#x2F;getcomposer.org&#x2F;download&#x2F;&quot;&gt;download
page&lt;&#x2F;a&gt;, they have two variants of the one-line
installer, the first being along the pattern already discussed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;curl -s https:&#x2F;&#x2F;getcomposer.org&#x2F;installer | php
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the second, for “if you don’t have &lt;code&gt;curl&lt;&#x2F;code&gt;”:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;php -r &amp;quot;eval(&amp;#39;?&amp;gt;&amp;#39;.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;file_get_contents(&amp;#39;https:&#x2F;&#x2F;getcomposer.org&#x2F;installer&amp;#39;));&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the former case, you are teaching your users that piping code downloaded
from web sites directly to an interpreter is OK; in the latter example, you are
teaching people that doing the same with &lt;code&gt;eval&lt;&#x2F;code&gt; in PHP is also just fine. I,
personally, think this is the worst part of all–while running &lt;code&gt;curl&lt;&#x2F;code&gt; to get
the code is bad, it might also end up suggesting to people that &lt;code&gt;eval&lt;&#x2F;code&gt; is just
fine for this purpose, when even the most rudimentary material on security will
say just the opposite. Software written in PHP has a bad enough reputation for
careless use of its capability to open, and if you’re not careful, execute
‘files’ across the Web, and advocating this as part of an installation process
is really not a good thing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-summary&quot;&gt;In summary&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#in-summary&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Although installers like this are undoubtedly convenient for the user, there is
a huge risk as a result. Convenience and security undoubtedly do not
go hand in hand; in this case, it would be far better to encourage people to
download the installer file, and then perhaps verify it using a checksum such
as SHA256–although, of course, this is also open to compromise, it would be
a start. The package could also be signed with GPG or a similar system. This
would take the user a few minutes, which undoubtedly gets in the way of using the
software in question.  However, I believe in this case the loss of convenience
is far outweighed by mitigating the security risks involved.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>New Toys</title>
        <published>2012-06-25T00:00:00+00:00</published>
        <updated>2012-06-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/new-toys/"/>
        <id>https://mgdm.net/weblog/new-toys/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/new-toys/">&lt;p&gt;For someone who hardly ever actually writes anything, I do spend quite a long
time messing about with the software that powers my site. I think over the
years I’ve variously used &lt;a href=&quot;http:&#x2F;&#x2F;www.wordpress.org&quot;&gt;WordPress&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;ez.no&quot;&gt;eZ
Publish&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;habariproject.org&quot;&gt;Habari&lt;&#x2F;a&gt;, and probably other
things that I’ve forgotten to run a weblog but never actually use it. Welcome
to the latest incarnation, which this time is powered by
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mojombo&#x2F;jekyll&quot;&gt;Jekyll&lt;&#x2F;a&gt;. I decided that running a database
and a server-side language all the time for a site that doesn’t get much
traffic is pointless, and hence Jekyll suits my purposes by generating flat
HTML files that require no further processing. It does also mean that I can
store the site itself on Github, and write Markdown files in Vim to create
posts, which appeals to my geek side.&lt;&#x2F;p&gt;
&lt;p&gt;This time I built the theme from scratch myself, too, after spending a little
too long reading books with names like &lt;em&gt;The Elements of Typographic Style&lt;&#x2F;em&gt; and
&lt;em&gt;Thinking With Type&lt;&#x2F;em&gt;, as well as innumerable articles on &lt;a href=&quot;http:&#x2F;&#x2F;alistapart.com&quot;&gt;A List
Apart&lt;&#x2F;a&gt; and places like that. I like to think that I have
the typography of the site working to a reasonable level, and I’ll probably
continue to ham-fistedly play with the rest of it. Just writing this post
resulted in me messing with the CSS of the navigation as I wasn’t quite happy
with how it looked.&lt;&#x2F;p&gt;
&lt;p&gt;In the time since my last post, I have actually done useful things to a couple
of the software projects I’ve been working on. I’ll aim to try and get some of
those written up soon.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PECL&#x2F;Cairo 0.3.0 released!</title>
        <published>2011-12-28T00:00:00+00:00</published>
        <updated>2011-12-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/peclcairo-030-released/"/>
        <id>https://mgdm.net/weblog/peclcairo-030-released/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/peclcairo-030-released/">&lt;p&gt;As I’m sure you’ve all been longing to hear, we’ve finally got around to releasing a new version of &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;cairo&quot;&gt;PECL&#x2F;Cairo&lt;&#x2F;a&gt;! This version fixes some bugs, and adds support for some new features available since Cairo 1.10 — notably, support for subsurfaces, which are surfaces that draw onto a part of a larger surface, and for recording surfaces, which record all drawing operations and can then be used as the source for other drawing operations. Also, &lt;a href=&quot;http:&#x2F;&#x2F;www.theskillers.co.uk&quot;&gt;Mark Skilbeck&lt;&#x2F;a&gt; has added support for Win32 fonts. Also, the FreeType font handling has been improved, and should now give more informative messages when errors occur.&lt;&#x2F;p&gt;
&lt;p&gt;Any questions, comments, bug reports, or contributed code are welcome. Drop us a line on the PECL mailing list, or try #php.pecl on EFNet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>FrOSCon 2011</title>
        <published>2011-08-03T00:00:00+00:00</published>
        <updated>2011-08-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/froscon-2011/"/>
        <id>https://mgdm.net/weblog/froscon-2011/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/froscon-2011/">&lt;p&gt;I’m very pleased to be able to announce that I’ll be giving two talks at this year’s FrOSCon conference in St Augustin near Bonn in Germany, on the 20th and 21st of August. The first is on the &lt;a href=&quot;http:&#x2F;&#x2F;froscon.phpugdo.de&quot;&gt;PHP track&lt;&#x2F;a&gt;, and is an overview of the &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;cairo&quot;&gt;PECL&#x2F;Cairo&lt;&#x2F;a&gt; extension for PHP.&lt;&#x2F;p&gt;
&lt;p&gt;The second talk is on the main track, and is about &lt;a href=&quot;http:&#x2F;&#x2F;programm.froscon.org&#x2F;2011&#x2F;events&#x2F;663.html&quot;&gt;Making Software See&lt;&#x2F;a&gt;, where I’ll give an introduction to the &lt;a href=&quot;http:&#x2F;&#x2F;www.opencv.org&quot;&gt;OpenCV&lt;&#x2F;a&gt; image processing library, including some examples in various popular programming languages.&lt;&#x2F;p&gt;
&lt;p&gt;I’m extremely happy to have been selected both by the main FrOSCon organisers and the PHP track, organised by the &lt;a href=&quot;http:&#x2F;&#x2F;phpugdo.de&#x2F;.html&quot;&gt;PHP Usergroup Dortmund&lt;&#x2F;a&gt;. I hope to see some of you there!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pango for PHP PECL channel</title>
        <published>2011-06-09T00:00:00+00:00</published>
        <updated>2011-06-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/pango-for-php-pecl-channel/"/>
        <id>https://mgdm.net/weblog/pango-for-php-pecl-channel/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/pango-for-php-pecl-channel/">&lt;p&gt;It occurs to me that though I wrote an &lt;a href=&quot;http:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;using-pango-for-php-a-taster&quot;&gt;introduction post about Pango for PHP&lt;&#x2F;a&gt;, I forgot to mention that it’s actually installable using the PECL installer.&lt;&#x2F;p&gt;
&lt;pre&gt;
 pecl channel-discover pecl.mgdm.net
 pecl install channel:&#x2F;&#x2F;pecl.mgdm.net&#x2F;Pango-0.1.0
&lt;&#x2F;pre&gt;
&lt;p&gt;Assuming you have the required development packages installed, it should go off and install it. You may still need to add the&lt;&#x2F;p&gt;
&lt;pre&gt;
extension=pango.so
&lt;&#x2F;pre&gt;
&lt;p&gt;line to your php.ini. Hope this helps someone give it a go! As ever, any feedback is welcome.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Android: LinearLayouts, WebViews and black screens</title>
        <published>2011-03-21T00:00:00+00:00</published>
        <updated>2011-03-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/android-linearlayouts-webviews-and-black-screens/"/>
        <id>https://mgdm.net/weblog/android-linearlayouts-webviews-and-black-screens/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/android-linearlayouts-webviews-and-black-screens/">&lt;p&gt;Just making a quick note in case anyone else is searching for the same problem.&lt;&#x2F;p&gt;
&lt;p&gt;I have an app with an activity which previously was just a WebView, but I wanted to add some other widgets above the WebView as well, so I made an XML layout and wrapped the WebView in a LinearLayout. Upon using this as the content view, my WebView went black. Completely. This resulted in a bit of frantic Googling, whereupon I discovered that it wasn’t an unusual problem. Most of the solutions revolved around making sure the LinearLayout’s width and height were both set to fill_parent — this didn’t work for me. A little bit of investigation then lead me to discover that I’d forgotten to set the orientation on the LinearLayout. Once I’d set that, everything started working fine. A silly problem, but quite often it’s the silly ones that take the most time to figure out.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using Pango for PHP: a taster</title>
        <published>2011-02-21T00:00:00+00:00</published>
        <updated>2011-02-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/using-pango-for-php-a-taster/"/>
        <id>https://mgdm.net/weblog/using-pango-for-php-a-taster/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/using-pango-for-php-a-taster/">&lt;p&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;cairo&quot;&gt;PECL&#x2F;Cairo&lt;&#x2F;a&gt; library is pretty good at drawing vector graphics (in our opinion, as the developers, at least!), but one thing it’s not able to do by itself is draw text with mildly advanced layout. It has the CairoContext::showText() function, but that doesn’t really let you do anything GD can’t. That’s because the developers of the Cairo library decided to let another more specialised library handle the job of text layout. Much of the time, the library that gets used for this is &lt;a href=&quot;http:&#x2F;&#x2F;pango.org&quot;&gt;Pango&lt;&#x2F;a&gt;. It has several bindings already for most popular languages on Unix-like platforms. It’s quite capable, and able to lay out text while taking care of things such as paragraph alignment, line breaking, bold&#x2F;italic text, justification, and various other features. In this post, I intend to give a little tour of some of its features.&lt;&#x2F;p&gt;
&lt;p&gt;Quite a while ago now, I wrote an extension to wrap Pango for PHP. It’s available on its &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;php-pango&quot;&gt;Github repository&lt;&#x2F;a&gt;. It’s not available on PECL right now, but you can check it out from there and install it using the &lt;a href=&quot;http:&#x2F;&#x2F;php.net&#x2F;manual&#x2F;en&#x2F;install.pecl.phpize.php&quot;&gt;normal method&lt;&#x2F;a&gt;. (Sorry Windows users, I’ve not had time to test it out on there, and likely won’t any time soon. Patches are welcome, though…). It requires that the Pango headers are installed, and that PECL&#x2F;Cairo is already installed into PHP.&lt;&#x2F;p&gt;
&lt;p&gt;Once installed, you can use it with Cairo. The best way to show it off is probably some example code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-php&quot;&gt;&amp;lt;?php&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-support z-function z-network z-php&quot;&gt;header&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;Content-Type: image&#x2F;png&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Make a 300x300px image surface &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoImageSurface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoFormat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;ARGB32&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;300&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;300&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoContext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Set the background to white &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setSourceRGB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;paint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Let&amp;#39;s draw using black &amp;#39;ink&amp;#39; &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setSourceRGB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Make a Pango layout, set the font, then set the layout size &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;PangoLayout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;desc&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;PangoFontDescription&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;Bitstream Charter 28&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setFontDescription&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;desc&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setWidth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;250&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-php&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-php&quot;&gt;PANGO_SCALE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Here, we use Pango markup to make part of the text bold &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setMarkup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;Hello &amp;lt;b&amp;gt;world!&amp;lt;&#x2F;b&amp;gt; Here is a rather long paragraph which should get wrapped&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Draw the layout on the surface &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;showLayout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Output the PNG to the browser &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;writeToPng&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;php:&#x2F;&#x2F;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all goes to plan, you should see a PNG in your browser with the above text.&lt;&#x2F;p&gt;
&lt;p&gt;Going through each step, firstly we set up the Cairo surface to draw on, and the context we use to draw with. Once we have done that, we can create a PangoLayout object which lets us draw the text we require. The PangoLayout is passed a context, so it can invoke the drawing methods itself to draw the text. We pass the PangoLayout a PangoFontDescription object, which lets us choose from the fonts already installed on the machine. This means that we don’t need to concern ourselves with the paths to actual TrueType font files, or similar - the fonts are resolved by Fontconfig or whatever system is available on your machine.&lt;&#x2F;p&gt;
&lt;p&gt;Next, we set the width of the layout. We can also set a height, but I haven’t bothered on this occasion. This lets Pango know where to wrap the text - if we don’t set this, it won’t bother, which may result in text falling off the edge of the image. You may note that the width is multiplied by the PANGO_SCALE - this is because Pango deals in units which are a tiny fraction (1&#x2F;1024, in fact) of a pixel, in order to handle antialiasing properly. Because we’re using a CairoImageSurface, this means that they layout will be 250 pixels wide.&lt;&#x2F;p&gt;
&lt;p&gt;Next up, we set the text to be drawn. There are two methods available to do this; PangoLayout::setText() is used when we just want to render text with no formatting instructions. In this case, I’ve opted for the PangoLayout::setMarkup() method, which lets me use &lt;a href=&quot;http:&#x2F;&#x2F;library.gnome.org&#x2F;devel&#x2F;pango&#x2F;stable&#x2F;PangoMarkupFormat.html&quot;&gt;Pango’s markup language&lt;&#x2F;a&gt; to make part of the text bold. Many other attributes can be changed using this markup, which has shortcuts that somewhat resemble HTML.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, the call to showLayout() renders the layout onto the surface. You can also render just a path, using layoutPath(), which sets the path on the surface so you can then use more advanced effects with Cairo. The layout is drawn using whatever the current source is on the Cairo context, so you can render using flat colours, gradients, other source images, or whatever takes your fancy. Additionally, this means that any transformations you have set on the Cairo context also take effect, allowing you to rotate, scale, shear and otherwise distort the text.&lt;&#x2F;p&gt;
&lt;p&gt;It probably looks a little complex just to write some text on an image, but it is rather flexible. This flexibility is handy when you consider that Cairo can render more than just PNG images; PDFs, PostScript and SVG are also easy to create. I hope that this post may inspire someone else to give it a try. Feedback and reports of issues are always welcome.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>libsureelec, a driver for Sure Electronics LCD displays</title>
        <published>2011-02-02T00:00:00+00:00</published>
        <updated>2011-02-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/libsureelec-a-driver-for-sure-electronics-lcd-displays/"/>
        <id>https://mgdm.net/weblog/libsureelec-a-driver-for-sure-electronics-lcd-displays/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/libsureelec-a-driver-for-sure-electronics-lcd-displays/">&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;img&#x2F;posts&#x2F;IMAG0227.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A few months ago I got a pair of 4x20 LCD displays from Sure Electronics, via eBay. Though they worked quite happily through LCDproc, I didn’t really want to use that (as I intend to use one of them on a &lt;a href=&quot;http:&#x2F;&#x2F;bifferos.bizhat.com&#x2F;&quot;&gt;Bifferboard&lt;&#x2F;a&gt;). To that end, I’ve attempted to write a driver for them. Until recently I didn’t have a lot of success, which made me think that the documentation provided with the device was incorrect, until &lt;a href=&quot;http:&#x2F;&#x2F;www.gjcp.net&quot;&gt;Gordon&lt;&#x2F;a&gt; suggested trying the command set through gtkterm. I did, which made it work, and discovered that it requires the entire line to be sent to the display even if you’re only updating part of it. Adjusting my code to handle this, and add some sleep time after sending each command, made it work.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve put the code on &lt;a href=&quot;http:&#x2F;&#x2F;github.com&#x2F;mgdm&#x2F;libsureelec&quot;&gt;Github&lt;&#x2F;a&gt; in case anyone else is interested. It’s able to drive my DE-LD023 device quite happily, but I suspect it should work for other 4x20 devices too. Once I add the code to detect the device features it should also work for different sized displays. Any comments or patches are of course welcome.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>CMSes: an update</title>
        <published>2011-01-19T00:00:00+00:00</published>
        <updated>2011-01-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/cmses-an-update/"/>
        <id>https://mgdm.net/weblog/cmses-an-update/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/cmses-an-update/">&lt;p&gt;My previous post was typed in a bit of a hurry (was it that obvious?) and could probably have done with a few more sarcasm tags, though I think I still have a valid, if small, point. It surprised me that these well-maintained projects seem to be content to run with what I would consider to be errors. Though they do run, otherwise nobody would be using them. For what it’s worth, SilverStripe and I have made up and it’s all going swimmingly at present. Thanks to everyone who commented with recommendations; I’ll try and follow some of them up when I get time.&lt;&#x2F;p&gt;
&lt;p&gt;One comment did ask me to define what I meant when I refer to a “lightweight” CMS – basically, I was looking for something that will allow me to create a hierarchy of pages that consist roughly of a title and content. Nothing fancy. I don’t need multiple content types, complex user management, discussion forums, built-in wikis, etc. It’s the sort of thing I could have coded up in a couple of days using any number of frameworks, but I figured there’d be something off the shelf that’d do what I was after.&lt;&#x2F;p&gt;
&lt;p&gt;Another commenter questioned why I cared about coding standards warnings seemingly more than avoiding SQL injection and XSS and CSRF protection – I don’t, those are absolute hard requirements for any application. I’d put avoiding the coding standards warnings somewhere above “nice to have”, but those warnings are indications that something is being done in a way which is either less than ideal (such as using non-static methods in a static context, a la Concrete5), or deprecated (such as using the ereg functions).&lt;&#x2F;p&gt;
&lt;p&gt;My next post shall try and be a little more constructive, as I release some code.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Where are all the decent PHP CMSes?</title>
        <published>2011-01-17T00:00:00+00:00</published>
        <updated>2011-01-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/where-are-all-the-decent-php-cmses/"/>
        <id>https://mgdm.net/weblog/where-are-all-the-decent-php-cmses/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/where-are-all-the-decent-php-cmses/">&lt;p&gt;I’ve been recently asked to check out some CMSes for someone, and try to find a recommendation. What I’ve been finding hasn’t really been encouraging. Out of the several CMSes I’ve tried, they’ve all failed for various reasons. I admit that I might be looking at this from a slightly different perspective than most - that of admining it and coding against it, rather than as a user - but it’s still rather disappointing.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Silverstripe is what I used first - but the forms (including the login to the admin) kept failing to render. In the end, I got sick of debugging it and started my hunt.&lt;&#x2F;li&gt;
&lt;li&gt;Next up was Concrete5, which I heard mentioned recently. There were &lt;strong&gt;one hundred and fifty-five&lt;&#x2F;strong&gt; strict warnings in the front page of the installer. Bye bye.&lt;&#x2F;li&gt;
&lt;li&gt;Next, CMS Made Simple. Its installer wanted &lt;code&gt;E_\STRICT&lt;&#x2F;code&gt; and &lt;code&gt;E\_DEPRECATED&lt;&#x2F;code&gt; removed from error reporting. At this point some folk might have continued; but that was enough for me not to consider it. I didn’t have enough confidence in the code that I wanted to continue. It lost more points for the tarball not extracting into a subdirectory, which resulted in my document root being filled with nonsense.&lt;&#x2F;li&gt;
&lt;li&gt;Joomla!… well, my last experience of it wasn’t pleasant - I couldn’t work out how the code was structured. It’s also overkill for the requirements of this site.&lt;&#x2F;li&gt;
&lt;li&gt;I would love to go for Habari, but the site isn’t a blog, so it doesn’t really fit the use case. It’s still the top of the list just now, though.&lt;&#x2F;li&gt;
&lt;li&gt;I could do what everyone else does and run Wordpress - but, again, the site isn’t a blog, and I’d rather try something different.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I didn’t consider Drupal or eZ Publish, which again I believed to be massive overkill for what is required of the site. What’s going on? This is what PHP is supposed to be good at. Where are the simple, lightweight CMSes with modern code? Notices, strict and deprecation warnings should be considered errors when developing - this doesn’t seem to be the case with many of the above projects.&lt;&#x2F;p&gt;
&lt;p&gt;So, that’s what I’ve found. I now don my asbestos suit.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Habari plugins published</title>
        <published>2011-01-16T00:00:00+00:00</published>
        <updated>2011-01-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/habari-plugins-published/"/>
        <id>https://mgdm.net/weblog/habari-plugins-published/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/habari-plugins-published/">&lt;p&gt;I’ve just committed two new plugins to the habari-extras Subversion. Firstly, there’s the ‘share’ plugin, which adds the Facebook OpenGraph metadata to pages so that the Like button works, and also adds Facebook and Twitter widgets to the bottom of posts. Secondly, there’s a bitly plugin, that pings bit.ly’s API when every post is published and generates a short URL. This URL is then stored in the post info, and it provides a template to add it to the head of each page using the &lt;a href=&quot;http:&#x2F;&#x2F;microformats.org&#x2F;wiki&#x2F;rel-shortlink&quot;&gt;shortlink&lt;&#x2F;a&gt; markup. I’d be interested in feedback from anyone more familar with Habari in case there’s a better way to do what I’m doing.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;svn.habariproject.org&#x2F;habari-extras&#x2F;plugins&#x2F;share&#x2F;&quot;&gt;Share plugin&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;svn.habariproject.org&#x2F;habari-extras&#x2F;plugins&#x2F;bitly&#x2F;&quot;&gt;Bit.ly plugin&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Recent activity: Habari plugins</title>
        <published>2011-01-15T00:00:00+00:00</published>
        <updated>2011-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/recent-activity-habari-plugins/"/>
        <id>https://mgdm.net/weblog/recent-activity-habari-plugins/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/recent-activity-habari-plugins/">&lt;p&gt;I think I’m just about keeping to this one-post-a-week thing, almost. I’ve recently been playing with the internals of Habari, writing a couple of plugins. I’ve found it quite well put together, though I don’t seem to ever get the Utils::debug() output to display properly - though this might have been due to the code I was writing running before a redirect. I believe though that I now have got 2 plugins which I’m going to investigate publishing - one which generates the Facebook and Twitter widgets at the bottom of the posts (and the relevant OpenGraph metadata for Facebook in the header), and another which pings bit.ly and generates a short URL for each post as it’s published. I’m writing this post in part as a test to see that it works for real :-)&lt;&#x2F;p&gt;
&lt;p&gt;If I get a bit of time over the next few days, I’ll finish tidying them up and make them available. If anyone’s interested before I do, drop me an email or catch me on Twitter.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2011, now with less tumbleweed</title>
        <published>2011-01-02T00:00:00+00:00</published>
        <updated>2011-01-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/2011-now-with-less-tumbleweed/"/>
        <id>https://mgdm.net/weblog/2011-now-with-less-tumbleweed/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/2011-now-with-less-tumbleweed/">&lt;p&gt;It’s my intention this year to at write at least one post on here per week, ideally with some substance to it, rather than just recording what I had for breakfast (that being Twitter’s job, after all). I’m not holding my breath about whether I will manage it or not, but I intend to give it a go. I have a draft in the works, which I will hope to get out there some time soon…&lt;&#x2F;p&gt;
&lt;p&gt;In actual news, I have been accepted to talk at &lt;a href=&quot;http:&#x2F;&#x2F;confoo.ca&quot;&gt;ConFoo&lt;&#x2F;a&gt; in Canada, on the subject “Making PHP See” - which is about image recognition using OpenCV and PHP. I’m really looking forward to the conference, and I’m fortunate to be up alongside some excellent speakers, so it should be great fun.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Cairo talk feedback from DPC10</title>
        <published>2010-06-12T00:00:00+00:00</published>
        <updated>2010-06-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/cairo-feedback-from-dpc10/"/>
        <id>https://mgdm.net/weblog/cairo-feedback-from-dpc10/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/cairo-feedback-from-dpc10/">&lt;p&gt;I noted a couple of comments after my talk on Cairo at &lt;a href=&quot;http:&#x2F;&#x2F;phpconference.nl&quot;&gt;DPC 10&lt;&#x2F;a&gt; yesterday, so I thought I’d respond to them here to clear up what’s going on. It’s always good to get some feedback about something I’ve been working on so I’d like to reply and keep the conversation going if I can.&lt;&#x2F;p&gt;
&lt;p&gt;First off, someone mentioned that the wrapper seems a bit beta and incomplete - and yes, that is true. The 0.2.0 release, which is the latest as I wrote this, is still marked as beta. The aim of me coming and talking about it is to try and get some more people interested in using it, so we can get somemore information from real users about what works and what doesn’t. I probably didn’t help by mentioning that there are some features that we intend to implement that aren’t there yet, which I’ll list:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Support for reading and writing images that aren’t PNGs&lt;&#x2F;strong&gt; The developers of the core Cairo API are not really interested in handling all the various graphics formats that exist, so they decided to implement one and one only which is useful for getting data in and out. This is the functionality that we use at present. We (the developers of the wrapper) would like to fix that and handle JPEG, GIF, TIFF, and whatever new format is cool this week, but we’re not quite sure how to go about that yet. We could recycle the code used by GD or use ImageMagick or GraphicsMagick, but those would introduce dependencies that people might not have available. Once we work out a decent solution here, it will be put in.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Support for hyperlinks in PDFs and SVGs&lt;&#x2F;strong&gt; Again, this is something we’d quite like but it’s not supported in the underlying library &lt;strong&gt;yet&lt;&#x2F;strong&gt;. There have been rumours about adding an API to do this, but there hasn’t been a concensus about what’s a good way to go about it. It’s something I’d quite like to help fix, so I’ve been learning how Cairo itself is put together with the intention to add the support.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The other comments I saw suggested that the API is a bit fiddly, which I can’t deny. It’s not quite as simple to set up and get running as some of the other libraries in PHP already. This is nearly intentional - we’re wrapping the underlying Cairo API as closely as we can, because we don’t want to diverge too far from how other languages with Cairo wrappers work, so that developers who may be familiar with those already know roughly what is going on. It’s for this reason that, for example, the API uses floating-point values from 0 to 1 to define the intensity of colours, rather than an integer value from 0-255 which most people are probably used to. This is because Cairo is designed not to make any assumptions about the surface you’re going to be drawing to - some day we might get 16-bits-per-channel surfaces, and using float values means that we don’t need to change the API or the values we’re passing in to allow us to write to them. It’ll just carry on working as it did before, just with better colour resolution.&lt;&#x2F;p&gt;
&lt;p&gt;However, if anyone has any ideas for how we could make things simpler, then we’d love to hear about it &amp;amp;emdash; drop us a line on the PECL developers mailing list (which you can find on the &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;support.php&quot;&gt;PECL mailing lists&lt;&#x2F;a&gt; page), or find us on IRC on #php.pecl on EFnet.&lt;&#x2F;p&gt;
&lt;p&gt;There are a couple of things that I have worked on which sit on top of the Cairo extension, which can do some interesting things. If you’re still at DPC I’ll be demoing a couple of them on the uncon track at 2pm. It’s only a 15 minute talk, so it shouldn’t be too boring…!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ubuntu Accessibility team</title>
        <published>2010-06-01T00:00:00+00:00</published>
        <updated>2010-06-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/ubuntu-accessibility-team/"/>
        <id>https://mgdm.net/weblog/ubuntu-accessibility-team/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/ubuntu-accessibility-team/">&lt;p&gt;Recently I’ve become involved in a move to resurrect the Ubuntu Accessibility team, which seemed to have stagnated until quite recently when &lt;a href=&quot;http:&#x2F;&#x2F;pendulumtech.wordpress.com&quot;&gt;Penelope Stowe&lt;&#x2F;a&gt; got involved and suggested I joined too. She arranged a session at the Ubuntu Developer Summit for the next Ubuntu release, Maverick Meerkat, which seems to have &lt;a href=&quot;http:&#x2F;&#x2F;pendulumtech.wordpress.com&#x2F;2010&#x2F;05&#x2F;31&#x2F;ubuntu-accessibility-team-goals-for-maverick-meerkat&#x2F;&quot;&gt;gone quite well&lt;&#x2F;a&gt;. The main focus for the team right now is getting organised, and to this end we’re aiming to create a set of personas, which are representations of hypothetical users with various accessibility requirements which developers and testers can keep in mind when working on the next Ubuntu release. These personas are going to be developed by a survey which will be dispatched to a host of groups who may have accessibility requirements to get an idea of what the main factors that affect their experience with Ubuntu are, so we can get an idea of the main areas to improve. Hopefully then the work which will take place as a result of these can be sent upstream to the original projects.&lt;&#x2F;p&gt;
&lt;p&gt;My own role in the team isn’t quite clear yet, but I intend to help on the development side, if I can, once more work starts in this area. If you would like to help, the team hangs out on &lt;a href=&quot;irc:&#x2F;&#x2F;chat.freenode.net&#x2F;#ubuntu-accessibility&quot;&gt;#ubuntu-accessibility&lt;&#x2F;a&gt; on Freenode IRC, and there is a &lt;a href=&quot;http:&#x2F;&#x2F;lists.ubuntu.com&#x2F;mailman&#x2F;listinfo&#x2F;ubuntu-accessibility&quot;&gt;mailing list&lt;&#x2F;a&gt;. You can also check out the &lt;a href=&quot;https:&#x2F;&#x2F;wiki.ubuntu.com&#x2F;Accessibility&quot;&gt;wiki page&lt;&#x2F;a&gt; which we’re working on improving.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>EuroWinPHP contest</title>
        <published>2010-04-10T00:00:00+00:00</published>
        <updated>2010-04-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/eurowinphp-contest/"/>
        <id>https://mgdm.net/weblog/eurowinphp-contest/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/eurowinphp-contest/">&lt;p&gt;This year I’ve decided to enter the &lt;a href=&quot;http:&#x2F;&#x2F;www.eurowinphp.com&quot;&gt;EuroWinPHP&lt;&#x2F;a&gt; contest, as I figured it might be interesting to learn a bit more about how PHP works on Windows. I originally started using it there, back in around 2002, running early versions of Apache 1.3 and PHP 4.1 on Windows 98 and 2000. These days, though, I’m running IIS7 and PHP 5.3.2, and have a bit more knowledge of how the bits fit together, though since I’ve been running Linux for the last 5 years I’m a little out of touch.&lt;&#x2F;p&gt;
&lt;p&gt;The project I’ve opted to do is something I’ve been thinking about for a little while, but not got around to developing until now. It’s named GarnetCMS, and the idea is to create a CMS that uses the features of PHP 5.3, such as closures, and based around a signal&#x2F;slot mechanism. The idea is to initially develop it to use NoSQL datastores, and I intend to create back ends for &lt;a href=&quot;http:&#x2F;&#x2F;www.microsoft.com&#x2F;windowsazure&#x2F;&quot;&gt;Microsoft Azure&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;www.mongodb.org&quot;&gt;MongoDB&lt;&#x2F;a&gt; at first. If I do things correctly, though, adding a traditional RDBMS back end later on should be relatively simple.&lt;&#x2F;p&gt;
&lt;p&gt;Development-wise, I’m trying out Mercurial for version control, and using Bitbucket to store the code - the project will be on there at &lt;a href=&quot;http:&#x2F;&#x2F;bitbucket.org&#x2F;mgdm&#x2F;garnet-cms&#x2F;&quot;&gt;http:&#x2F;&#x2F;bitbucket.org&#x2F;mgdm&#x2F;garnet-cms&#x2F;&lt;&#x2F;a&gt; once it gets going. I’m intending to try out Komodo Edit, because while I do love GVim on Windows it doesn’t quite fit with the “complete change” I’m going for with most other things! &lt;a href=&quot;http:&#x2F;&#x2F;tortoisehg.bitbucket.org&#x2F;&quot;&gt;TortoiseHg&lt;&#x2F;a&gt; seems quitenice so far, and I’ve managed to get IIS up and running, so now all I need to do is get coding. I’m quite looking forward to seeing how it turns out.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Handling fonts in PECL&#x2F;Cairo</title>
        <published>2010-03-01T00:00:00+00:00</published>
        <updated>2010-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/handling-fonts-in-peclcairo/"/>
        <id>https://mgdm.net/weblog/handling-fonts-in-peclcairo/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/handling-fonts-in-peclcairo/">&lt;p&gt;(This is just a quick note to get some information out there for reference, I am adding it to the PHP manual as well!)&lt;&#x2F;p&gt;
&lt;p&gt;Currently, in PECL&#x2F;Cairo the only way to draw text is the referred to as the “toy” text API, which is a very basic way of handling text compared to the facilities available in the Cairo library itself. However, it’s sufficient for most purposes that I’ve come across so far. In version 0.1.0 of PECL&#x2F;Cairo, there was only one way to choose what font you wished to use, which was the &lt;a href=&quot;http:&#x2F;&#x2F;www.php.net&#x2F;manual&#x2F;en&#x2F;cairocontext.selectfontface.php&quot;&gt;CairoContext::selectFontFace()&lt;&#x2F;a&gt; method. You pass a string to this method with the name of the font you want, along with the optional slant and weight parameters. This then invokes your system’s font handling to find the font you’re after, or an alternative if it’s not available, so you need to have the font you want installed into your system’s font library. This is occasionally not handy.&lt;&#x2F;p&gt;
&lt;p&gt;In version 0.2.0 FreeType support was added. It allows you to choose any font file you’d like, as long as PHP’s streams API can find it. Yes, this means &lt;code&gt;http:&#x2F;&#x2F;&lt;&#x2F;code&gt; streams, but I wouldn’t recommend it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;php&quot; class=&quot;language-php z-code&quot;&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-php&quot;&gt;&amp;lt;?php&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Set up the surface, and make the background white &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoImageSurface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoFormat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-php&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-class z-php&quot;&gt;ARGB32&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;300&lt;&#x2F;span&gt;, &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoContext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setSourceRgb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;paint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Draw the text using the Vollkorn font, from 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;   http:&#x2F;&#x2F;friedrichalthausen.de&#x2F;2006&#x2F;01&#x2F;01&#x2F;vollkorn&#x2F; &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setSourceRGB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;moveTo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-php&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;60&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-php&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-new z-php&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-php&quot;&gt;&lt;span class=&quot;z-support z-class z-php&quot;&gt;CairoFtFontFace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-support z-function z-file z-php&quot;&gt;dirname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-language z-php&quot;&gt;__FILE__&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-string z-php&quot;&gt;.&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&#x2F;vollkorn.otf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setFontFace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;setFontSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-php&quot;&gt;50&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;showText&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;Hello world&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-comment z-block z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-php&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; Send the image to the browser &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-php&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-support z-function z-network z-php&quot;&gt;header&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;Content-type: image&#x2F;png&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;span class=&quot;z-variable z-other z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-php&quot;&gt;$&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-method z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-arrow z-php&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-php&quot;&gt;writeToPng&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-php&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-php&quot;&gt;&lt;span class=&quot;z-meta z-string-contents z-quoted z-double z-php&quot;&gt;php:&#x2F;&#x2F;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-php&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-php&quot;&gt;&lt;span class=&quot;z-meta z-group z-php&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-php&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-expression z-php&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-embedding z-php&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-block z-php&quot;&gt;&lt;span class=&quot;z-source z-php&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-php&quot;&gt;?&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-html-newline-after-php z-php&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The output image should hopefully look like this:&lt;&#x2F;p&gt;
&lt;img alt=&quot;Script output&quot; src=&quot;http:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;user&#x2F;files&#x2F;cairo-freetype.png&quot;&gt;
&lt;p&gt;(For those who are familiar with the Cairo library, this function maps to the &lt;code&gt;cairo_ft_font_face_create_for_ft_face&lt;&#x2F;code&gt; function in its API.)&lt;&#x2F;p&gt;
&lt;p&gt;There is still some work to be done in this area, notably to support the Windows and Mac OS X font systems, but they’ll be coming in a future release, we hope. If anyone would like to help us with that, or any other aspect of it (including documentation!), you can get in touch on the &lt;a href=&quot;http:&#x2F;&#x2F;news.php.net&#x2F;php.pecl.dev&quot;&gt;PECL dev mailing list&lt;&#x2F;a&gt;, or if you’re on IRC, drop in to #php.pecl on EFnet. All contributions are welcome!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Speaking at DPC10</title>
        <published>2010-02-26T00:00:00+00:00</published>
        <updated>2010-02-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/speaking-at-dpc10/"/>
        <id>https://mgdm.net/weblog/speaking-at-dpc10/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/speaking-at-dpc10/">&lt;p&gt;I’m happy to say that I’ll be speaking at the &lt;a href=&quot;http:&#x2F;&#x2F;phpconference.nl&#x2F;&quot;&gt;Dutch PHP Conference&lt;&#x2F;a&gt; in June in Amsterdam, on the subject of the &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;cairo&quot;&gt;PECL&#x2F;Cairo extension&lt;&#x2F;a&gt; I’ve been helping out by working on for the past few months. This will be my first appearance as a speaker at a technical conference so I’m a little nervous, but I’ve no doubt I’ll be practicing a bit before it happens. Apologies in advance to anyone I inflict the talk on before the event.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PECL&#x2F;Cairo 0.2.0 released</title>
        <published>2010-02-03T00:00:00+00:00</published>
        <updated>2010-02-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/peclcairo-020-released/"/>
        <id>https://mgdm.net/weblog/peclcairo-020-released/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/peclcairo-020-released/">&lt;p&gt;The first beta version of the &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;cairo&quot;&gt;PECL&#x2F;Cairo extension&lt;&#x2F;a&gt; has just been released. This version includes support for loading arbitrary fonts via Freetype, cloning matrices, and has a rather large set of bug fixes. If you’ve been using 0.1.0 for anything at all I’d really recommend an upgrade. Windows builds will appear soon over at &lt;a href=&quot;http:&#x2F;&#x2F;perisama.net&#x2F;cairo&#x2F;&quot;&gt;perisama.net&lt;&#x2F;a&gt; for all the major PHP variants courtesy of &lt;a href=&quot;http:&#x2F;&#x2F;www.elizabethmariesmith.com&#x2F;&quot;&gt;Elizabeth M. Smith&lt;&#x2F;a&gt;. Many thanks to Mark Skilbeck for helping get this release working on Windows!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Cairo article published</title>
        <published>2010-01-21T00:00:00+00:00</published>
        <updated>2010-01-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/cairo-article-published/"/>
        <id>https://mgdm.net/weblog/cairo-article-published/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/cairo-article-published/">&lt;p&gt;I’ve got 3 posts or so queued up in my mind to write out, but some of them rather depend on doing other things first, so this will just be a quick note to say I have an article in &lt;a href=&quot;http:&#x2F;&#x2F;www.phparch.com&#x2F;magazine&#x2F;index&#x2F;111&quot;&gt;the most recent php|architect magazine&lt;&#x2F;a&gt; on the subject of “Vector Graphics with Cairo”. This is a basic introduction to the &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;pecl&#x2F;cairo&quot;&gt;PECL&#x2F;Cairo&lt;&#x2F;a&gt; extension which I’ve been helping out on for a while now. Thanks to &lt;a href=&quot;http:&#x2F;&#x2F;caseysoftware.com&#x2F;&quot;&gt;Keith Casey&lt;&#x2F;a&gt; for his input, to the folks at php|architect for letting me do it, and the long-suffering &lt;a href=&quot;http:&#x2F;&#x2F;www.elizabethmariesmith.com&#x2F;&quot;&gt;Elizabeth Marie Smith&lt;&#x2F;a&gt; for putting up with all my stupid questions while working on this and other extensions!&lt;&#x2F;p&gt;
&lt;p&gt;Now, back to my regularly scheduled coding…&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A brief update</title>
        <published>2009-11-09T00:00:00+00:00</published>
        <updated>2009-11-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/a-brief-update/"/>
        <id>https://mgdm.net/weblog/a-brief-update/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/a-brief-update/">&lt;p&gt;Last weekend I spent a couple of days on the yacht &lt;a href=&quot;http:&#x2F;&#x2F;www.flickr.com&#x2F;photos&#x2F;mgdm&#x2F;3087512670&#x2F;&quot;&gt;Hebridean&lt;&#x2F;a&gt; as part of an &lt;a href=&quot;http:&#x2F;&#x2F;www.rya.org.uk&#x2F;coursestraining&#x2F;courses&#x2F;sailcruising&#x2F;Pages&#x2F;Dayskipper.aspx&quot;&gt;RYA sail cruising day skipper course&lt;&#x2F;a&gt;. This was the second half, as we were aboard before last month but had to cancel due to the weather. This time, we combined the course with delivering the yacht to Oban Marina on Kerrera where it will spend the winter. I’m happy to say I passed, so theoretically at least I could be able to charter a yacht for a trip at some stage. I might investigate that for one summer, but I’ll want a bit more mileage and experience first. I also noticed that the local college were running a Coastal Skipper theory course, so I’m on that now too.&lt;&#x2F;p&gt;
&lt;p&gt;I’m considering going to &lt;a href=&quot;http:&#x2F;&#x2F;fosdem.org&quot;&gt;FOSDEM&lt;&#x2F;a&gt; in Belgium in February. I missed &lt;a href=&quot;http:&#x2F;&#x2F;lugradio.org&#x2F;live&#x2F;&quot;&gt;LugRadio Live&lt;&#x2F;a&gt; this year so I’m thinking of it as a sort of substitute. Also considering PHP London, but we’ll see.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Debug of the year</title>
        <published>2009-07-16T00:00:00+00:00</published>
        <updated>2009-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/debug-of-the-year/"/>
        <id>https://mgdm.net/weblog/debug-of-the-year/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/debug-of-the-year/">&lt;p&gt;I saw &lt;a href=&quot;http:&#x2F;&#x2F;news.bbc.co.uk&#x2F;1&#x2F;hi&#x2F;world&#x2F;americas&#x2F;8152278.stm&quot;&gt;this article&lt;&#x2F;a&gt; on the BBC, where a man who bought a packet of cigarettes from a petrol station in the US ended up being charged $23,148,855,308,184,500 instead. Wow. I was a little curious as to how this could have happened, though the number didn’t look familar - I know roughly what 2^32, 2^32 &#x2F; 2, 2^64, 2^64 &#x2F; 2 look like, and this didn’t appear to be any of those. A swift Google though led me to Stack Overflow, which is a fantastic site. Therein lies &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1133581&#x2F;is-23-148-855-308-184-500-a-magic-number-or-sheer-chance&#x2F;1133612#1133612&quot;&gt;a quite plausible explanation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Add the cents to the number and you get 2314885530818450000, which in hexadecimal is 2020 2020 2020 1250.
Do you see the pattern? The first six bytes has been overwritten by spaces (hex 20, dec 32).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Ingenious! I can imagine spending quite a while trying to come up with that…&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PECL&#x2F;Cairo 0.1.0 released</title>
        <published>2009-07-06T00:00:00+00:00</published>
        <updated>2009-07-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/peclcairo-010-released/"/>
        <id>https://mgdm.net/weblog/peclcairo-010-released/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/peclcairo-010-released/">&lt;p&gt;The first alpha of the &lt;a href=&quot;http:&#x2F;&#x2F;pecl.php.net&#x2F;package&#x2F;cairo&quot;&gt;PECL Cairo&lt;&#x2F;a&gt; extension I’ve been helping out with has been released. Please download it, play with it, try and break it, and file bugs if you do! There isn’t an official manual yet (for licencing-related reasons which I’m hoping to sort out soon), but I’ll update this post when there is one. For now, there is a lot of stuff in the &lt;a href=&quot;http:&#x2F;&#x2F;cvs.php.net&#x2F;viewvc.cgi&#x2F;pecl&#x2F;cairo&#x2F;examples&#x2F;&quot;&gt;examples&#x2F;&lt;&#x2F;a&gt; directory in the source which can be used as inspiration.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What I&#x27;ve been up to</title>
        <published>2009-05-15T00:00:00+00:00</published>
        <updated>2009-05-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/what-ive-been-up-to/"/>
        <id>https://mgdm.net/weblog/what-ive-been-up-to/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/what-ive-been-up-to/">&lt;p&gt;I finally decided to get around to doing something about my site, so I’ve made a front page for it which is better than a straight redirect onto the blog. Hopefully it’s reasonable.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been learning a bit more recently about the internals of PHP, and how to write extensions for it. I’ve been practicing by doing a bit of work on a &lt;a href=&quot;http:&#x2F;&#x2F;trac.macvicar.net&#x2F;php-cairo&quot;&gt;Cairo wrapper&lt;&#x2F;a&gt; that was started in the Google Summer of Code last year and until now has been mainly looked after by &lt;a href=&quot;http:&#x2F;&#x2F;elizabethmariesmith.com&#x2F;&quot;&gt;Elizabeth Marie Smith&lt;&#x2F;a&gt;. She’s put up with many, many newbie questions from me and so I’ve learned a lot while doing it. It’s now at the stage where it’ll run the eZ Components Graph component without too much complaining. It has a dual procedural and object-oriented API, so it should manage to run most things that use the existing cairo_wrapper extension. Thanks to all the regulars on #php.pecl and #php.doc on EFNet, and #php-gtk on Freenode for putting up with me while doing this. I’ve also written a quick wrapper for &lt;a href=&quot;http:&#x2F;&#x2F;tokyocabinet.sourceforge.net&#x2F;&quot;&gt;Tokyo Cabinet&lt;&#x2F;a&gt; for the DBA extension in PHP which with a bit of luck will get committed to PHP6 some time soon.&lt;&#x2F;p&gt;
&lt;p&gt;In other news, I’ve been occasionally helping in the maintenance of Jubilee and An Sulaire, the two Sgoth Niseach boats I go sailing on occasionally. Hopefully they’ll be going back in the water soon and we can get some sailing done. I’m looking forward to it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PHP 5.3.0RC2</title>
        <published>2009-05-08T00:00:00+00:00</published>
        <updated>2009-05-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/php-530rc2/"/>
        <id>https://mgdm.net/weblog/php-530rc2/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/php-530rc2/">&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.php.net&#x2F;archive&#x2F;2009.php#id2009-05-07-1&quot;&gt;PHP 5.3.0RC2 has been released&lt;&#x2F;a&gt;, which means that the next version of PHP is just around the corner. It comes right in the middle of the annual &lt;a href=&quot;http:&#x2F;&#x2F;wiki.php.net&#x2F;qa&#x2F;testfest&quot;&gt;PHP Testfest&lt;&#x2F;a&gt;. I rambled on a bit on the &lt;a href=&quot;http:&#x2F;&#x2F;podcast.freenode.net&#x2F;episodes&#x2F;free-as-in-node-season-1-episode-3-soapbox&quot;&gt;Freenode podcast&lt;&#x2F;a&gt; a couple of weeks ago about this - it’s an annual project where PHP usergroups and individuals around the world get together to improve the unit testing of PHP. This has benefits for everyone involved - PHP is improved, and more likely to maintain backward compatibility, and the people involved in writing the tests get to contribute in a meaningful way to the project, and hopefully learn something on the way. Several usergroups have events scheduled, and a couple have already taken place to great success. If you’re a serious PHP user, and interested in getting involved, it’s well worth checking out.&lt;&#x2F;p&gt;
&lt;p&gt;Even just grabbing the latest PHP release, compiling it on your platform, and running “make test” helps the project. It doesn’t take much to do, and you can run it in the background while doing something else. Go for it!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My favourite ever dialogue box</title>
        <published>2008-10-19T00:00:00+00:00</published>
        <updated>2008-10-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/my-favourite-ever-dialogue-box/"/>
        <id>https://mgdm.net/weblog/my-favourite-ever-dialogue-box/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/my-favourite-ever-dialogue-box/">&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&amp;lt;p&amp;gt;I saw this on &amp;lt;a href=&amp;quot;http:&#x2F;&#x2F;www.thedailywtf.com&amp;quot;&amp;gt;TheDailyWTF&amp;lt;&#x2F;a&amp;gt; recently, and decided I had to try it for myself, and it works!&amp;lt;&#x2F;p&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;img alt=&quot;the-best-dialogue-box-ever.png&quot; src=&quot;&#x2F;weblog&#x2F;user&#x2F;files&#x2F;the-best-dialogue-box-ever.png&quot;&gt;
&lt;p&gt;You get it if you go to &quot;Clear History&quot; in the &quot;Go&quot; menu in Nautilus.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Custom functions on the 400D</title>
        <published>2008-09-29T00:00:00+00:00</published>
        <updated>2008-09-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/custom-functions-on-the-400d/"/>
        <id>https://mgdm.net/weblog/custom-functions-on-the-400d/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/custom-functions-on-the-400d/">&lt;p&gt;This is a camera-geek post, so if you’re not one of those, feel free to skip. I’ve just been having a bit more of a play with the custom functions available to change how the 400D operates. There are a couple of things that I’ve found that I can’t believe I didn’t know about - they look like they’ll make things a lot easier. I’m making a note here so that if I lose them, I can find them again.&lt;&#x2F;p&gt;
&lt;p&gt;Now I just need to get out and do some more shooting. Not done very much of late that hasn’t been with my N95, which is disappointing.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Setting name&lt;&#x2F;th&gt;&lt;th&gt;Value&lt;&#x2F;th&gt;&lt;th&gt;Effect&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;CF01 - Set button&#x2F;cross keys function&lt;&#x2F;td&gt;&lt;td&gt;4: Cross keys - AF Frame select&lt;&#x2F;td&gt;&lt;td&gt;Makes the arrow keys choose the autofocus point when shooting, rather than selecting the picture “style”, which is something I’ve never used beyond setting it on “neutral”&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CF04 - Shutter&#x2F;AE lock button&lt;&#x2F;td&gt;&lt;td&gt;1: AE Lock&#x2F;AF&lt;&#x2F;td&gt;&lt;td&gt;This makes the “*” button cause the camera to autofocus, and have pressing the shutter button half way set the exposure (in non-manual modes). This might well drive me nuts, but I like the idea, in theory.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CF05 - AF-assist beam&lt;&#x2F;td&gt;&lt;td&gt;2: Only external flash emits&lt;&#x2F;td&gt;&lt;td&gt;This should stop it flashing like mad when trying to focus in low light, when I’m not using my 430EX. I don’t use the on-camera flash that much anyway, so it won’t make a lot of difference, but it is an irritating feature when I am using it.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CF09 - Shutter curtain sync&lt;&#x2F;td&gt;&lt;td&gt;1: Second curtain sync&lt;&#x2F;td&gt;&lt;td&gt;This makes the flash fire just before the shutter closes, rather than when the shutter opens. This might not seem to make a lot of sense at first glance, but it means that if I take a photo with a relatively long exposure with the intention of getting some motion blur, the shutter will fire at the end of the exposure, so that the object is “frozen” with the trail behind it, rather than seeming to go ahead of it.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CF11 - LCD display when power ON&lt;&#x2F;td&gt;&lt;td&gt;1: Retain power OFF status&lt;&#x2F;td&gt;&lt;td&gt;This stops the display coming on when I switch the camera on. I don’t use the display much so I have it turned off most of the time to save battery power.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Making timelapses with Linux</title>
        <published>2008-07-28T00:00:00+00:00</published>
        <updated>2008-07-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/making-timelapses-with-linux/"/>
        <id>https://mgdm.net/weblog/making-timelapses-with-linux/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/making-timelapses-with-linux/">&lt;p&gt;In other news, I’ve been spending far too much time recently with my camera. One thing I quite like doing is timelapse photography, which my camera (a Canon 400D) can’t do by itself, however I did acquire a cheap intervalometer from eBay, which together with my new tripod (a Velbon Sherpa 250, highly recommended) is quite for this kind of work.&lt;&#x2F;p&gt;
&lt;p&gt;I can’t, however, ever remember the command to create the timelapses. So, here’s a note to myself and anyone else who’s interested. If you have a folder full of .JPG files, with a sequential numbering scheme like most cameras have by default, you can run this command to create a video file using each JPEG image as a frame:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mencoder &amp;quot;mf:&#x2F;&#x2F;*.JPG&amp;quot; -mf fps=25 -vf scale -zoom -xy 1024 -ovc lavc -lavcopts vcodec=mpeg4 -o output.avi
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will output an MPEG4 file in the file output.avi. It will scale the images so that the video ends up being 1024 pixels wide, and set the height to keep the aspect ratio. It will also run at 25 frames per second. These values can be tweaked, depending on the effect you want.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll update this post once I’ve figured out a few more things - I’d like to be able to do panning and zooming as well, and I know it’s possible, though perhaps a bit fiddly.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Lugradio Live 2008</title>
        <published>2008-06-04T00:00:00+00:00</published>
        <updated>2008-06-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/lugradio-live-2008/"/>
        <id>https://mgdm.net/weblog/lugradio-live-2008/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/lugradio-live-2008/">&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;lugradio.org&#x2F;live&#x2F;UK2008&#x2F;&quot;&gt;LugRadio Live 2008&lt;&#x2F;a&gt; is happening on the 19th and 20th of July at The Lighthouse Media Center, Chubb Buildings, Fryer Street, Wolverhampton. This’ll be my first time there, and so I’ve been very sensible and volunteered for the crew. Should be fun!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Linksys NSLU2, part one</title>
        <published>2008-04-23T00:00:00+00:00</published>
        <updated>2008-04-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Michael Maclean
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mgdm.net/weblog/the-linksys-nslu2-part-one/"/>
        <id>https://mgdm.net/weblog/the-linksys-nslu2-part-one/</id>
        
        <content type="html" xml:base="https://mgdm.net/weblog/the-linksys-nslu2-part-one/">&lt;p&gt;I’ve spent some time recently playing with a couple of Linksys NSLU2s. These are small devices which have 2 USB ports and an Ethernet port, and are intended to be used to share USB drives across a network via CIFS (Windows file sharing). The best feature of them though is that like the early WRT54G routers, it runs Linux by default, and uses Samba to share the files. This means that with a bit of hacking, it’s fairly easy to extend it to make it more functional. There are a few projects doing this, the most famous being the Unslung firmware.&lt;&#x2F;p&gt;
&lt;p&gt;Another project that has been working on support for the NSLU2 is Debian. As of version 4.0 (Etch), the default Debian installer has had support for them out of the box. More information on this can be found at &lt;a href=&quot;http:&#x2F;&#x2F;cyrius.com&#x2F;debian&#x2F;nslu2&#x2F;&quot;&gt;http:&#x2F;&#x2F;cyrius.com&#x2F;debian&#x2F;nslu2&#x2F;&lt;&#x2F;a&gt;. I’ve installed Etch on both my NSLU2s, though I found it quicker and easier to use the manual install method, which just means unpacking a tarball of the base system. This is described at &lt;a href=&quot;http:&#x2F;&#x2F;cyrius.com&#x2F;debian&#x2F;nslu2&#x2F;unpack.html&quot;&gt;http:&#x2F;&#x2F;cyrius.com&#x2F;debian&#x2F;nslu2&#x2F;unpack.html&lt;&#x2F;a&gt;. The instructions there are far better than I could describe, so I won’t bother trying to replicate them.&lt;&#x2F;p&gt;
&lt;p&gt;So, what can you do with these things once they’re running Debian? Lots of things. Just now I’m going to describe one of the most basic things I use it for, which is for serving DHCP and DNS on my LAN.&lt;&#x2F;p&gt;
&lt;p&gt;You can, if you like, run the full ISC BIND and dhcpd servers on your Slug, but there isn’t really that much point. They’re big, sometimes tricky to configure, and overkill for a small LAN. A decent, light alternative is dnsmasq. It’s a small daemon that uses the existing &#x2F;etc&#x2F;hosts and other related files to handle serving the network. I run it for a couple of reasons - firstly, my ISP’s DNS servers are somewhat less than reliable, so I use dnsmasq to proxy to OpenDNS. Secondly, it allows me to use internal DNS names for my machines. So, for example, rather than having to remember that my router is 192.168.1.1, if I want to go and change something in its configuration, I can just type “portal” into my browser. Similarly, my NSLU2s can be accessed by just typing “ssh kaylee” or “ssh inara”. I’ve picked a domain name that doesn’t exist in the wider Internet to ensure I don’t collide with anything real.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setting-it-up&quot;&gt;Setting it up&lt;a class=&quot;zola-anchor&quot; style=&quot;display: none;&quot; href=&quot;#setting-it-up&quot; aria-hidden=&quot;true&quot;&gt;&lt;img height=&quot;16&quot; width=&quot;16&quot; src=&quot;&#x2F;icons&#x2F;link.svg&quot; alt=&quot;&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;dnsmasq doesn’t come installed by default, but it’s only an apt-get away.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;apt-get install dnsmasq
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that, there is a configuration file at &#x2F;etc&#x2F;dnsmasq.conf which you may want to have a look at. The defaults are mostly sensible. In my setup, I have changed the following options:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Set the domain name for hosts on this network
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;domain=internal.lan
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Set the start and end of the DHCP pool, and set the
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# default lease time to 24 hours
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dhcp-range=192.168.1.100,192.168.1.150,24h
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Set DHCP option 3 (which supplies the default route) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# to the IP address of your router - otherwise dnsmasq 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# will assume that the gateway is the machine it is running on
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dhcp-option 3,192.168.1.1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Answer DNS queries based on the interface the request was sent
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# to - the effect of this means that you will never get 127.0.0.1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# returned when looking up the name of the dnsmasq server. 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;localise-queries
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also hard-code the MAC addresses of your machines into the dnsmasq.conf file, using the dhcp-host statement, so that each machine will always get the same IP address. This is a neat trick, but personally I don’t think that dnsmasq.conf is the right place to do that when there is already an &lt;code&gt;&#x2F;etc&#x2F;ethers&lt;&#x2F;code&gt; file that stores this information. So, for now, uncomment the “read-ethers” line in dnsmasq.conf. I’ll get back to setting up that file in a moment.&lt;&#x2F;p&gt;
&lt;p&gt;Next, you want to set up your resolv.conf file. This will contain the IP addresses of the nameservers you want to use, and which dnsmasq will proxy for. In my case, I’m using OpenDNS, so I’ve grabbed the DNS servers from &lt;a href=&quot;https:&#x2F;&#x2F;www.opendns.com&#x2F;start&quot;&gt;https:&#x2F;&#x2F;www.opendns.com&#x2F;start&lt;&#x2F;a&gt;. My resolv.conf now looks like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;domain internal.lan
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;nameserver 208.67.222.222
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;nameserver 208.67.220.220
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To set up internal hosts on your LAN, you just need to enter them in &lt;code&gt;&#x2F;etc&#x2F;hosts&lt;&#x2F;code&gt;, and dnsmasq will read them from there. Beyond the normal entries for localhost and some IPv6 ones, I have things that look like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;192.168.1.1     portal.internal.lan        portal
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;192.168.1.5     zoidberg.internal.lan      zoidberg
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;192.168.1.10    inara.internal.lan         inara
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;192.168.1.11    kaylee.internal.lan        kaylee
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can add as many of these as you like, making sure that the domain name part of them matches what is in &#x2F;etc&#x2F;dnsmasq.conf, otherwise they may not work properly.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, back to &lt;code&gt;&#x2F;etc&#x2F;ethers&lt;&#x2F;code&gt;. This is a simple mapping between MAC addresses and either IP addresses or names, as long as the names can be resolved by either DNS or (in this case) the &#x2F;etc&#x2F;hosts file.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;00:12:34:56:78:9A zoidberg.planetexpress.lan
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;00:BC:DE:F0:12:34 animal.planetexpress.lan
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All the hosts in this file will be issued the same IP address every time they do a DHCP request, provided they also exist in &lt;code&gt;&#x2F;etc&#x2F;hosts&lt;&#x2F;code&gt;. Bear in mind that MAC addresses are per interface, not per machine, so if you have a laptop with a wired and a wireless interface I’d advise having two entries, one for each. Last of all, ensure that your router or other device isn’t running a DHCP server any more, and run &lt;code&gt;&#x2F;etc&#x2F;init.d&#x2F;dnsmasq restart&lt;&#x2F;code&gt;. The new settings should take effect, and all being well, everything should work.&lt;&#x2F;p&gt;
&lt;p&gt;(I have updated this based on feedback from &lt;a href=&quot;http:&#x2F;&#x2F;www.dropshock.com&#x2F;blog&#x2F;&quot;&gt;Jason Liquorish&lt;&#x2F;a&gt;, adding a bit about DHCP option 3 and the localise-queries option, which I forgot earlier. Thanks Jason!)&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
